Basic analysis of Python turtle library implementation

For the related usage of turtle, please refer to ["Python graphics drawing library turtle Chinese development documentation and examples"] (https://blog.csdn.net/A757291228/article/details/105884899)

This article is an analysis of the realization of the turtle library, but does not involve the python TK library.

Start##

Entrance Exploration##

In turtle, the forward or fd function is used to go straight; after the turtle library is installed on this machine, the turtle.py file is found in the following directory:

Let's start by exploring the basic implementation of the turtle library from the entrance in a conventional way; create a new turtle object:

tt=Turtle()

Find class Turtle in the file:

classTurtle(RawTurtle):"""RawTurtle auto-creating(scrolled) canvas.

 When a Turtle object is created or a function derived from some
 Turtle method is called a TurtleScreen object is automatically created."""
 _ pen = None
 _ screen = None

 def __init__(self,
     shape=_CFG["shape"],
     undobuffersize=_CFG["undobuffersize"],
     visible=_CFG["visible"]):if Turtle._screen is None:
   Turtle._screen =Screen()
  RawTurtle.__init__(self, Turtle._screen,
       shape=shape,
       undobuffersize=undobuffersize,
       visible=visible)

It can be seen from the comments that this class will automatically create the TurtleScreen object and canvas, this is in the code process in the __init__ method; after that, the __init__ of RawTurtle is called to create the animation part of the turtle, and it is realized as follows:

	screens =[]

 def __init__(self, canvas=None,
     shape=_CFG["shape"],
     undobuffersize=_CFG["undobuffersize"],
     visible=_CFG["visible"]):ifisinstance(canvas, _Screen):
   self.screen = canvas
  elif isinstance(canvas, TurtleScreen):if canvas not in RawTurtle.screens:
    RawTurtle.screens.append(canvas)
   self.screen = canvas
  elif isinstance(canvas,(ScrolledCanvas, Canvas)):for screen in RawTurtle.screens:if screen.cv == canvas:
     self.screen = screen
     breakelse:
    self.screen =TurtleScreen(canvas)
    RawTurtle.screens.append(self.screen)else:
   raise TurtleGraphicsError("bad canvas argument %s"% canvas)

  screen = self.screen
  TNavigator.__init__(self, screen.mode())
  TPen.__init__(self)
  screen._turtles.append(self)
  self.drawingLineItem = screen._createline()
  self.turtle =_TurtleImage(screen, shape)
  self._poly = None
  self._creatingPoly = False
  self._fillitem = self._fillpath = None
  self._shown = visible
  self._hidden_from_screen = False
  self.currentLineItem = screen._createline()
  self.currentLine =[self._position]
  self.items =[self.currentLineItem]
  self.stampItems =[]
  self._undobuffersize = undobuffersize
  self.undobuffer =Tbuffer(undobuffersize)
  self._update()

After creating a turtle object, call the forward function to draw a line segment.

We open the turtle file and query the definition of the forward function according to the general form of the function definition:

I understand from the comments that forward | fd can be used to call the function, and the parameter is to pass in a distance; please refer to the article marked at the head of the article for specific usage, and I will not explain too much here.

At the bottom of the forward function, it is found that the _go method is called: self._go(distance). View the _go method:

def _go(self, distance):"""move turtle forward by specified distance"""
  ende = self._position + self._orient * distance
  self._goto(ende)

In the _go method, the distance is passed in, and the ende is assigned to self._position + self._orient * distance. First, understand what the _position, _orient, and distance members are.

_ The go method is located in the TNavigator class. In the init method of TNavigator, the reset method is used. The reset method has the initialization of _position and _orient:

def reset(self):"""reset turtle to its initial values

  Will be overwritten by parent class"""
  self._position =Vec2D(0.0,0.0)
  self._orient =  TNavigator.START_ORIENTATION[self._mode]

Let's look at Vec2D again:

classVec2D(tuple):"""A 2 dimensional vector class, used as a helper classfor implementing turtle graphics.
 May be useful for turtle graphics programs also.
 Derived from tuple, so a vector is a tuple!Provides(for a, b vectors, k number):
  a+b vector addition
  a-b vector subtraction
  a*b inner product
  k*a and a*k multiplication with scalar
  | a| absolute value of a
  a.rotate(angle) rotation
    """
 def __new__(cls, x, y):return tuple.__new__(cls,(x, y))
 def __add__(self, other):returnVec2D(self[0]+other[0], self[1]+other[1])
 def __mul__(self, other):ifisinstance(other, Vec2D):return self[0]*other[0]+self[1]*other[1]returnVec2D(self[0]*other, self[1]*other)
 def __rmul__(self, other):ifisinstance(other, int) or isinstance(other, float):returnVec2D(self[0]*other, self[1]*other)
 def __sub__(self, other):returnVec2D(self[0]-other[0], self[1]-other[1])
 def __neg__(self):returnVec2D(-self[0],-self[1])
 def __abs__(self):return(self[0]**2+ self[1]**2)**0.5
 def rotate(self, angle):"""rotate self counterclockwise by angle
        """
  perp =Vec2D(-self[1], self[0])
  angle = angle * math.pi /180.0
  c, s = math.cos(angle), math.sin(angle)returnVec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
 def __getnewargs__(self):return(self[0], self[1])
 def __repr__(self):return"(%.2f,%.2f)"% self

After looking at Vec2D, we know that it is actually a tuple; looking at the TNavigator class:

classTNavigator(object):"""Navigation part of the RawTurtle.
 Implements methodsfor turtle movement."""
 START_ORIENTATION ={"standard":Vec2D(1.0,0.0),"world":Vec2D(1.0,0.0),"logo":Vec2D(0.0,1.0)}
 DEFAULT_MODE ="standard"
 DEFAULT_ANGLEOFFSET =0
 DEFAULT_ANGLEORIENT =1

Then check TNavigator.START_ORIENTATION[self._mode], and learn that _mode is standard in the TNavigator class. At this time, TNavigator.START_ORIENTATION[self._mode] is Vec2D(1.0, 0.0).

Next look at the _goto method:

def _goto(self, end):"""Move the pen to the point end, thereby drawing a line
  if pen is down. All other methods for turtle movement depend
  on this one."""
  ## Version with undo-stuff
  go_modes =( self._drawing,
      self._pencolor,
      self._pensize,isinstance(self._fillpath, list))
  screen = self.screen
  undo_entry =("go", self._position, end, go_modes,(self.currentLineItem,
      self.currentLine[:],
      screen._pointlist(self.currentLineItem),
      self.items[:]))if self.undobuffer:
   self.undobuffer.push(undo_entry)
  start = self._position
  if self._speed and screen._tracing ==1:
   diff =(end-start)
   diffsq =(diff[0]*screen.xscale)**2+(diff[1]*screen.yscale)**2
   nhops =1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
   delta = diff *(1.0/nhops)for n inrange(1, nhops):if n ==1:
     top = True
    else:
     top = False
    self._position = start + delta * n
    if self._drawing:
     screen._drawline(self.drawingLineItem,(start, self._position),
          self._pencolor, self._pensize, top)
    self._update()if self._drawing:
    screen._drawline(self.drawingLineItem,((0,0),(0,0)),
            fill="", width=self._pensize)
  # Turtle now at end,if self._drawing: # now update currentLine
   self.currentLine.append(end)ifisinstance(self._fillpath, list):
   self._fillpath.append(end)
  ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
  self._position = end
  if self._creatingPoly:
   self._poly.append(end)iflen(self.currentLine)>42: # 42! answer to the ultimate question
          # of life, the universe and everything
   self._newLine()
  self._update() #count=True)

In the goto_ method, the first comment explains the function of the method "Move from the current position to the incoming end parameter coordinate point, in the process of moving, draw the line segment, and all turtle drawing methods are based on this goto_method". In the goto_ method, a tuple go_modes is defined at the beginning:

go_modes =( self._drawing,
      self._pencolor,
      self._pensize,isinstance(self._fillpath, list))

In the go_modes tuple, _drawing, _pencolor, and _pensize are passed in, and the isinstance method is called to determine whether _fillpath is a list; and then an undo_entry tuple is constructed. After judging if self.undobuffer:, if it is empty or Null, then self.undobuffer.push(undo_entry). Then, the drawing method in the default state:

if self._speed and screen._tracing ==1:
   diff =(end-start)
   diffsq =(diff[0]*screen.xscale)**2+(diff[1]*screen.yscale)**2
   nhops =1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
   delta = diff *(1.0/nhops)for n inrange(1, nhops):if n ==1:
     top = True
    else:
     top = False
    self._position = start + delta * n
    if self._drawing:
     screen._drawline(self.drawingLineItem,(start, self._position),
          self._pencolor, self._pensize, top)
    self._update()if self._drawing:
    screen._drawline(self.drawingLineItem,((0,0),(0,0)),
            fill="", width=self._pensize)

Among them, start is the coordinate point of the current position, and end is the coordinate point of the target position. The most important of the above main methods is: _drawline, using _drawline to pass in the configuration parameters, coordinate sequence, pen color, and drawing line Width and whether to specify polyitem; (I haven't figured out the algorithm of the specific coordinate sequence. I hope some students who know can tell me what the calculation is and what the formula is, thank you!).

View the implementation of _drawline:

def _drawline(self, lineitem, coordlist=None,
    fill=None, width=None, top=False):"""Configure lineitem according to provided arguments:
 coordlist is sequence of coordinates
 fill is drawing color
 width is width of drawn line.
 top is a boolean value, which specifies if polyitem
 will be put on top of the canvas' displaylist so it
 will not be covered by other items."""
 if coordlist is not None:
  cl =[]for x, y in coordlist:
   cl.append(x * self.xscale)
   cl.append(-y * self.yscale)
  self.cv.coords(lineitem,*cl)if fill is not None:
  self.cv.itemconfigure(lineitem, fill=fill)if width is not None:
  self.cv.itemconfigure(lineitem, width=width)if top:
  self.cv.tag_raise(lineitem)

**The above articles have not been fully analyzed and implemented, and will be updated later. **

Recommended Posts

Basic analysis of Python turtle library implementation
Analysis of glob in python standard library
Basic syntax of Python
Basic knowledge of Python (1)
Analysis of common methods of Python operation Jira library
Python implementation of AI automatic matting example analysis
Python analysis of wav files
Analysis of JS of Python crawler
Python implementation of gomoku program
Analysis of Python Sandbox Escape
Analysis of Python object-oriented programming
Analysis of usage examples of Python yield
Detailed implementation of Python plug-in mechanism
Implementation of reverse traversal of python list
Python implementation of IOU calculation case
Python preliminary implementation of word2vec operation
FM algorithm analysis and Python implementation
Python file operation basic process analysis
Implementation of python selenium operation cookie
Analysis of Python conditional control statements
Implementation of python3 registration global hotkey
Implementation of python student management system
​Full analysis of Python module knowledge
Implementation of python gradient descent algorithm
Implementation of JWT user authentication in python
Python implementation of intersection and IOU tutorial
Detailed analysis of Python garbage collection mechanism
Implementation principle of dynamic binding of Python classes
The essence of Python language: Itertools library
Analysis of common methods of Python multi-process programming
The specific method of python import library
Method analysis of Python calling C language program
Python basic syntax (1)
Python3 basic syntax
7 features of Python3.9
Detailed explanation of python standard library OS module
Python basic summary
Python data analysis
Implementation of Python headless crawler to download files
Python implementation of hand drawing effect example sharing
Implementation of business card management system with python
Python basic operators
Python writes the game implementation of fishing master
Implementation of business card management system based on python
Detailed explanation of the implementation steps of Python interface development
Python basic syntax generator
Python basic drawing tutorial (1)
Python function basic learning
Python linear interpolation analysis
Basics of Python syntax
python_ crawler basic learning
Python basic data types
Prettytable module of python
Python basic data types
09. Common modules of Python3
Python basic syntax iteration