使用 for 循环生成 Python 代码块

发布于 2024-10-18 09:01:06 字数 2451 浏览 6 评论 0原文

我用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

(り薆情海 2024-10-25 09:01:06

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

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)

I think this is more or less what you're after:

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)
或十年 2024-10-25 09:01:06

如果我理解您的意思:

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。

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

If I understand you:

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)

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.

樱娆 2024-10-25 09:01:06

这个高阶函数为您创建函数。但您需要确保像 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

一点评论:您似乎将小部件的生成与属性调整和每帧绘制混为一谈。照原样,每次更改时,代码都会重新生成所有小部件......

This higher-order function creates the functions for you. But you'll need to make sure variables like painelhoriz and BikeDrawing are either in scope for the definition or pass them manually.

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

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...

年华零落成诗 2024-10-25 09:01:06

从字面上回答你的问题 - exec。但是,当其他选项不可行时,应该保留这一点,并且您的代码可以轻松地重构为更通用。查看 getattrsetattr,即代替 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 into getattr and setattr, i.e. instead of BikeDrawing.p.something = foo do setattr(BikeDrawing.p, 'something', foo) — you can then use a variable for the attribute name, similarly with accessing attributes and getattr. It's all about finding patterns (and you have a lot of them — creating Adjustment/HScale instances, setting BikeDrawing.p), and moving code around.

你是暖光i 2024-10-25 09:01:06

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

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

You may want to use introspection, something like:

for par in par_list:
    value=getattr(BikeDrawing.p, par)
    # ...
云裳 2024-10-25 09:01:06

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

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 use getattr/setattr on BikeDrawing.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 own HScale and Label to manipulate.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文