Skip to main content
 首页 » 编程设计

python之在 Python 中创建静态类

2025年05月04日15wuhuacong

我喜欢创建可以被其他类使用并且所有方法都是静态的 (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 中是为了帮助您避免意外的名称冲突,而不是理所当然地保护成员变量。