关于python:myclass.attr vs type(self).attr vs separate@classmethod

MyClass.attr VS type(self).attr VS separate @classmethod

假设我的类中有一个(正常绑定)方法必须访问类变量(就像__init__中的计数器)。如果我想修改类变量,我可以看到三种可能性:

  • 使用type(self)self.__class__(在阅读完本文后,我选择type而不是__class__,因为我使用的是python 3,所以"旧式"类不适用)
  • 使用类的名称。除非这个名字是反弹的,否则这个效果很好。
  • 专门为更改类变量编写一个@classmethod。这是最复杂,但也是最清晰(IMO)的方法。
  • 这三种方法是这样写的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class MyClass:
        counter = 0

        def f1(self):
            type(self).counter += 1

        def f2(self):
            MyClass.counter += 1

        def f3(self):
            self._count()
        @classmethod
        def _count(cls):
            cls.counter += 1

    是否有一个明确的"最佳"选择,是哪一个,或者它们或多或少是等价的,只是"我最喜欢什么"?继承会改变什么吗?


    如果您从定义变量的方法派生类(并且可能是分配给它的方法),那么使用type(self)将属性(的新值)存储在对象的实际类上。这可能非常有用,但在您的示例中肯定是错误的。

    使用一个类方法是一样的,除了子类可以重写该方法:这可能会使复杂的案例工作,但对于修复简单的继承案例却没有任何作用。

    使用类的名称是简单的、惯用的答案,并且避免了子类的混淆。在不关心重新绑定该名称的情况下,即使没有任何继承,这也应该是默认的。如果这是一个问题,您可以用两种不同的方式存储类对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class A:
      counter=0

      # use the magic behind super():
      def _count1(): __class__.counter+=1

      # inject the class object:
      @staticmethod
      def _count2(cls): cls.counter+=1
    A._count2.__defaults__=A,

    # inject via a closure:
    def capture(cls):
      def _count(): cls.counter+=1
      return _count
    A._count3=staticmethod(capture(A))

    当然,__class__技巧可以直接使用,不需要包装方法,但有点难看;在内部,它与capture的最后一种方法非常相似。有一件事不起作用,那就是试图创建一个引用类字典的函数,因为这些字典是为了优化而保护的。