Python 如何检查方法是类方法还是元类中的静态方法?
下面是一个非常简单的Python 如何检查方法是类方法还是元类中的静态方法?,python,static-methods,metaclass,class-method,Python,Static Methods,Metaclass,Class Method,下面是一个非常简单的Base类,它包含一个静态方法和一个类方法: class Base(): @staticmethod def f(): print("Base.f") @classmethod def g(cls): print("Base.g") def h(self): print("Base.h") 如果要从Base派生类并重写f或g,则需要在重写方法上再次使用staticmethod和cl
Base
类,它包含一个静态方法和一个类方法:
class Base():
@staticmethod
def f():
print("Base.f")
@classmethod
def g(cls):
print("Base.g")
def h(self):
print("Base.h")
如果要从Base
派生类并重写f
或g
,则需要在重写方法上再次使用staticmethod
和classmethod
装饰器
class A(Base):
@staticmethod
def f():
print("A.f")
class B(Base):
@classmethod
def g(cls):
print("B.g")
所以,一开始我想我会创建一个元类,自动生成f
astaticmethod
和g
astaticmethod
class BaseMeta(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
if 'f' in namespace: cls.f = staticmethod(cls.f)
if 'g' in namespace: cls.g = classmethod(cls.g)
现在剩下的类不需要显式地使用staticmethod
和classmethod
class Base(metaclass=BaseMeta):
def f():
print("Base.f")
def g(cls):
print("Base.g")
def h(self):
print("Base.h")
class A(Base):
def f():
print("A.f")
class B(Base):
def g(cls):
print("B.g")
这行得通,但我不喜欢它的样子。现在,我意识到应该显式使用staticmethod
和classmethod
装饰器(毕竟显式比隐式好,不是吗?)
所以我想我可以保留元类,但是这次我不应该强制使用装饰器,我应该检查它们是否被使用,如果没有,则抛出一个异常
class BaseMeta(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
# check if cls.f is a static method
if not inspect.isfunction(cls.f):
raise Exception("f should be a static method")
# check if cls.g is a static method
if not (inspect.ismethod(cls.g) and cls.g.__self__ == cls):
raise Exception("g should be a class method")
不幸的是,这不起作用。似乎在元类的\uuuu init\uuuu
中,一切都被认为只是一个函数(只需打印cls.f
和cls.g
就可以看出这一点)
这里有什么我遗漏的吗?好的,因此,试图检查
cls.f
或cls.g
是否是元类中的静态或类方法似乎是毫无意义的,它们似乎还没有绑定
然而,在一个方法上使用了staticmethod
或classmethod
装饰器肯定已经在其上留下了印记。我到处玩,最终发现我原本想做的事情可以实现如下:
class BaseMeta(type):
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
# check if cls.f is a static method
if 'f' in namespace and not isinstance(namespace['f'], staticmethod):
raise Exception(cls.__name__ + ".f should be a static method")
# check if cls.g is a class method
if 'g' in namespace and not isinstance(namespace['g'], classmethod):
raise Exception(cls.__name__ + ".g should be a class method")
因此,原来问题的答案是:
通过从名称空间检索方法并检查它是否是'staticmethod'
或'classmethod'
的实例,可以在元类中检查方法是否已用staticmethod
或'classmethod'
修饰
这:
工作正常,但这:
if not inspect.isfunction(cls.f):
raise Exception("f should be a static method")
不会,因为在Python 3上,cls.f
将是f
函数,无论是否应用了staticmethod
装饰器。(在Python2上,如果没有decorator,它将是一个未绑定的方法对象。)
与其访问
cls.f
或cls.g
并试图根据描述符协议的结果确定所使用的描述符类型,不如绕过描述符协议并访问类定义命名空间的原始内容:
if 'f' in namespace and not isinstance(namespace['f'], staticmethod):
whatever()
if 'g' in namespace and not isinstance(namespace['g'], classmethod):
whatever()
对于Python 3.2+,您可以使用: 通过描述符协议、getattr()或getattribute()检索属性而不触发动态查找 例如:
导入检查
A类:
@静力学方法
def():
通过
@类方法
def g(cls):
通过
def r():
通过
a=a()
打印(isinstance(inspect.getattr_static(a,“f”),staticmethod))
打印(isinstance(inspect.getattr_static(A,“f”),staticmethod))
打印(isinstance(inspect.getattr_static(a,“g”),classmethod))
打印(isinstance(inspect.getattr_static(A,“g”),classmethod))
打印(isinstance(inspect.getattr_static(a,“r”),classmethod))
打印(isinstance(inspect.getattr_static(A,“r”),staticmethod))
将输出:
True
True
True
True
False
False
您不需要查看
\uuuuu名称
isinstance(无论什么,staticmethod)
和isinstance(无论什么,classmethod)
都可以。谢谢,这当然更优雅了。我将进行相应的编辑。我测试了inspect.isfunction
,它返回了所有方法的True
(f
,g
和h
)。我还测试了inspect.ismethod
,对于所有这些方法,它都返回了False
。如果您在创建类之后尝试这些测试,那么这些测试实际上是有效的,但是它们在元类中似乎不起作用。@GeorgeBoukeas:你能澄清一下XX
应该在那里表示什么吗?@GeorgeBoukeas:ismethod
返回类方法所期望的True
。在Python中,显式并不一定比隐式好。考虑到EAFP(比许可更容易请求宽恕)被认为是Pythic的,更高层次的思维被鼓励作为计算细节的例子。
True
True
True
True
False
False