使用for循环生成Python代码块

时间:2011-02-22 16:16:31

标签: python code-generation pygtk

我用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)

我读过一些以前的问题/答案,似乎没有对这个具体问题的答案。

我非常感谢你的关注

6 个答案:

答案 0 :(得分:3)

我认为这或多或少是你所追求的:

def makeAdjuster(name, attr, lower, upper, step):
    def doAdjust(par):
        setattr(Bikedrawing.p, attr, par.get_value())
        panelhoriz.queue_draw()

    val = getattr(Bikedrawing.p, attr)
    adjust = gtk.Adjustment(value=val, lower=lower, upper=upper, step_incr=step)

    label = gtk.Label(name)
    topcolumn1.pack_start(label, False, False)

    scale = gtk.HScale(adjustment=adjust)
    scale.set_value_pos(gtk.POS_LEFT)
    scale.connect("value-changed", doAdjust)
    topcolumn1.pack_start(scale, True, True)

for adj in (
    ('Bottom bracket height', 'bottomBracketHeight', 180., 400., 10.),
    ('Seat tube angle', 'seatTubeAngle', 60., 80., 0.5),
    ('Seat tube length', 'seatTubeLength', 300., 700., 10.),
    ('Top tube length', 'topTubeLength', 400., 700., 10.)
):
    makeAdjuster(*adj)

答案 1 :(得分:2)

如果我理解你:

def widgetize(parameter):
    def handler(par):
        setattr(BikeDrawing.p, parameter, par.get_value()
        painelhoriz.queue_draw()

    adjust = gtk.Adjustment(value=getattr(BikeDrawing.p, parameter), lower=300., upper=700., step_incr=10.)
    stlScale = gtk.HScale(adjustment=adjust)
    stlScale.set_value_pos(gtk.POS_LEFT)
    stlScale.connect("value-changed", handler)
    topcolumn1.pack_start(stlScale, True, True)

您可能希望将其他参数(例如BikeDrawing.p)传递给widgetize。

请注意,不需要为对象或函数名称自定义本地名称,只有属性名称在这里很重要。对于更通用的代码,请使用更通用的函数和对象名称。

答案 2 :(得分:2)

这个高阶函数为您创建函数。但是,您需要确保painelhorizBikeDrawing等变量位于定义范围内或手动传递。

def widgetize(name, needsLabel = False, labelText = None):
    def adjust(par):
        val = par.get_value()
        setattr(BikeDrawing.p, name, val)
        painelhoriz.queue_draw()
        adjustment = gtk.Adjustment(value=val, lower=180., upper=400., step_incr=10.0)
        scale = gtk.HScale(adjustment=adjustment)
        scale.set_value_pos(gtk.POS_LEFT)
        scale.connect("value-changed", adjust)
        if needsLabel:
            label = gtk.Label(labelText)
            topcolumn1.pack_start(Label, False, False)
        topcolumn1.pack_start(scale, True, True)
    # add nice name for debugging
    adjust.__name__ = "adjust{}".format(name[0].upper() + name[1:])
    return adjust

一句话:您似乎混淆了小部件的生成以及属性和每帧绘制的调整。按原样,代码会在每次更改时重新生成所有小部件...

答案 3 :(得分:1)

按字面意思回答你的问题 - exec。但是当其他选项不可行时,应该保留这一点,并且可以轻松地重构代码以使其更通用。查看getattrsetattr,即代替BikeDrawing.p.something = foo执行setattr(BikeDrawing.p, 'something', foo) - 您可以使用变量作为属性名称,类似于访问属性和getattr 。这一切都与发现模式有关(你有很多模式 - 创建Adjustment / HScale个实例,设置BikeDrawing.p),以及移动代码。

答案 4 :(得分:1)

您可能想要使用内省,例如:

for par in par_list:
    value=getattr(BikeDrawing.p, par)
    # ...

答案 5 :(得分:0)

我建议将它包装成一个知道如何管理/绘制自己的类。你仍然需要传递属性名称来修改(例如"bottomBracketHeight")并在getattr上使用setattr / BikeDrawing.p(或者你甚至可以将它们存储为如果没有其他代码接触这些值,这个新类的实例变量!),每个类都会得到自己的HScaleLabel进行操作。