我喜欢创建可以被其他类使用并且所有方法都是静态的 (staticmethod) 的辅助类。我需要用装饰器 @staticmethod 包装每个方法,但这个解决方案在我看来不太美观。我决定为这样的类创建一个元类——工具,这里是一个抽象的实现示例:
import types
import math
class StaticClass(type):
def __new__(mcs, name, bases, attr):
for name, value in attr.items():
if type(value) is types.MethodType:
attr[name] = staticmethod(value)
return super().__new__(mcs, name, bases, attr)
class Tool(metaclass=StaticClass):
def get_radius_from_area(area):
return math.sqrt(area/Tool.get_pi())
def get_pi():
return math.pi
class CalcRadius:
def __init__(self, area):
self.__area = area
def __call__(self):
return Tool.get_radius_from_area(self.__area)
if __name__ == '__main__':
get_it = CalcRadius(100)
print(get_it()) # 5.641895835477563
一切正常并给出正确的结果,但 IDE 中的代码检查存在可理解和可预测的问题(我使用 Pycharm 2019.2)。
对于 def get_radius_from_area(area): 通常是名为“self”的方法的第一个参数。 “区域”在方法的返回中以黄色突出显示。
对于 get_pi(): 方法必须有第一个参数,通常称为“self” 没有参数的括号中的 Void 带有红色下划线。
如果我在类上方添加行“# noinspection PyMethodParameters”,这部分解决了问题,但它看起来比几十个@staticmethods 还要糟糕。
我理解为什么会这样,以及为什么 JetBrains 的开发人员专门为 Django 改编了他们 IDE 中的部分代码。
但是我能否以某种方式漂亮地创建一个纯静态类,其中所有方法都是静态的? 也许元类不是最佳选择,是否有某种替代解决方案?
最佳答案
您的元类实际上没有做任何事情,因为 types.MethodType
只匹配绑定(bind)的方法对象。当您浏览 __new__
中的类命名空间时,您不会获得任何这些内容,因此您永远不会在 staticmethod
中包装任何内容。
您可以通过将检查更改为 types.FunctionType
来修复它(这可能会满足能够正确看到方法类型的自动化工具):
class StaticClass(type):
def __new__(mcs, name, bases, attr):
for name, value in attr.items():
if type(value) is types.FunctionType:
attr[name] = staticmethod(value)
return super().__new__(mcs, name, bases, attr)
但我建议直接取消类并直接使用函数。函数是 Python 中的一流对象,您可以根据需要在对象之间传递它们。如果你想对它们进行方便的分组,你可以将它们放在列表或字典中,或者使用模块将它们的代码收集在各种分组中(并使用包来对模块进行分组)。我还建议您避免使用前导双下划线 __names
来尝试通过调用名称修改来保护您的属性。它实际上并没有保护您的数据不受任何影响(外部代码仍然可以获取它),并且它使调试变得更加困难。它包含在 Python 中是为了帮助您避免意外的名称冲突,而不是理所当然地保护成员变量。
关于python - 在 Python 中创建静态类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57931486/