这是一个非常简单的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
成为staticmethod
和g
成为staticmethod
的元类。
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")
不幸的是,这不起作用。似乎在metaclasse的__init__
中,一切都被认为只是一个函数(只需打印cls.f
而cls.g
就可以了。)
我在这里找不到什么东西?
答案 0 :(得分:2)
此:
if not (inspect.ismethod(cls.g) and cls.g.__self__ == cls):
raise Exception("g should be a class method")
工作正常,但是这个:
if not inspect.isfunction(cls.f):
raise Exception("f should be a static method")
没有,因为在Python 3上,cls.f
将是f
函数,无论是否应用了staticmethod
装饰器。 (在Python 2上,它将是一个没有装饰器的未绑定方法对象。)
而不是访问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()
答案 1 :(得分:1)
好的,所以似乎尝试检查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'
。
答案 2 :(得分:0)
对于Python 3.2+,您可以使用inspect.getattr_static
:
无需通过描述符协议 getattr ()或 getattribute ()触发动态查找即可获取属性。
示例:
import inspect
class A:
@staticmethod
def f():
pass
@classmethod
def g(cls):
pass
def r():
pass
a = A()
print(isinstance(inspect.getattr_static(a, "f"), staticmethod))
print(isinstance(inspect.getattr_static(A, "f"), staticmethod))
print(isinstance(inspect.getattr_static(a, "g"), classmethod))
print(isinstance(inspect.getattr_static(A, "g"), classmethod))
print(isinstance(inspect.getattr_static(a, "r"), classmethod))
print(isinstance(inspect.getattr_static(A, "r"), staticmethod))
将输出:
True
True
True
True
False
False