在 Python 中编写一个接受回调的类?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1567777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:36:00  来源:igfitidea点击:

Writing a class that accepts a callback in Python?

pythoncallback

提问by Charles Dietrich

I need to write a class that allows a subclass to set an attribute with the name of a function. That function must then be callable from instances of the class.

我需要编写一个允许子类使用函数名称设置属性的类。然后必须可以从类的实例调用该函数。

For example, I say I need to write a Fruit class where the subclass can pass in a welcome message. The Fruit class must expose an attribute print_callback that can be set.

例如,我说我需要编写一个 Fruit 类,其中子类可以传入欢迎消息。Fruit 类必须公开可以设置的属性 print_callback。

class Fruit(object):
    print_callback = None

    def __init__(self, *args, **kwargs):
        super(Fruit, self).__init__(*args, **kwargs)
        self.print_callback("Message from Fruit: ")

I need to expose an API that is can be consumed by this code (to be clear, this code cannot change, say it is 3rd party code):

我需要公开一个可以被这段代码使用的 API(要清楚,这段代码不能改变,说它是 3rd 方代码):

def apple_print(f):
    print "%sI am an Apple!" % f

class Apple(Fruit):
    print_callback = apple_print

If I run:

如果我运行:

mac = Apple()

I want to get:

我想得到:

Message from Fruit: I am an Apple!

来自水果的消息:我是苹果!

Instead I get:

相反,我得到:

TypeError: apple_print() takes exactly 1 argument (2 given)

类型错误:apple_print() 只需要 1 个参数(给出 2 个)

I think this is because self is passed in as the first argument.

我认为这是因为 self 作为第一个参数传入。

So how do I write the Fruit class? Thanks!

那么我该如何编写 Fruit 类呢?谢谢!

采纳答案by John Millikin

Python assumes that any functions bound within a class scope are methods. If you'd like to treat them as functions, you have to dig around in their attributes to retrieve the original function object:

Python 假定在类范围内绑定的任何函数都是方法。如果您想将它们视为函数,则必须深入挖掘它们的属性以检索原始函数对象:

def __init__(self, *args, **kwargs):
    super(Fruit, self).__init__(*args, **kwargs)

    # The attribute name was changed in Python 3; pick whichever line matches
    # your Python version.
    callback = self.print_callback.im_func  # Python 2
    callback = self.print_callback.__func__ # Python 3

    callback("Message from Fruit: ")

回答by user190071

You can use directly:

您可以直接使用:

class Apple(Fruit):
    print_callback = staticmethod(apple_print)

or:

或者:

class Apple(Fruit):
    print_callback = classmethod(apple_print)

In the first case, you'll get only one parameter (the original). In the second, you'll receive two parameters where the first will be the class on which it was called.

在第一种情况下,您只会得到一个参数(原始参数)。在第二个中,您将收到两个参数,其中第一个是调用它的类。

Hope this helps, and is shorter and less complex.

希望这会有所帮助,并且更短且更简单。

回答by Daniel Pryden

Updated: incorporating abourget's suggestionto use staticmethod:

更新:结合abourget 的使用建议staticmethod

Try this:

试试这个:

def __init__(self, *args, **kwargs):
    super(Fruit, self).__init__(*args, **kwargs)

    # Wrap function back into a proper static method
    self.print_callback = staticmethod(self.print_callback)

    # And now you can do:
    self.print_callback("Message from Fruit: ")

回答by RobotHumans

I was looking for something more like this when I found this question:

当我发现这个问题时,我正在寻找更像这样的东西:

class Something:
    def my_callback(self, arg_a):
        print arg_a

class SomethingElse:
    def __init__(self, callback):
        self.callback = callback

something = Something()
something_else = SomethingElse(something.my_callback)
something_else.callback("It works...")

回答by pygabriel

There's also a bit dirtyer solution with metaclasses:

元类还有一个更脏的解决方案:

def apple_print(f):
    print "Apple " + f

class FruitMeta(type):
    def __new__(cls, name, bases, dct):
        func = dct["print_callback"]
        dct["print_callback"]=lambda x,f,func=func: func(f)
        return type.__new__(cls,name,bases,dct)

class Fruit(object):
    __metaclass__ = FruitMeta
    print_callback = None
    def __init__(self):
        super(Fruit,self).__init__()
        self.print_callback("Msg ")

class Apple(Fruit):
    print_callback = apple_print

mac = Apple()here

It manipulates the class before its creation!

它在创建之前操作类!