如何解决对函数的类变量引用更改为 instancemethod
我正在尝试通过类变量调用外部函数。以下是我的真实代码的简化:
def func(arg):
print(arg)
class MyClass(object):
func_ref = None
@classmethod
def setUpClass(cls):
#MyClass.func_ref = func
cls.func_ref = func
@staticmethod
def func_override(arg):
print("override printing arg...")
MyClass.func_ref(arg)
if __name__ == "__main__":
print(type(func))
print(type(MyClass.func_ref))
MyClass.setUpClass()
print(type(MyClass.func_ref))
MyClass.func_override("hello!")
[~]$ python tmp.py
<type 'function'>
<type 'nonetype'>
<type 'instancemethod'>
override printing arg...
Traceback (most recent call last):
File "tmp.py",line 20,in <module>
MyClass.func_override("hello!")
TypeError: func_override() takes exactly 2 arguments (1 given)
如果我在 classmethod MyClass
中使用 cls
代替 setUpClass()
,情况似乎没有改变。
我希望 MyClass.func_ref
的类型在 function
中的赋值之后是 setUpClass()
,这解释了我尝试调用它时得到的 TypeError
。当我分配给它的值是 func_ref
类型时,为什么将 instancemethod
的类型更改为 function
?
这似乎只是 Python 2 中的一个问题。Python 3 的行为符合我的预期。
如何调用静态方法 MyClass.func_override()
以调用 func()
?
更新
通过应用以下补丁,我能够使上述内容正常工作:
@@ -14,7 +14,7 @@ class MyClass(object):
def func_override(arg):
print("override printing arg...")
func(arg)
- MyClass.func_ref.__func__(arg)
+ MyClass.func_ref(arg)
if __name__ == "__main__":
print(type(func))
虽然上述方法有效,但我完全不清楚为什么我需要这样做。我仍然不明白为什么 func_ref
的类型在我为其分配了类型为 instancemethod
的值时以 function
结束。
解决方法
只需将函数通过 staticmethod
如下:
@classmethod
def setUpClass(cls):
#MyClass.func_ref = func
cls.func_ref = staticmethod(func)
在这种情况下不需要使用基于 @ 的装饰器,因为您想修改方法绑定到 MyClass 的方式,而不是 func
的一般定义。
为什么需要这样做?因为,当您将方法分配给类时,Python 假定您要引用实例(通过 self
)或类(通过 cls
)。 self
与 JS 中的 this
不同,它只是一个命名约定,因此当它看到 arg
时,它假定它有一个实例,但您在调用中传递了一个字符串。
因此,正如 Python 所关心的那样,您也可以编写 def func(self):
。这就是消息显示 unbound method func() must be called with MyClass ?instance? as first argument
的原因。
staticmethod
的意思是,“请不要管它,不要在第一个变量中假设一个实例或一个类”。
您甚至可以省去setUpClass entirely
:
class MyClass(object):
func_ref = staticmethod(func)
顺便说一句:在 2021 年,即 EOL 后的 16 个月,Python 2.7 具有发霉的运动袜的所有微妙气味。除了不太安全,从病毒学角度来说。
,当调用 func_ref
时,它需要一个 self
参数,就像任何其他普通(实例)类方法一样(有关原因的讨论,请参阅 this question and answers)。您可以向 self
添加 func
参数或使 func
成为静态方法:
@staticmethod
def func(arg):
print(arg)
>>> MyClass.setUpClass()
>>> MyClass.func_override("hello!")
override printing arg...
hello!
请注意,在这两种情况下,func
现在通常不能作为常规函数调用:
>>> func('what does this do?')
TypeError: 'staticmethod' object is not callable
如果您需要将 func
用作常规函数,您可以用另一个合格的函数包装它并在 MyClass
中使用包装器:
def func(arg):
print(arg)
@staticmethod
def func_wrapper(arg):
func(arg)
class MyClass(object):
@classmethod
def setUpClass(cls):
cls.func_ref = func_wrapper # use wrapper function
>>> MyClass.setUpClass()
>>> MyClass.func_override("success!")
override printing arg...
success!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。