Генерация блоков кода Python с помощью цикла for - PullRequest
2 голосов
/ 22 февраля 2011

Я сделал небольшую программу с графическим интерфейсом PyGtk для параметрического рисования рамки велосипеда (идея: вы перемещаете какой-то ползунок, и рамка обновляется с обновленным параметром).

Где-то в коде,Я должен создать ползунок для каждого параметра, и я получаю очень непитоновый и повторяющийся код (извините, я не мог правильно сделать отступ при написании этого сообщения):

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 ]

3 голосов
/ 22 февраля 2011

Я думаю, это более или менее то, что вы ищете:

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)
2 голосов
/ 22 февраля 2011

Эта функция высшего порядка создает функции для вас.Но вам нужно убедиться, что переменные типа painelhoriz и BikeDrawing либо находятся в области действия для определения, либо передают их вручную.

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

Одно замечание: вы, похоже, перепутали генерацию виджетов снастройка атрибутов и перфрейма.Таким образом, код будет генерировать все виджеты заново каждый раз, когда они меняются ...

2 голосов
/ 22 февраля 2011

Если я вас понимаю:

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, для виджетов.

Обратите внимание, что нет необходимости настраивать локальные имена для объектов или имен функций, здесь важны только имена атрибутов. Для более общего кода используйте более общие имена функций и объектов.

1 голос
/ 22 февраля 2011

Вы можете использовать самоанализ, что-то вроде:

for par in par_list:
    value=getattr(BikeDrawing.p, par)
    # ...
1 голос
/ 22 февраля 2011

Чтобы ответить на ваш вопрос буквально - exec.Но это должно быть зарезервировано, когда другие варианты не являются жизнеспособными, и ваш код может быть легко реорганизован, чтобы стать более универсальным.Посмотрите на getattr и setattr, т.е. вместо BikeDrawing.p.something = foo do setattr(BikeDrawing.p, 'something', foo) - вы можете использовать переменную для имени атрибута, аналогично с доступом к атрибутам и getattr.Все дело в поиске шаблонов (а их у вас много - создание Adjustment / HScale экземпляров, установка BikeDrawing.p) и перемещение кода.

0 голосов
/ 22 февраля 2011

Я бы предложил обернуть его в класс, который знает, как управлять / рисовать сам.Вам все равно нужно либо передать имя атрибута для изменения (например, "bottomBracketHeight") и использовать getattr / setattr для BikeDrawing.p (или вы можете даже просто сохранить их как переменные экземпляра этого нового класса, если нетдругой код касается этих значений!), и каждый класс получит свои собственные HScale и Label для манипуляции.

...