在 Python 中 instance() 可以用来检测 class 方法吗?
In Python can instance() be used to detect a class method?
如何判断一个对象是否是class方法?使用 instance() 不是最佳实践吗?如何实现这一点?
class Foo:
class_var = 0
@classmethod
def bar(cls):
cls.class_var += 1
print("class variable value:", cls.class_var)
def wrapper(wrapped: classmethod):
"""
Call the wrapped method.
:param wrapped (classmethod, required)
"""
wrapped()
Foo.bar()
wrapper(Foo.bar)
print("the type is:", type(Foo.bar))
print("instance check success:", isinstance(Foo.bar, classmethod))
输出:
class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False
Process finished with exit code 0
如您所知,Python 使用对 class 本身的引用填充 classmethod
的第一个参数,如果您从 class 或 class 的实例。方法对象是一个绑定了对象的函数。
可以通过 .__self__
属性检索该对象。因此,您可以简单地检查 .__self__
属性是否为 class。如果是 class , 就是 class 就是 type
.
一种方法:
class Foo:
@classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(m):
first_parameter = getattr(m, '__self__', None)
if not first_parameter:
return False
type_ = type(first_parameter)
return type_ is type
print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))
输出:
True
True
-----------------------------------
False
False
inspect 模块中有一个 ismethod
函数专门检查对象是否是绑定方法。您也可以在检查第一个参数的类型之前使用它。
注意:上面的解决方案有一个警告,我会在最后提到它。
解决方案编号 2:
您的 isinstance
解决方案无效,因为 classmethod
是一个描述符。如果您想获取实际的 class 方法实例,您应该检查 Foo 的命名空间并从那里获取方法。
class Foo:
@classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(cls, m):
return isinstance(cls.__dict__[m.__name__], classmethod)
print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))
解决方案 1 警告:例如,如果您有一个简单的 MethodType
对象,其绑定对象与 class 不同,例如 int
在这里,这个解决方案是行不通的。因为记得我们刚刚检查了第一个参数是否是 type
:
类型
from types import MethodType
class Foo:
def fn2(self):
pass
fn2 = MethodType(fn2, int)
@classmethod
def fn1(cls):
pass
现在只有解决方案 2 有效。
如果您只想将 class 方法与常规方法和静态方法区分开来,那么您可以使用 inspect.ismethod(f)
.
进行检查
class A:
def method(self): pass
@classmethod
def class_method(cls): pass
@staticmethod
def static_method(): pass
在 REPL 中:
>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False
如果您更喜欢使用 isinstance
执行此操作,则可以使用 typing.types.MethodType
:
>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False
请注意,这些测试会错误地识别例如A().method
因为实际上我们只是在测试绑定方法而不是未绑定函数。因此,上述解决方案仅在假设您正在检查 A.something
的情况下起作用,其中 A
是 class 并且 something
是常规方法、class 方法或静态方法。
如何判断一个对象是否是class方法?使用 instance() 不是最佳实践吗?如何实现这一点?
class Foo:
class_var = 0
@classmethod
def bar(cls):
cls.class_var += 1
print("class variable value:", cls.class_var)
def wrapper(wrapped: classmethod):
"""
Call the wrapped method.
:param wrapped (classmethod, required)
"""
wrapped()
Foo.bar()
wrapper(Foo.bar)
print("the type is:", type(Foo.bar))
print("instance check success:", isinstance(Foo.bar, classmethod))
输出:
class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False
Process finished with exit code 0
如您所知,Python 使用对 class 本身的引用填充 classmethod
的第一个参数,如果您从 class 或 class 的实例。方法对象是一个绑定了对象的函数。
可以通过 .__self__
属性检索该对象。因此,您可以简单地检查 .__self__
属性是否为 class。如果是 class , 就是 class 就是 type
.
一种方法:
class Foo:
@classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(m):
first_parameter = getattr(m, '__self__', None)
if not first_parameter:
return False
type_ = type(first_parameter)
return type_ is type
print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))
输出:
True
True
-----------------------------------
False
False
inspect 模块中有一个 ismethod
函数专门检查对象是否是绑定方法。您也可以在检查第一个参数的类型之前使用它。
注意:上面的解决方案有一个警告,我会在最后提到它。
解决方案编号 2:
您的 isinstance
解决方案无效,因为 classmethod
是一个描述符。如果您想获取实际的 class 方法实例,您应该检查 Foo 的命名空间并从那里获取方法。
class Foo:
@classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(cls, m):
return isinstance(cls.__dict__[m.__name__], classmethod)
print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))
解决方案 1 警告:例如,如果您有一个简单的 MethodType
对象,其绑定对象与 class 不同,例如 int
在这里,这个解决方案是行不通的。因为记得我们刚刚检查了第一个参数是否是 type
:
from types import MethodType
class Foo:
def fn2(self):
pass
fn2 = MethodType(fn2, int)
@classmethod
def fn1(cls):
pass
现在只有解决方案 2 有效。
如果您只想将 class 方法与常规方法和静态方法区分开来,那么您可以使用 inspect.ismethod(f)
.
class A:
def method(self): pass
@classmethod
def class_method(cls): pass
@staticmethod
def static_method(): pass
在 REPL 中:
>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False
如果您更喜欢使用 isinstance
执行此操作,则可以使用 typing.types.MethodType
:
>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False
请注意,这些测试会错误地识别例如A().method
因为实际上我们只是在测试绑定方法而不是未绑定函数。因此,上述解决方案仅在假设您正在检查 A.something
的情况下起作用,其中 A
是 class 并且 something
是常规方法、class 方法或静态方法。