I think a custom decorator could be put on all methods that copy their
doc string from the other module. That would allow the definitions to
be modified immediately after they were first read.
Andy
Toby Donaldson wrote:
>Hi all,
>
>I've fadded doc-strings to the RawPen methods in turtlenew.py.
>However, I have not yet added these doc-strings to the module-level
>functions, mainly to avoid the hassles of maintaining duplicate doc
>strings; I think any duplicate doc-strings should be added as a last
>step. Or better yet: does anyone know how to automatically copy the
>doc-strings from the RawPen methods and add them to their module-level
>equivalents?
>
>I tried as much as possible to copy from the standard Python
>documentation. I also added runnable examples for each of the methods.
>I am not certain if these examples would be appreciated by young
>children, as I am thinking mainly of what the students in my
>first-year university class would benefit from.
>
>I made two other major changes:
>
> - I don't think the speed (and delay) functions should return a
>value when speed is None. That's effectively making them both setters
>and getters, which is not good style. It forces the programmer to
>remember this non-standard convention, and turtle.py already has some
>odd conventions (e.g. the fill(1)/fill(0)). Thus I changed them both
>to be simply setters. If getters are wanted, then lets add those as
>separate functions.
>
> - I added helper functions begin_fill() and end_fill(), which can
>be used in place of fill(1) and fill(0). I can never remember if it is
>fill(1) or fill(0) that should be called first.
>
>Toby
>--
>Dr. Toby Donaldson
>School of Computing Science
>Simon Fraser University (Surrey)
>
>----------------------------------------------------------------------------------------------------
>
># LogoMation-like turtle graphics
>
>"""
>Turtle graphics is a popular way for introducing programming to
>kids. It was part of the original Logo programming language developed
>by Wally Feurzig and Seymour Papert in 1966.
>
>Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it
>the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
>the direction it is facing, drawing a line as it moves. Give it the
>command turtle.left(25), and it rotates in-place 25 degrees clockwise.
>
>By combining together these and similar commands, intricate shapes and
>pictures can easily be drawn.
>"""
>
>from math import * # Also for export
>import Tkinter
>
>speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']
>
>class Error(Exception):
> pass
>
>class RawPen:
>
> def __init__(self, canvas):
> self._canvas = canvas
> self._items = []
> self._tracing = 1
> self._arrow = 0
> self._delay = 10 # default delay for drawing
> self.degrees()
> self.reset()
>
> def degrees(self, fullcircle=360.0):
> """ Set angle measurement units to degrees.
>
> Example:
> >>> turtle.degrees()
> """
> self._fullcircle = fullcircle
> self._invradian = pi / (fullcircle * 0.5)
>
> def radians(self):
> """ Set the angle measurement units to radians.
>
> Example:
> >>> turtle.radians()
> """
> self.degrees(2.0*pi)
>
> def reset(self):
> """Clear the screen, re-center the pen, and set variables to
> the default values.
>
> Example:
> >>> turtle.position()
> [0.0, -22.0]
> >>> turtle.heading()
> 100.0
> >>> turtle.reset()
> >>> turtle.position()
> [0.0, 0.0]
> >>> turtle.heading()
> 0.0
> """
> canvas = self._canvas
> self._canvas.update()
> width = canvas.winfo_width()
> height = canvas.winfo_height()
> if width <= 1:
> width = canvas['width']
> if height <= 1:
> height = canvas['height']
> self._origin = float(width)/2.0, float(height)/2.0
> self._position = self._origin
> self._angle = 0.0
> self._drawing = 1
> self._width = 1
> self._color = "black"
> self._filling = 0
> self._path = []
> self._tofill = []
> self.clear()
> canvas._root().tkraise()
>
> def clear(self):
> """ Clear the screen. The turtle does not move.
>
> Example:
> >>> turtle.position()
> [10.0, -20.0]
> >>> turtle.heading()
> 270.0
> >>> turtle.clear()
> >>> turtle.position()
> [10.0, -20.0]
> >>> turtle.heading()
> 270.0
> """
> self.fill(0)
> canvas = self._canvas
> items = self._items
> self._items = []
> for item in items:
> canvas.delete(item)
> self._delete_turtle()
> self._draw_turtle()
>
> def tracer(self, flag):
> """Set tracing on if flag is True, and off if it is False.
> Tracing means line are drawn more slowly, with an
> animation of an arrow along the line.
>
> Example:
> >>> turtle.tracer(False) # turns off Tracer
> """
> self._tracing = flag
> if not self._tracing:
> self._delete_turtle()
> self._draw_turtle()
>
> def forward(self, distance):
> """ Go forward distance steps.
>
> Example:
> >>> turtle.position()
> [0.0, 0.0]
> >>> turtle.heading()
> 0.0
> >>> turtle.forward(25)
> >>> turtle.position()
> [25.0, 0.0]
> >>> turtle.heading()
> 0.0
> >>> turtle.forward(-75)
> >>> turtle.position()
> [-50.0, 0.0]
> >>> turtle.heading()
> 0.0
> """
> x0, y0 = start = self._position
> x1 = x0 + distance * cos(self._angle*self._invradian)
> y1 = y0 - distance * sin(self._angle*self._invradian)
> self._goto(x1, y1)
>
> def backward(self, distance):
> """ Go backwards distance steps.
>
> The turtle's heading does not change.
>
> Example:
> >>> turtle.position()
> [0.0, 0.0]
> >>> turtle.heading()
> 0.0
> >>> turtle.backward(30)
> >>> turtle.position()
> [-30.0, 0.0]
> >>> turtle.heading()
> 0.0
> """
> self.forward(-distance)
>
> def left(self, angle):
> """ Turn left angle units.
>
> Units are by default degrees, but can be set via the degrees()
> and radians() functions.
>
> When viewed from above, the turning happens in-place around
> its center point.
>
> Example:
> >>> turtle.position()
> [-10.0, 135.0]
> >>> turtle.heading()
> 22
> >>> turtle.left(45)
> >>> turtle.position()
> [-10.0, 135.0]
> >>> turtle.heading()
> 67.0
> """
> self._angle = (self._angle + angle) % self._fullcircle
> self._draw_turtle()
>
> def right(self, angle):
> """ Turn right angle units.
>
> Units are by default degrees, but can be set via the degrees()
> and radians() functions.
>
> When viewed from above, the turning happens in-place around
> its center point.
>
> Example:
> >>> turtle.position()
> [-10.0, 135.0]
> >>> turtle.heading()
> 22
> >>> turtle.right(45)
> >>> turtle.position()
> [-10.0, 135.0]
> >>> turtle.heading()
> 337.0
> """
> self.left(-angle)
>
> def up(self):
> """Pull the pen up -- no drawing when moving.
>
> Example:
> >>> turtle.up()
> """
> self._drawing = 0
>
> def down(self):
> """Put the pen down -- draw when moving.
>
> Example:
> >>> turtle.down()
> """
> self._drawing = 1
>
> def width(self, width):
> """ Set the line to thickness to width.
>
> Example:
> >>> turtle.width(10)
> """
> self._width = float(width)
>
> def color(self, *args):
> """ Set the pen color.
>
> Three input formats are allowed:
>
> color(s)
> s is a Tk specification string, such as "red" or "yellow"
>
> color((r, g, b))
> r, g, and b represent an RGB color, and each of r, g, and b
> are in the range [0..1]
>
> color(r, g, b)
> r, g, and b represent an RGB color, and each of r, g, and b
> are in the range [0..1]
>
> Example:
>
> >>> turtle.color('brown')
> >>> tup = (0.2, 0.8, 0.55)
> >>> turtle.color(tup)
> >>> turtle.color(0, .5, 0)
> """
> if not args:
> raise Error, "no color arguments"
> if len(args) == 1:
> color = args[0]
> if type(color) == type(""):
> # Test the color first
> try:
> id = self._canvas.create_line(0, 0, 0, 0, fill=color)
> except Tkinter.TclError:
> raise Error, "bad color string: %r" % (color,)
> self._set_color(color)
> return
> try:
> r, g, b = color
> except:
> raise Error, "bad color sequence: %r" % (color,)
> else:
> try:
> r, g, b = args
> except:
> raise Error, "bad color arguments: %r" % (args,)
> assert 0 <= r <= 1
> assert 0 <= g <= 1
> assert 0 <= b <= 1
> x = 255.0
> y = 0.5
> self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
>
> def _set_color(self,color):
> self._color = color
> self._draw_turtle()
>
> def write(self, text, move=0):
> """ Write text at the current pen position.
>
> If move is true, the pen is moved to the bottom-right corner
> of the text. By default, move is False.
>
> Example:
> >>> turtle.write('The race is on!')
> >>> turtle.write('Home = (0, 0)', True)
> """
> x, y = self._position
> x = x-1 # correction -- calibrated for Windows
> item = self._canvas.create_text(x, y,
> text=str(text), anchor="sw",
> fill=self._color)
> self._items.append(item)
> if move:
> x0, y0, x1, y1 = self._canvas.bbox(item)
> self._goto(x1, y1)
> self._draw_turtle()
>
> def fill(self, flag):
> """ Call fill(1) before drawing the shape you want to fill, and
> fill(0) when done.
>
> Example:
> >>> turtle.fill(1)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.fill(0)
> """
> if self._filling:
> path = tuple(self._path)
> smooth = self._filling < 0
> if len(path) > 2:
> item = self._canvas._create('polygon', path,
> {'fill': self._color,
> 'smooth': smooth})
> self._items.append(item)
> if self._tofill:
> for item in self._tofill:
> self._canvas.itemconfigure(item, fill=self._color)
> self._items.append(item)
> self._path = []
> self._tofill = []
> self._filling = flag
> if flag:
> self._path.append(self._position)
> self.forward(0)
>
> def begin_fill(self):
> """ Called just before drawing a shape to be filled.
>
> Example:
> >>> turtle.begin_fill()
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.end_fill()
> """
> self.fill(1)
>
> def end_fill(self):
> """ Called after drawing a shape to be filled.
>
> Example:
> >>> turtle.begin_fill()
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.left(90)
> >>> turtle.forward(100)
> >>> turtle.end_fill()
> """
> self.fill(0)
>
> def circle(self, radius, extent=None):
> """ Draw a circle with given radius.
> The center is radius units left of the turtle; extent
> determines which part of the circle is drawn. If not given,
> the entire circle is drawn.
>
> If extent is not a full circle, one endpoint of the arc is the
> current pen position. The arc is drawn in a counter clockwise
> direction if radius is positive, otherwise in a clockwise
> direction. In the process, the direction of the turtle is
> changed by the amount of the extent.
>
> >>> turtle.circle(50)
> >>> turtle.circle(120, 180) # half a circle
> """
> if extent is None:
> extent = self._fullcircle
> x0, y0 = self._position
> xc = x0 - radius * sin(self._angle * self._invradian)
> yc = y0 - radius * cos(self._angle * self._invradian)
> if radius >= 0.0:
> start = self._angle - 90.0
> else:
> start = self._angle + 90.0
> extent = -extent
> if self._filling:
> if abs(extent) >= self._fullcircle:
> item = self._canvas.create_oval(xc-radius, yc-radius,
> xc+radius, yc+radius,
> width=self._width,
> outline="")
> self._tofill.append(item)
> item = self._canvas.create_arc(xc-radius, yc-radius,
> xc+radius, yc+radius,
> style="chord",
> start=start,
> extent=extent,
> width=self._width,
> outline="")
> self._tofill.append(item)
> if self._drawing:
> if abs(extent) >= self._fullcircle:
> item = self._canvas.create_oval(xc-radius, yc-radius,
> xc+radius, yc+radius,
> width=self._width,
> outline=self._color)
> self._items.append(item)
> item = self._canvas.create_arc(xc-radius, yc-radius,
> xc+radius, yc+radius,
> style="arc",
> start=start,
> extent=extent,
> width=self._width,
> outline=self._color)
> self._items.append(item)
> angle = start + extent
> x1 = xc + abs(radius) * cos(angle * self._invradian)
> y1 = yc - abs(radius) * sin(angle * self._invradian)
> self._angle = (self._angle + extent) % self._fullcircle
> self._position = x1, y1
> if self._filling:
> self._path.append(self._position)
> self._draw_turtle()
>
> def heading(self):
> """ Returns the turtle's current heading.
>
> Example:
> >>> turtle.heading()
> 67.0
> """
> return self._angle
>
> def setheading(self, angle):
> """ Set the turtle facing the given angle.
>
> Here are some common directions in degrees:
>
> 0 - east
> 90 - north
> 180 - west
> 270 - south
>
> Example:
> >>> turtle.setheading(90)
> >>> turtle.heading()
> 90
> >>> turtle.setheading(128)
> >>> turtle.heading()
> 128
> """
> self._angle = angle
> self._draw_turtle()
>
> def window_width(self):
> """ Returns the width of the turtle window.
>
> Example:
> >>> turtle.window_width()
> 640
> """
> width = self._canvas.winfo_width()
> if width <= 1: # the window isn't managed by a geometry manager
> width = self._canvas['width']
> return width
>
> def window_height(self):
> """ Returns the height of the turtle window.
>
> Example:
> >>> turtle.window_height()
> 768
> """
> height = self._canvas.winfo_height()
> if height <= 1: # the window isn't managed by a geometry manager
> height = self._canvas['height']
> return height
>
> def position(self):
> """ Returns the current (x, y) location of the turtle.
>
> Example:
> >>> turtle.position()
> [0.0, 240.0]
> >>> x, y = turtle.position()
> >>> x
> 0.0
> >>> y
> 240.0
> """
> x0, y0 = self._origin
> x1, y1 = self._position
> return [x1-x0, -y1+y0]
>
> def setx(self, xpos):
> """ Sets the turtle's x coordinate to be xpos.
>
> Example:
> >>> turtle.position()
> [10.0, 240.0]
> >>> turtle.setx(10)
> >>> turtle.position()
> [10.0, 240.0]
> """
> x0, y0 = self._origin
> x1, y1 = self._position
> self._goto(x0+xpos, y1)
>
> def sety(self, ypos):
> """ Sets the turtle's y coordinate to be ypos.
>
> Example:
> >>> turtle.position()
> [0.0, 0.0]
> >>> turtle.sety(-22)
> >>> turtle.position()
> [0.0, -22.0]
> """
> x0, y0 = self._origin
> x1, y1 = self._position
> self._goto(x1, y0-ypos)
>
> def towards(self, *args):
> """Returns the angle, which corresponds to the line
> from turtle-position to point (x,y).
>
> Argument can be two coordinates or one pair of coordinates
> or a RawPen/Pen instance.
>
> Example:
> >>> turtle.position()
> [10.0, 10.0]
> >>> turtle.towards(0,0)
> 225.0
> """
> if len(args) == 2:
> x, y = args
> else:
> arg = args[0]
> if isinstance(arg, RawPen):
> x, y = arg.position()
> else:
> x, y = arg
> x0, y0 = self.position()
> dx = x - x0
> dy = y - y0
> return (atan2(dy,dx) / self._invradian) % self._fullcircle
>
> def goto(self, *args):
> """ Goto the given point.
>
> If the pen is down, then a line will be drawn. The turtle's
> orientation does not change.
>
> Two input formats are accepted:
>
> goto(x, y)
> go to point (x, y)
>
> goto((x, y))
> go to point (x, y)
>
> Example:
> >>> turtle.position()
> [0.0, 0.0]
> >>> turtle.heading()
> 0.0
> >>> turtle.goto(50, -45)
> >>> turtle.position()
> [50.0, -45.0]
> >>> turtle.heading()
> 0.0
> """
> if len(args) == 1:
> try:
> x, y = args[0]
> except:
> raise Error, "bad point argument: %r" % (args[0],)
> else:
> try:
> x, y = args
> except:
> raise Error, "bad coordinates: %r" % (args[0],)
> x0, y0 = self._origin
> self._goto(x0+x, y0-y)
>
> def _goto(self, x1, y1):
> x0, y0 = self._position
> self._position = map(float, (x1, y1))
> if self._filling:
> self._path.append(self._position)
> if self._drawing:
> if self._tracing:
> dx = float(x1 - x0)
> dy = float(y1 - y0)
> distance = hypot(dx, dy)
> nhops = int(distance)
> item = self._canvas.create_line(x0, y0, x0, y0,
> width=self._width,
> capstyle="round",
> fill=self._color)
> try:
> for i in range(1, 1+nhops):
> x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
> self._canvas.coords(item, x0, y0, x, y)
> self._draw_turtle((x,y))
> self._canvas.update()
> self._canvas.after(self._delay)
> # in case nhops==0
> self._canvas.coords(item, x0, y0, x1, y1)
> self._canvas.itemconfigure(item, arrow="none")
> except Tkinter.TclError:
> # Probably the window was closed!
> return
> else:
> item = self._canvas.create_line(x0, y0, x1, y1,
> width=self._width,
> capstyle="round",
> fill=self._color)
> self._items.append(item)
> self._draw_turtle()
>
> def speed(self, speed):
> """ Set the turtle's speed.
>
> speed must one of these five strings:
>
> 'fastest' is a 0 ms delay
> 'fast' is a 5 ms delay
> 'normal' is a 10 ms delay
> 'slow' is a 15 ms delay
> 'slowest' is a 20 ms delay
>
> Example:
> >>> turtle.speed('slow')
> """
> try:
> speed = speed.strip().lower()
> self._delay = speeds.index(speed) * 5
> except:
> raise ValueError, "%r is not a valid speed. speed must be
>one of %s" % (speed, speeds)
>
>
> def delay(self, delay):
> """ Sets the drawing delay in milliseconds.
>
> Example:
> >>> turtle.delay(15)
> """
> if int(delay) < 0:
> raise ValueError, "delay must be greater than or equal to 0"
> self._delay = int(delay)
>
>
> def _draw_turtle(self, position=[]):
> if not self._tracing:
> return
> if position == []:
> position = self._position
> x,y = position
> distance = 8
> dx = distance * cos(self._angle*self._invradian)
> dy = distance * sin(self._angle*self._invradian)
> self._delete_turtle()
> self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
> width=self._width,
> arrow="last",
> capstyle="round",
> fill=self._color)
> self._canvas.update()
>
> def _delete_turtle(self):
> if self._arrow != 0:
> self._canvas.delete(self._arrow)
> self._arrow = 0
>
>
>_root = None
>_canvas = None
>_pen = None
>_width = 0.50 # 50% of window for width
>_height = 0.75 # 75% of window for height
>_startx = None
>_starty = None
>_title = "Turtle Graphics" # default title
>
>class Pen(RawPen):
>
> def __init__(self):
> global _root, _canvas, _width, _height
> if _root is None:
> _root = Tkinter.Tk()
> _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
> _root.title(_title)
>
> if _canvas is None:
> # XXX Should have scroll bars
> _canvas = Tkinter.Canvas(_root, background="white")
> _canvas.pack(expand=1, fill="both")
>
> setup(width=_width, height= _height, startx=_startx, starty=_starty)
>
> RawPen.__init__(self, _canvas)
>
> def _destroy(self):
> global _root, _canvas, _pen
> root = self._canvas._root()
> if root is _root:
> _pen = None
> _root = None
> _canvas = None
> root.destroy()
>
>def _getpen():
> global _pen
> if not _pen:
> _pen = Pen()
> return _pen
>
>class Turtle(Pen):
> pass
>
>def degrees(): _getpen().degrees()
>def radians(): _getpen().radians()
>def reset(): _getpen().reset()
>def clear(): _getpen().clear()
>def tracer(flag): _getpen().tracer(flag)
>def forward(distance): _getpen().forward(distance)
>def backward(distance): _getpen().backward(distance)
>def left(angle): _getpen().left(angle)
>def right(angle): _getpen().right(angle)
>def up(): _getpen().up()
>def down(): _getpen().down()
>def width(width): _getpen().width(width)
>def color(*args): _getpen().color(*args)
>def write(arg, move=0): _getpen().write(arg, move)
>def fill(flag): _getpen().fill(flag)
>def begin_fill(): _getpen().begin_fill()
>def end_fill(): _getpen.end_fill()
>def circle(radius, extent=None): _getpen().circle(radius, extent)
>def goto(*args): _getpen().goto(*args)
>def heading(): return _getpen().heading()
>def setheading(angle): _getpen().setheading(angle)
>def position(): return _getpen().position()
>def window_width(): return _getpen().window_width()
>def window_height(): return _getpen().window_height()
>def setx(xpos): _getpen().setx(xpos)
>def sety(ypos): _getpen().sety(ypos)
>def towards(*args): return _getpen().towards(*args)
>def done(): _root.mainloop()
>def delay(delay=-1): return _getpen().delay(delay)
>def speed(speed=''): return _getpen().speed(speed)
>def setup(**geometry):
> global _root, _canvas, _width, _height, _startx, _starty
>
> _width = geometry.get('width',_width)
> _height = geometry.get('height',_height)
> _startx = geometry.get('startx', _startx)
> _starty = geometry.get('starty', _starty)
>
> if _root:
> if 0 < _width <= 1:
> _width = _root.winfo_screenwidth() * _width
> if 0 < _height <= 1:
> _height = _root.winfo_screenheight() * _height
> # center window on screen
> if _startx is None:
> _startx = (_root.winfo_screenwidth() - _width) / 2
> if _starty is None:
> _starty = (_root.winfo_screenheight() - _height) / 2
>
> _root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
>
>
>def title(title):
> global _title
> _title = title
>
>def demo():
> reset()
> tracer(1)
> up()
> backward(100)
> down()
> # draw 3 squares; the last filled
> width(3)
> for i in range(3):
> if i == 2:
> fill(1)
> for j in range(4):
> forward(20)
> left(90)
> if i == 2:
> color("maroon")
> fill(0)
> up()
> forward(30)
> down()
> width(1)
> color("black")
> # move out of the way
> tracer(0)
> up()
> right(90)
> forward(100)
> right(90)
> forward(100)
> right(180)
> down()
> # some text
> write("startstart", 1)
> write("start", 1)
> color("red")
> # staircase
> for i in range(5):
> forward(20)
> left(90)
> forward(20)
> right(90)
> # filled staircase
> fill(1)
> for i in range(5):
> forward(20)
> left(90)
> forward(20)
> right(90)
> fill(0)
> # more text
> write("end")
> if __name__ == '__main__':
> _root.mainloop()
>
>if __name__ == '__main__':
> demo()
>
>
>
>
--
Andrew N. Harrington
Computer Science Department Undergraduate Program Director
Loyola University Chicago http://www.cs.luc.edu/~anh
512B Lewis Towers (office) Office Phone: 312-915-7982
Snail mail to Lewis Towers 416 Dept. Fax: 312-915-7998
820 North Michigan Avenue [EMAIL PROTECTED]
Chicago, Illinois 60611
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"edupython" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/edupython
-~----------~----~----~----~------~----~------~--~---