使用 for 循环生成 Python 代码块
我用 PyGtk 制作了一个小型 GUI 程序,用于参数化绘制自行车的框架(想法:移动一些滑块,然后使用更新的参数重新绘制框架)。
在代码中的某个地方,我必须为每个参数创建一个滑块,并且我得到了这个非常非Pythonic和重复的代码(抱歉,我在编写此消息时无法获得正确的缩进):
def adjustbottomBracketHeight(par):
BikeDrawing.p.bottomBracketHeight = par.get_value()
painelhoriz.queue_draw()
bottomBracketHeightAdjust = gtk.Adjustment(value=BikeDrawing.p.bottomBracketHeight, lower=180., upper=400., step_incr=10.)
bbhScale = gtk.HScale(adjustment=bottomBracketHeightAdjust)
bbhScale.set_value_pos(gtk.POS_LEFT)
bbhScale.connect("value-changed", adjustbottomBracketHeight)
bbhLabel = gtk.Label("Bottom bracket height")
topcolumn1.pack_start(bbhLabel, False, False)
topcolumn1.pack_start(bbhScale, True, True)
def adjustseatTubeAngle(par):
BikeDrawing.p.seatTubeAngle = par.get_value()
painelhoriz.queue_draw()
seatTubeAngleAdjust = gtk.Adjustment(value=BikeDrawing.p.seatTubeAngle, lower=60., upper=85., step_incr=0.5)
staScale = gtk.HScale(adjustment=seatTubeAngleAdjust)
staScale.set_value_pos(gtk.POS_LEFT)
staScale.connect("value-changed", adjustseatTubeAngle)
staLabel = gtk.Label("Seat tube angle")
topcolumn1.pack_start(staLabel, False, False)
topcolumn1.pack_start(staScale, True, True)
def adjustSeatTubeLength(par):
BikeDrawing.p.seatTubeLength = par.get_value()
painelhoriz.queue_draw()
seatTubeLengthAdjust = gtk.Adjustment(value=BikeDrawing.p.seatTubeLength, lower=300., upper=700., step_incr=10.)
stlScale = gtk.HScale(adjustment=seatTubeLengthAdjust)
stlScale.set_value_pos(gtk.POS_LEFT)
stlScale.connect("value-changed", adjustSeatTubeLength)
topcolumn1.pack_start(stlScale, True, True)
def adjusttopTubeLength(par):
BikeDrawing.p.topTubeLength = par.get_value()
painelhoriz.queue_draw()
topTubeLengthAdjust = gtk.Adjustment(value=BikeDrawing.p.topTubeLength,
lower=400., upper=700., step_incr=10.)
ttlScale = gtk.HScale(adjustment=topTubeLengthAdjust)
ttlScale.set_value_pos(gtk.POS_LEFT)
ttlScale.connect("value-changed", adjusttopTubeLength)
topcolumn1.pack_start(ttlScale, True, True)
好吧,通过一些小的调整,我想(知道如何;o)“创建”这种迭代参数名称列表的代码,类似于:
par_list = ['bottomBracketHeight', 'seatTubeAngle', 'seatTubeHeight']
def widgetize(PARAMETER):
""" Create blocks of code where the name PARAMETER would be used to personalize names of handlers, functions, objects, etc. """
for par in par_list:
widgetize(par)
我读了一些以前的问题/答案,似乎没有这个特定问题的答案。
非常感谢您的关注
I made a small GUI program with PyGtk for parametrically drawing the frame of a bike (the idea: you move some slider, and the frame gets redrawn with the updated parameter).
Somewhere in the code, I must create a slider for each parameter, and I get this very non-pythonic and repetitive code (sorry, I could not get the indentation right while writing this message):
def adjustbottomBracketHeight(par):
BikeDrawing.p.bottomBracketHeight = par.get_value()
painelhoriz.queue_draw()
bottomBracketHeightAdjust = gtk.Adjustment(value=BikeDrawing.p.bottomBracketHeight, lower=180., upper=400., step_incr=10.)
bbhScale = gtk.HScale(adjustment=bottomBracketHeightAdjust)
bbhScale.set_value_pos(gtk.POS_LEFT)
bbhScale.connect("value-changed", adjustbottomBracketHeight)
bbhLabel = gtk.Label("Bottom bracket height")
topcolumn1.pack_start(bbhLabel, False, False)
topcolumn1.pack_start(bbhScale, True, True)
def adjustseatTubeAngle(par):
BikeDrawing.p.seatTubeAngle = par.get_value()
painelhoriz.queue_draw()
seatTubeAngleAdjust = gtk.Adjustment(value=BikeDrawing.p.seatTubeAngle, lower=60., upper=85., step_incr=0.5)
staScale = gtk.HScale(adjustment=seatTubeAngleAdjust)
staScale.set_value_pos(gtk.POS_LEFT)
staScale.connect("value-changed", adjustseatTubeAngle)
staLabel = gtk.Label("Seat tube angle")
topcolumn1.pack_start(staLabel, False, False)
topcolumn1.pack_start(staScale, True, True)
def adjustSeatTubeLength(par):
BikeDrawing.p.seatTubeLength = par.get_value()
painelhoriz.queue_draw()
seatTubeLengthAdjust = gtk.Adjustment(value=BikeDrawing.p.seatTubeLength, lower=300., upper=700., step_incr=10.)
stlScale = gtk.HScale(adjustment=seatTubeLengthAdjust)
stlScale.set_value_pos(gtk.POS_LEFT)
stlScale.connect("value-changed", adjustSeatTubeLength)
topcolumn1.pack_start(stlScale, True, True)
def adjusttopTubeLength(par):
BikeDrawing.p.topTubeLength = par.get_value()
painelhoriz.queue_draw()
topTubeLengthAdjust = gtk.Adjustment(value=BikeDrawing.p.topTubeLength,
lower=400., upper=700., step_incr=10.)
ttlScale = gtk.HScale(adjustment=topTubeLengthAdjust)
ttlScale.set_value_pos(gtk.POS_LEFT)
ttlScale.connect("value-changed", adjusttopTubeLength)
topcolumn1.pack_start(ttlScale, True, True)
Well with some minor adaptations, I would like (to know how ;o) to "create" this kind of code iterating over a list of the parameter names, something similar to:
par_list = ['bottomBracketHeight', 'seatTubeAngle', 'seatTubeHeight']
def widgetize(PARAMETER):
""" Create blocks of code where the name PARAMETER would be used to personalize names of handlers, functions, objects, etc. """
for par in par_list:
widgetize(par)
I read some previous questions/answers and there seems not to be an answer to this specific problem.
I appreciate very much your attention
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我认为这或多或少是你所追求的:
I think this is more or less what you're after:
如果我理解您的意思:
您可能还想将一些其他参数(例如 BikeDrawing.p)传递给 widgetize。
请注意,不需要自定义对象的本地名称或函数的名称,这里只有属性的名称很重要。对于更通用的代码,请使用更通用的函数和对象名称。
If I understand you:
You might want to pass some other parameters such as BikeDrawing.p in to widgetize also.
Note that there's no need to customise local names for objects or the names of functions, only the names of attributes matter here. For more general code use more general function and object names.
这个高阶函数为您创建函数。但您需要确保像
painelhoriz
和BikeDrawing
这样的变量要么在定义范围内,要么手动传递它们。一点评论:您似乎将小部件的生成与属性调整和每帧绘制混为一谈。照原样,每次更改时,代码都会重新生成所有小部件......
This higher-order function creates the functions for you. But you'll need to make sure variables like
painelhoriz
andBikeDrawing
are either in scope for the definition or pass them manually.One remark: You seem to mix up generation of widgets with adjustment of attributes and per-frame-drawing. As is, the code will generate all the widgets anew every time one changes...
从字面上回答你的问题 -
exec
。但是,当其他选项不可行时,应该保留这一点,并且您的代码可以轻松地重构为更通用。查看getattr
和setattr
,即代替BikeDrawing.p.something = foo
执行setattr(BikeDrawing.p, 'something' , foo)
— 然后您可以使用变量作为属性名称,与访问属性和 getattr 类似。这都是关于查找模式(您有很多模式 - 创建Adjustment
/HScale
实例、设置BikeDrawing.p
)和移动代码大约。To answer your question literally —
exec
. But this should be reserved when other options are not viable, and your code can easily be refactored to be more generic. Look intogetattr
andsetattr
, i.e. instead ofBikeDrawing.p.something = foo
dosetattr(BikeDrawing.p, 'something', foo)
— you can then use a variable for the attribute name, similarly with accessing attributes andgetattr
. It's all about finding patterns (and you have a lot of them — creatingAdjustment
/HScale
instances, settingBikeDrawing.p
), and moving code around.您可能想要使用内省,例如:
You may want to use introspection, something like:
我建议将其包装到一个知道如何管理/绘制自身的类中。您仍然需要传入要修改的属性名称(例如
"bottomBracketHeight"
)并在上使用
(或者,如果没有其他代码触及这些值,您甚至可以将它们存储为这个新类的实例变量!),并且每个类都会获得自己的getattr
/setattr
BikeDrawing.pHScale
和要操作的标签
。I would suggest wrapping it into a class that knows how to manage/draw itself. You would still need to either pass in the attribute name to modify (
"bottomBracketHeight"
for example) and usegetattr
/setattr
onBikeDrawing.p
(or you could even just store them as instance variables of this new class if no other code touches these values!), and each class would get their ownHScale
andLabel
to manipulate.