Метапрограммирование Python: автоматически генерировать функции-члены - PullRequest
6 голосов
/ 20 ноября 2010

Как мне написать функцию, которая добавляет метод к классу?У меня есть:

class A:
    def method(self):
        def add_member(name):
            self.new_method = def name...?

        add_member("f1")
        add_member("f2")

Чтобы ответить на то, что я пытаюсь сделать.Я пытаюсь выделить некоторые pyqt слоты.Я хочу иметь возможность вызывать функцию create_slider, которая создаст QSlider и QLabel, создаст код обработки ползунка и заставит обработчик ползунка обновить текст в QLabel.Вот слот, который необходимо вычленить:

    def on_sample_slider(self, value):
        self.samples = pow(4, value)
        self.sample_label.setText('%d' % self.samples)

вот метод, который генерирует некоторый пользовательский интерфейс, но было бы неплохо, чтобы он генерировал метод on_sample_slider при каждом его вызове:1012 *

Итоговый код:

def attach_on_slider(obj, name, variable, label, base):
    def on_slider(self, value):
        variable = base**value
        label.setText('%d' % variable)

    # This next line creates a method from the function
    # The first arg is the function and the second arg is the object
    # upon which you want it to be a method.
    method = types.MethodType(on_slider, obj)
    obj.__dict__["on_slider_" + name] = method
    return method

class A:
    def insert_labeled_slider(hbox, name, label_name, variable):
        # name
        hbox.addWidget(QLabel(label_name))

        # label
        label = QLabel()
        label.setMinimumSize(40, 0)
        hbox.addWidget(label)

        #slider
        slider = QSlider(Qt.Horizontal)
        slider.setRange(0, 6)
        slider.setTracking(True)
        slider.setPageStep(1)
        hbox.addWidget(slider)

        on_slider_method = attach_on_slider(self, name, variable, label, 4)

        self.connect(slider, SIGNAL('valueChanged(int)'),
                     on_slider_method)
        slider.setValue(0)
        return (label, slider)

Ответы [ 2 ]

7 голосов
/ 20 ноября 2010

Вот реальный пример из вашего недавно опубликованного кода:

import types

def attach_on_sample_slider(obj, base):
    def on_sample_slider(self, value):
        self.samples = base**value
        self.sample_label.setText('%d' % self.samples)

    # This next line creates a method from the function
    # The first arg is the function and the second arg is the object
    # upon which you want it to be a method.
    obj.on_sample_slider = types.MethodType(on_sample_slider, obj)

Теперь вы можете называть это как

def some_method(self, foo):
    attach_on_sample_slider(self, 4)

оригинальный пост

Поскольку вы говорите, что функции-члены идентичны, я бы сделал это примерно так

def make_method(name):
    def method(self, whatever, args, go, here):
        #whatever code goes here
    method.__name__ = name
    return method


class A(object):
    method1 = make_method('method1')
    method2 = make_method('method2') 

Строго говоря, передача имени и установка атрибута __name__ для новой функции не обязательна, но может помочь с отладкой. Это немного дублирование и может окупиться. Если вы собираетесь пропустить это, вы могли бы также сделать

class A(object):
    def method1(self, arg1, arg2):
        #code goes here

    method2 = method1
    method3 = method1 

Это создает идентичные методы. Вызов любого из них приведет к тому же методу.

Первая форма более мощная, потому что вы можете передавать другие аргументы, кроме имени, в make_method и иметь разные версии возвращаемого метода для доступа к этим параметрам при закрытии, чтобы они работали по-разному. Вот глупый пример с функциями (работает так же с методами):

def make_opener(filename):
    def opener():
        return open(filename)
    return opener

open_config = make_opener('config.cfg')
open_log = make_opener('log.log')

Здесь все они по сути являются одной и той же функцией, но выполняют немного разные вещи, потому что у них есть доступ к значению filename, с которым они были созданы. Закрытия - это определенно то, на что стоит обратить внимание, если вы собираетесь делать много такого рода вещей.

Это может быть намного больше, поэтому, если у вас есть конкретные вопросы, на которые они не отвечают, вы должны обновить свой вопрос.

0 голосов
/ 10 сентября 2012
...