在 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
Writing a class that accepts a callback in Python?
提问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!
它在创建之前操作类!