Python元编程:自动生成成员函数

6 投票
2 回答
6032 浏览
提问于 2025-04-16 07:22

我想写一个函数,能够给一个类添加方法。我有:

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 方法,那就太好了:

    def insert_labeled_slider(hbox, name, slider_target):
        # name
        hbox.addWidget(QLabel(name))

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

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

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

最终代码:

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 个回答

9

这里有一个你新发布的代码的真实例子:

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 的值,所以做的事情稍有不同。如果你打算做很多这种事情,闭包绝对是值得研究的。

这方面的内容可能还有很多,如果你有特别的问题没有被解答,建议你更新你的提问。

撰写回答