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

Nei*_*l G 6 python metaprogramming

如何编写一个向类添加方法的函数?我有:

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

        add_member("f1")
        add_member("f2")
Run Code Online (Sandbox Code Playgroud)

为了回答我正在尝试做的事情.我试图分解出一些pyqt插槽.我希望能够调用一个函数create_slider来创建一个QSlider和一个QLabel并创建滑块处理代码,并使滑块处理程序更新文本QLabel.这是需要考虑的插槽:

    def on_sample_slider(self, value):
        self.samples = pow(4, value)
        self.sample_label.setText('%d' % self.samples)
Run Code Online (Sandbox Code Playgroud)

这是一个生成一些UI的方法,但是每次调用它时都会生成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)
Run Code Online (Sandbox Code Playgroud)

最终代码:

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)
Run Code Online (Sandbox Code Playgroud)

aar*_*ing 7

以下是您新发布的代码中的一个真实示例:

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)
Run Code Online (Sandbox Code Playgroud)

你现在可以这样称呼它

def some_method(self, foo):
    attach_on_sample_slider(self, 4)
Run Code Online (Sandbox Code Playgroud)

原帖

既然你说成员函数是相同的,我会这样做

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') 
Run Code Online (Sandbox Code Playgroud)

严格来说,传递名称并__name__在新函数上设置属性是没有必要的,但它可以帮助调试.这有点重复,可以收回成本.如果你打算跳过这个,你也可以这样做

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

    method2 = method1
    method3 = method1 
Run Code Online (Sandbox Code Playgroud)

这创建了相同的方法.调用其中任何一个都将产生相同的方法.

第一种形式更强大,因为您可以传递除名称之外的其他参数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')
Run Code Online (Sandbox Code Playgroud)

在这里,它们基本上都是相同的功能,但做的事情略有不同,因为它们可以访问filename它们的创建价值.如果你要做很多这类事情,闭包肯定是值得关注的.

这可能还有很多,所以如果你有特别的问题没有解决,你应该更新你的问题.