为什么我必须将 'resizemode' 设置为 'user' 两次才能使我对 'stretchfactor' 的更改在使用 'turtle' 时生效?
Why do I have to set 'resizemode' to 'user' twice in order for my change to 'stretchfactor' to take effect when using 'turtle'?
我正在使用 Python 3.6.0 自动化在 Cracker Barrel 找到的 "triangle peg game",我目前正在使用 'turtle' 实现其图形。我创建的两个 类 与此问题相关:'Game'(包含在主包中的模块中)和 'TurtleGraphics'(包含在子包中的模块中 'graphics'),其预期目的是不言自明的。当使用 'TurtleGraphics' 对象作为参数调用 'Game' 对象时,这两个对象相互链接,并调用 'graphics._construct()',它定义了一个 'Pen' 对象和使用 'pen()' 设置其 'stretchfactor'。这就是问题出现的地方。即使我在 'turtle.cfg' 文件中将 'resizemode' 设置为 'user',我必须再次将 'resizemode' 设置为 'user' 作为 [=57= 的参数] 以便在从游戏调用时正确构造图形。 St运行gely 够了,如果我 运行 直接包含 'TurtleGraphics' 的模块并创建一个图形对象,它工作正常。此外,即使当我从游戏对象调用图形时,使用 'shapesize()' 而不是 'pen()' 设置 'stretchfactor' 也有效。首先,我将 post 'Game.__call__' 和 'TurtleGraphics._construct' 的代码,在每个模块的导入前加上,这可能是相关的。我也会 post 'TurtleGraphics.__init__' 和 'TurtleGraphics._draw_board'。 (类 都有基础 类,但是 'BaseGame' 不处理图形,而 'Graphics' 是抽象的,所以在这种情况下它们是无关紧要的。此外,值得一提的是'Game' 没有 '__init__' 方法。所有实例属性都在调用时分配。)然后我将解释到目前为止我对此事所做的研究。
Game.__call__:
from tripeg.graphics import Graphics
from tripeg.graphics.ascii_ import ASCIIGraphics
from tripeg.graphics.turtle_ import TurtleGraphics
#...
def __call__(self, graphics=None):
"""Starts the game with given graphics, or none, if not given."""
super().__call__()
if graphics:
if not isinstance(graphics, Graphics):
raise TypeError(f"Argument '{graphics}' is not of type"
" 'Graphics'.")
else:
self._graphics = graphics
self._graphics._game = self
self._graphics._construct()
TurtleGraphics._construct:
import os
import turtle
from turtle import Screen, RawPen, Pen, Shape, Terminator, _CFG
from tripeg.graphics import Graphics
#...
def __init__(self):
"""Initialize self. See help(type(self)) for accurate signature."""
os.chdir("C:\Users\Sylvaenn\Python3.6.0\Programs\tripeg\graphics")
turtle.readconfig("turtle.cfg")
#...
def _construct(self):
"""Constructs the graphics for the game."""
self.window = Screen()
self.window.setworldcoordinates(0,0,10,10)
self._draw_board()
#...
def _draw_board(self):
"""Draws the game board."""
wh_ratio = self.window.canvwidth / self.window.canvheight
tri_board = Shape("compound")
tri_board.addcomponent(((0,0),(8,0),(4,8)),(51,25,0),"black")
self.window.addshape("tri_board", tri_board)
board = Pen("tri_board")
board.pen(pendown=False, outline=7, stretchfactor=(60*wh_ratio,60))
import pdb; pdb.set_trace()
board.setheading(90)
board.goto(1,1)
board.stamp()
现在,这是我到目前为止的发现:
我使用'pdb'创建了一个断点并直接放在调用'pen()'之后。当我 运行 游戏模块并从游戏中调用图形时,就像这样...
>>> ga = Game()
>>> gr = TurtleGraphics()
>>> ga(gr)
> c:\users\sylvaenn\python3.6.0\programs\tripeg\graphics\turtle_.py(82)._draw_board()
-> board.setheading(90)
(Pdb) !board.pen()
{'shown': True, 'pendown': False, 'pencolor': 'black', 'fillcolor': 'black', 'pensize': 1, 'speed': 3, 'resizemode': 'noresize', 'stretchfactor': (71.46496815286623, 60), 'shearfactor': 0.0, 'outline': 7, 'tilt': 0.0}
(Pdb)
...'stretchfactor' 已更改,但尽管有 cfg 文件,'resizemode' 仍设置为 'noresize'。
如果我运行图形模块,直接调用图形,像这样...
>>> gr = TurtleGraphics()
>>> gr._construct()
> c:\users\sylvaenn\python3.6.0\programs\tripeg\graphics\turtle_.py(82)_draw_board()
-> board.setheading(90)
(Pdb) !board.pen
{'shown': False, 'pendown': False, 'pencolor': 'black', 'fillcolor': 'black', 'pensize': 1, 'speed': 3, 'resizemode': 'user', 'stretchfactor': (71.46496815286623, 60), 'shearfactor': 0.0, 'outline': 7, 'tilt': 0.0}
(Pdb)
...'stretchfactor' 和 'resizemode' 都具有预期值。
我已经尝试过的:
- 分析了 'turtle' 的源代码,特别是 'pen()'、'_CFG' 和 类 'Turtle'、'RawTurtle' 及其基础类
- 广泛阅读教程 python.org 和方法文档字符串
- 运行 使用 IDLE 调试器和 'pdb'
逐步完成程序
正如我一开始所说,我可以通过在 'pen()' 以及 cfg 文件中包含 "resizemode='user'" 或使用 'shapesize()' 来完成这项工作。只是我想知道为什么我的 cfg 文件在所有情况下都没有达到预期目的,我想更好地理解 'turtle' 模块和 Python ,如果我不这样做明白为什么会这样,我相信我会 运行 遇到更严重的错误,而且我无法修复它们。
I want to know why my cfg file isn't serving its intended purpose in
all cases
这是我对你的情况的分析。您的代码的关键部分是:
import turtle
#...
def __init__(self):
os.chdir("C:\Users\Sylvaenn\Python3.6.0\Programs\tripeg\graphics")
turtle.readconfig("turtle.cfg")
需要注意的两件事可能并不明显:
turtle.readconfig()
的参数被忽略。相反它看起来
对于目录中的硬编码文件名 "turtle.cfg"
*.py 源文件来自当前工作目录。在
那个命令。如果两者都加载,则优先加载第二个
存在。 (还有第三种可能的配置文件我不会去
到这里。)
如果os.chdir()
在import turtle
之后,就不会看
对于刚刚更改到的目录中的配置文件。
如果需要,os.chdir()
必须在 import turtle
之前
它在 chdir 目录中查找。即使明确调用
turtle.readconfig()
为了演示第二点,首先在临时目录中创建一个配置文件:
mkdir temporary_directory
echo "resizemode = user" > temporary_directory/turtle.cfg
运行 此代码:
import os
import turtle
from os.path import isfile
current_directory = os.getcwd()
os.chdir("temporary_directory")
turtle.readconfig(None)
print(turtle.resizemode())
您将获得默认的 noresize
模式。 运行 再次修改代码:
import os
from os.path import isfile
current_directory = os.getcwd()
os.chdir("temporary_directory")
import turtle
turtle.readconfig(None)
print(turtle.resizemode())
您将获得模式 user
。
最后,如 turtle 文档中所述,当 shapesize()
被带参数调用时,resizemode('user')
被 shapesize()
调用。
我正在使用 Python 3.6.0 自动化在 Cracker Barrel 找到的 "triangle peg game",我目前正在使用 'turtle' 实现其图形。我创建的两个 类 与此问题相关:'Game'(包含在主包中的模块中)和 'TurtleGraphics'(包含在子包中的模块中 'graphics'),其预期目的是不言自明的。当使用 'TurtleGraphics' 对象作为参数调用 'Game' 对象时,这两个对象相互链接,并调用 'graphics._construct()',它定义了一个 'Pen' 对象和使用 'pen()' 设置其 'stretchfactor'。这就是问题出现的地方。即使我在 'turtle.cfg' 文件中将 'resizemode' 设置为 'user',我必须再次将 'resizemode' 设置为 'user' 作为 [=57= 的参数] 以便在从游戏调用时正确构造图形。 St运行gely 够了,如果我 运行 直接包含 'TurtleGraphics' 的模块并创建一个图形对象,它工作正常。此外,即使当我从游戏对象调用图形时,使用 'shapesize()' 而不是 'pen()' 设置 'stretchfactor' 也有效。首先,我将 post 'Game.__call__' 和 'TurtleGraphics._construct' 的代码,在每个模块的导入前加上,这可能是相关的。我也会 post 'TurtleGraphics.__init__' 和 'TurtleGraphics._draw_board'。 (类 都有基础 类,但是 'BaseGame' 不处理图形,而 'Graphics' 是抽象的,所以在这种情况下它们是无关紧要的。此外,值得一提的是'Game' 没有 '__init__' 方法。所有实例属性都在调用时分配。)然后我将解释到目前为止我对此事所做的研究。
Game.__call__:
from tripeg.graphics import Graphics
from tripeg.graphics.ascii_ import ASCIIGraphics
from tripeg.graphics.turtle_ import TurtleGraphics
#...
def __call__(self, graphics=None):
"""Starts the game with given graphics, or none, if not given."""
super().__call__()
if graphics:
if not isinstance(graphics, Graphics):
raise TypeError(f"Argument '{graphics}' is not of type"
" 'Graphics'.")
else:
self._graphics = graphics
self._graphics._game = self
self._graphics._construct()
TurtleGraphics._construct:
import os
import turtle
from turtle import Screen, RawPen, Pen, Shape, Terminator, _CFG
from tripeg.graphics import Graphics
#...
def __init__(self):
"""Initialize self. See help(type(self)) for accurate signature."""
os.chdir("C:\Users\Sylvaenn\Python3.6.0\Programs\tripeg\graphics")
turtle.readconfig("turtle.cfg")
#...
def _construct(self):
"""Constructs the graphics for the game."""
self.window = Screen()
self.window.setworldcoordinates(0,0,10,10)
self._draw_board()
#...
def _draw_board(self):
"""Draws the game board."""
wh_ratio = self.window.canvwidth / self.window.canvheight
tri_board = Shape("compound")
tri_board.addcomponent(((0,0),(8,0),(4,8)),(51,25,0),"black")
self.window.addshape("tri_board", tri_board)
board = Pen("tri_board")
board.pen(pendown=False, outline=7, stretchfactor=(60*wh_ratio,60))
import pdb; pdb.set_trace()
board.setheading(90)
board.goto(1,1)
board.stamp()
现在,这是我到目前为止的发现:
我使用'pdb'创建了一个断点并直接放在调用'pen()'之后。当我 运行 游戏模块并从游戏中调用图形时,就像这样...
>>> ga = Game()
>>> gr = TurtleGraphics()
>>> ga(gr)
> c:\users\sylvaenn\python3.6.0\programs\tripeg\graphics\turtle_.py(82)._draw_board()
-> board.setheading(90)
(Pdb) !board.pen()
{'shown': True, 'pendown': False, 'pencolor': 'black', 'fillcolor': 'black', 'pensize': 1, 'speed': 3, 'resizemode': 'noresize', 'stretchfactor': (71.46496815286623, 60), 'shearfactor': 0.0, 'outline': 7, 'tilt': 0.0}
(Pdb)
...'stretchfactor' 已更改,但尽管有 cfg 文件,'resizemode' 仍设置为 'noresize'。
如果我运行图形模块,直接调用图形,像这样...
>>> gr = TurtleGraphics()
>>> gr._construct()
> c:\users\sylvaenn\python3.6.0\programs\tripeg\graphics\turtle_.py(82)_draw_board()
-> board.setheading(90)
(Pdb) !board.pen
{'shown': False, 'pendown': False, 'pencolor': 'black', 'fillcolor': 'black', 'pensize': 1, 'speed': 3, 'resizemode': 'user', 'stretchfactor': (71.46496815286623, 60), 'shearfactor': 0.0, 'outline': 7, 'tilt': 0.0}
(Pdb)
...'stretchfactor' 和 'resizemode' 都具有预期值。
我已经尝试过的:
- 分析了 'turtle' 的源代码,特别是 'pen()'、'_CFG' 和 类 'Turtle'、'RawTurtle' 及其基础类
- 广泛阅读教程 python.org 和方法文档字符串
- 运行 使用 IDLE 调试器和 'pdb' 逐步完成程序
正如我一开始所说,我可以通过在 'pen()' 以及 cfg 文件中包含 "resizemode='user'" 或使用 'shapesize()' 来完成这项工作。只是我想知道为什么我的 cfg 文件在所有情况下都没有达到预期目的,我想更好地理解 'turtle' 模块和 Python ,如果我不这样做明白为什么会这样,我相信我会 运行 遇到更严重的错误,而且我无法修复它们。
I want to know why my cfg file isn't serving its intended purpose in all cases
这是我对你的情况的分析。您的代码的关键部分是:
import turtle
#...
def __init__(self):
os.chdir("C:\Users\Sylvaenn\Python3.6.0\Programs\tripeg\graphics")
turtle.readconfig("turtle.cfg")
需要注意的两件事可能并不明显:
turtle.readconfig()
的参数被忽略。相反它看起来 对于目录中的硬编码文件名 "turtle.cfg" *.py 源文件来自当前工作目录。在 那个命令。如果两者都加载,则优先加载第二个 存在。 (还有第三种可能的配置文件我不会去 到这里。)如果
os.chdir()
在import turtle
之后,就不会看 对于刚刚更改到的目录中的配置文件。 如果需要,os.chdir()
必须在import turtle
之前 它在 chdir 目录中查找。即使明确调用turtle.readconfig()
为了演示第二点,首先在临时目录中创建一个配置文件:
mkdir temporary_directory
echo "resizemode = user" > temporary_directory/turtle.cfg
运行 此代码:
import os
import turtle
from os.path import isfile
current_directory = os.getcwd()
os.chdir("temporary_directory")
turtle.readconfig(None)
print(turtle.resizemode())
您将获得默认的 noresize
模式。 运行 再次修改代码:
import os
from os.path import isfile
current_directory = os.getcwd()
os.chdir("temporary_directory")
import turtle
turtle.readconfig(None)
print(turtle.resizemode())
您将获得模式 user
。
最后,如 turtle 文档中所述,当 shapesize()
被带参数调用时,resizemode('user')
被 shapesize()
调用。