Class 对函数的变量引用更改为 instancemethod
Class variable reference to function changes to instancemethod
我正在尝试通过 class 变量调用外部函数。以下是我的真实代码的简化:
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)
如果我在 class 方法 setUpClass()
.
中使用 MyClass
代替 cls
,情况似乎没有改变
我希望 MyClass.func_ref
的类型在 setUpClass()
中的赋值后为 function
,这解释了我在尝试调用它时得到的 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
的类型在我为它分配 function
.
类型的值时以 instancemethod
结束
当 func_ref
被调用时,它需要一个 self
参数,就像任何其他普通(实例)class 方法一样(参见 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!
只需将函数通过一个staticmethod
如下:
@classmethod
def setUpClass(cls):
#MyClass.func_ref = func
cls.func_ref = staticmethod(func)
在这种情况下不需要使用基于@的装饰器,因为您想修改方法绑定到 MyClass 的方式,而不是 func
的一般定义。
为什么这是必要的?因为,当您将方法分配给 class 时,Python 假定您将要引用一个实例(通过 self
)或 class(通过 cls
). self
,与 JS 中的 this
不同,它只是一个命名约定,所以当它看到 arg
时,它假定它有一个实例,但你在调用中传递了一个字符串。
因此,正如 Python 所关心的那样,您也可以写 def func(self):
。这就是消息显示 unbound method func() must be called with MyClass instance as first argument
.
的原因
staticmethod
的意思是,“请别管它,不要在第一个变量中假设一个实例或 class”。
你甚至可以省去 setUpClass entirely
:
class MyClass(object):
func_ref = staticmethod(func)
顺便说一句:在 2021 年,也就是停产后 16 个月,Python 2.7 散发着发霉运动袜的所有微妙气味。除了不太安全,从病毒学角度来说。
我正在尝试通过 class 变量调用外部函数。以下是我的真实代码的简化:
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)
如果我在 class 方法 setUpClass()
.
MyClass
代替 cls
,情况似乎没有改变
我希望 MyClass.func_ref
的类型在 setUpClass()
中的赋值后为 function
,这解释了我在尝试调用它时得到的 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
的类型在我为它分配 function
.
instancemethod
结束
当 func_ref
被调用时,它需要一个 self
参数,就像任何其他普通(实例)class 方法一样(参见 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!
只需将函数通过一个staticmethod
如下:
@classmethod
def setUpClass(cls):
#MyClass.func_ref = func
cls.func_ref = staticmethod(func)
在这种情况下不需要使用基于@的装饰器,因为您想修改方法绑定到 MyClass 的方式,而不是 func
的一般定义。
为什么这是必要的?因为,当您将方法分配给 class 时,Python 假定您将要引用一个实例(通过 self
)或 class(通过 cls
). self
,与 JS 中的 this
不同,它只是一个命名约定,所以当它看到 arg
时,它假定它有一个实例,但你在调用中传递了一个字符串。
因此,正如 Python 所关心的那样,您也可以写 def func(self):
。这就是消息显示 unbound method func() must be called with MyClass instance as first argument
.
staticmethod
的意思是,“请别管它,不要在第一个变量中假设一个实例或 class”。
你甚至可以省去 setUpClass entirely
:
class MyClass(object):
func_ref = staticmethod(func)
顺便说一句:在 2021 年,也就是停产后 16 个月,Python 2.7 散发着发霉运动袜的所有微妙气味。除了不太安全,从病毒学角度来说。