【问题标题】:Using property() on classmethods在类方法上使用 property()
【发布时间】:2018-05-05 04:53:54
【问题描述】:

我有一个具有两个类方法(使用classmethod() 函数)的类,用于获取和设置本质上是静态变量的内容。我尝试将property() 函数与这些一起使用,但会导致错误。我能够在解释器中使用以下内容重现错误:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

我可以演示类方法,但它们不能用作属性:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

是否可以将property() 函数与@classmethod 修饰函数一起使用?

【问题讨论】:

    标签: python oop


    【解决方案1】:

    Python >= 3.9

    只需同时使用两个装饰器。见this answer

    Python

    属性是在类上创建的,但会影响实例。因此,如果您想要一个 classmethod 属性,请在元类上创建该属性。

    >>> class foo(object):
    ...     _var = 5
    ...     class __metaclass__(type):  # Python 2 syntax for metaclasses
    ...         pass
    ...     @classmethod
    ...     def getvar(cls):
    ...         return cls._var
    ...     @classmethod
    ...     def setvar(cls, value):
    ...         cls._var = value
    ...     
    >>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
    >>> foo.var
    5
    >>> foo.var = 3
    >>> foo.var
    3
    

    但是由于您无论如何都在使用元类,因此如果您将类方法移到那里会更好。

    >>> class foo(object):
    ...     _var = 5
    ...     class __metaclass__(type):  # Python 2 syntax for metaclasses
    ...         @property
    ...         def var(cls):
    ...             return cls._var
    ...         @var.setter
    ...         def var(cls, value):
    ...             cls._var = value
    ... 
    >>> foo.var
    5
    >>> foo.var = 3
    >>> foo.var
    3
    

    或者,使用 Python 3 的 metaclass=... 语法,以及在 foo 类主体之外定义的元类,以及负责设置 _var 初始值的元类:

    >>> class foo_meta(type):
    ...     def __init__(cls, *args, **kwargs):
    ...         cls._var = 5
    ...     @property
    ...     def var(cls):
    ...         return cls._var
    ...     @var.setter
    ...     def var(cls, value):
    ...         cls._var = value
    ...
    >>> class foo(metaclass=foo_meta):
    ...     pass
    ...
    >>> foo.var
    5
    >>> foo.var = 3
    >>> foo.var
    3
    

    【讨论】:

    • 这在 Python 3.2 中似乎对我不起作用。如果我将 foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func) 更改为 foo.__metaclass__.var = property(foo.getvar.__func__, foo.setvar.__func__) 我得到“AttributeError: type执行“foo.var”时,对象“foo”没有属性“var”。
    • 我不太清楚,那么 Python 3.x 的编写方式是什么?
    • @Josay:您需要先定义元类,然后使用新的class Foo(metaclass=...) 语法定义类。
    • 值得注意的是,由于元类的工作方式,这些属性在您的类的实例(在本例中为foo)上不可用,仅在类本身上可用。
    • @Devyzr 发生这种情况是因为......好吧,实际上,它的名字是对的,尽管它是一个不明显的结果。类 Foo 的元类 Meta 是 类 Foo 的类,因此 Foo 本身将是 Meta 的一个实例——但 Foo 的实例将 NOT 是 Meta 的实例。 (它们是 Foo 的实例,而 Foo 不继承 Meta,它实例化 Meta。)因此,Foo 通过作为 Meta 的实例而获得的任何属性都是没有传递给它的实例。如果是,Meta 将是 Foo 的父类,而不是 Foo 的元类。
    【解决方案2】:

    阅读Python 2.2 release的笔记,我发现以下内容。

    [属性]的get方法不会被调用 该属性作为一个类访问 属性 (C.x) 而不是作为 实例属性 (C().x)。如果你 想要覆盖 __get__ 操作 用作类时的属性 属性,你可以继承属性 - 它本身就是一种新型类型-to 扩展它的 __get__ 方法,或者你可以 从头开始定义描述符类型 通过创建一个新样式的类 定义 __get__、__set__ 和 __delete__ 方法。

    注意:以下方法实际上不适用于 setter,仅适用于 getter。

    因此,我认为规定的解决方案是创建一个 ClassProperty 作为属性的子类。

    class ClassProperty(property):
        def __get__(self, cls, owner):
            return self.fget.__get__(None, owner)()
    
    class foo(object):
        _var=5
        def getvar(cls):
            return cls._var
        getvar=classmethod(getvar)
        def setvar(cls,value):
            cls._var=value
        setvar=classmethod(setvar)
        var=ClassProperty(getvar,setvar)
    
    assert foo.getvar() == 5
    foo.setvar(4)
    assert foo.getvar() == 4
    assert foo.var == 4
    foo.var = 3
    assert foo.var == 3
    

    然而,setter 实际上并不工作:

    foo.var = 4
    assert foo.var == foo._var # raises AssertionError
    

    foo._var 没有改变,您只是用新值覆盖了该属性。

    你也可以使用ClassProperty作为装饰器:

    class foo(object):
        _var = 5
    
        @ClassProperty
        @classmethod
        def var(cls):
            return cls._var
    
        @var.setter
        @classmethod
        def var(cls, value):
            cls._var = value
    
    assert foo.var == 5
    

    【讨论】:

    • 我认为 ClassProperty 的 setter 部分实际上并没有像描述的那样工作:虽然示例的断言都通过了,但最后 foo._var == 4 (而不是暗示的 3)。设置属性会破坏属性本身。当python-devit was pointed out that, while getters are trivial, setters are difficult (impossible?) without a metaclass讨论类属性时
    • @Gabriel 完全正确。我不敢相信两年来没有人指出这一点。
    • 我也不确定你为什么不只使用self.fget(owner) 并且完全不需要使用@classmethod? (这就是classmethod 所做的,通过中介将.__get__(instance, owner)(*args, **kwargs) 转换为function(owner, *args, **kwargs) 调用;属性不需要中介)。
    • 您的演示缺少任何在 getter 或 setter 中的实际转换,这将巧妙地证明您的 foo.var = 3 分配实际上并没有通过属性,而是简单地将foo 上的属性对象替换为整数。如果您在断言之间添加了assert isinstance(foo.__dict__['var'], ClassProperty) 调用,您会看到在执行foo.var = 3 后失败。
    • Python 类不支持在设置 类本身 时进行描述符绑定,仅在获取时才支持(所以 instance.attrinstance.attr = valuedel instance.attr 都将绑定在 type(instance) 上找到描述符,但在 classobj.attr 绑定时,classobj.attr = valuedel classobj.attr 执行 not 而是替换或删除描述符对象本身)。您需要一个元类来支持设置和删除(使类对象成为实例,元类成为类型)。
    【解决方案3】:

    我希望这个非常简单的只读 @classproperty 装饰器可以帮助寻找类属性的人。

    class classproperty(object):
    
        def __init__(self, fget):
            self.fget = fget
    
        def __get__(self, owner_self, owner_cls):
            return self.fget(owner_cls)
    
    class C(object):
    
        @classproperty
        def x(cls):
            return 1
    
    assert C.x == 1
    assert C().x == 1
    

    【讨论】:

    • 这适用于子类吗? (子类可以覆盖类属性吗?)
    • 嗯,是吗? class D(C): x = 2; assert D.x == 2
    • 我希望当我在.format 中使用它时,它可以工作,比如"{x}".format(**dict(self.__class__.__dict__, **self.__dict__)) :(
    • @Nathan 不仅...当您设置它时,您将覆盖所有x 访问10。我喜欢这种方法,因为它简洁明了,但听起来像是一种反模式
    • AttributeError,这只能阻止C().x = val,而不是C.x = val
    【解决方案4】:

    Python 3.9 2020 更新

    你可以一起使用它们:

    class G:
        @classmethod
        @property
        def __doc__(cls):
            return f'A doc for {cls.__name__!r}'
    
    

    顺序很重要 - 由于描述符的交互方式,@classmethod 必须位于顶部。

    https://docs.python.org/3.9/library/functions.html#classmethod

    【讨论】:

    • 看起来不适用于functools.cached_property
    • @Pycz 只是堆叠@classmethod @property @functools.cache 以获得相同的行为
    • 二传手呢?
    • mypy 0.910 不喜欢这样的属性。对于这段代码:variable = get_variable(FooBar.get_version) 它输出以下内容:main.py:36: error: Argument 1 to "get_variable" has incompatible type "Callable[[], str]"; expected "str" [arg-type]
    • @Vladoski this 已更改。在 3.9 中,@classmethod 实现已扩展为支持 @property 描述符。
    【解决方案5】:

    是否可以将 property() 函数与 classmethod 修饰函数一起使用?

    没有。

    但是,类方法只是类的绑定方法(部分函数),可从该类的实例访问。

    由于实例是类的函数,并且您可以从实例派生类,因此您可以使用 property 从类属性中获得您可能想要的任何所需行为:

    class Example(object):
        _class_property = None
        @property
        def class_property(self):
            return self._class_property
        @class_property.setter
        def class_property(self, value):
            type(self)._class_property = value
        @class_property.deleter
        def class_property(self):
            del type(self)._class_property
    

    此代码可用于测试 - 它应该可以通过而不会引发任何错误:

    ex1 = Example()
    ex2 = Example()
    ex1.class_property = None
    ex2.class_property = 'Example'
    assert ex1.class_property is ex2.class_property
    del ex2.class_property
    assert not hasattr(ex1, 'class_property')
    

    请注意,我们根本不需要元类 - 无论如何,您也不能通过其类的实例直接访问元类。

    编写 @classproperty 装饰器

    您实际上可以通过子类化property 在几行代码中创建一个classproperty 装饰器(它是用C 实现的,但您可以看到等效的Python here):

    class classproperty(property):
        def __get__(self, obj, objtype=None):
            return super(classproperty, self).__get__(objtype)
        def __set__(self, obj, value):
            super(classproperty, self).__set__(type(obj), value)
        def __delete__(self, obj):
            super(classproperty, self).__delete__(type(obj))
    

    然后将装饰器视为结合了属性的类方法:

    class Foo(object):
        _bar = 5
        @classproperty
        def bar(cls):
            """this is the bar attribute - each subclass of Foo gets its own.
            Lookups should follow the method resolution order.
            """
            return cls._bar
        @bar.setter
        def bar(cls, value):
            cls._bar = value
        @bar.deleter
        def bar(cls):
            del cls._bar
    

    并且这段代码应该可以正常工作:

    def main():
        f = Foo()
        print(f.bar)
        f.bar = 4
        print(f.bar)
        del f.bar
        try:
            f.bar
        except AttributeError:
            pass
        else:
            raise RuntimeError('f.bar must have worked - inconceivable!')
        help(f)  # includes the Foo.bar help.
        f.bar = 5
    
        class Bar(Foo):
            "a subclass of Foo, nothing more"
        help(Bar) # includes the Foo.bar help!
        b = Bar()
        b.bar = 'baz'
        print(b.bar) # prints baz
        del b.bar
        print(b.bar) # prints 5 - looked up from Foo!
    
        
    if __name__ == '__main__':
        main()
    

    但我不确定这样做是否明智。旧的邮件列表 article 表明它不应该工作。

    让属性在类上工作:

    上面的缺点是“类属性”不能从类中访问,因为它只会覆盖类__dict__的数据描述符。

    但是,我们可以使用元类__dict__ 中定义的属性来覆盖它。例如:

    class MetaWithFooClassProperty(type):
        @property
        def foo(cls):
            """The foo property is a function of the class -
            in this case, the trivial case of the identity function.
            """
            return cls
    

    然后元类的类实例可以有一个属性,该属性使用前面部分已经演示的原理访问类的属性:

    class FooClassProperty(metaclass=MetaWithFooClassProperty):
        @property
        def foo(self):
            """access the class's property"""
            return type(self).foo
    

    现在我们看到了两个实例

    >>> FooClassProperty().foo
    <class '__main__.FooClassProperty'>
    

    和班级

    >>> FooClassProperty.foo
    <class '__main__.FooClassProperty'>
    

    有权访问类属性。

    【讨论】:

      【解决方案6】:

      Python 3!

      [更新:请参阅 @Amit Portnoy's answer 以了解版本 >= 3.9 中更简洁的方法]

      老问题,很多观点,非常需要一种真正的 Python 3 方式。

      幸运的是,metaclass kwarg 很容易:

      class FooProperties(type):
          
          @property
          def var(cls):
              return cls._var
      
      class Foo(object, metaclass=FooProperties):
          _var = 'FOO!'
      

      那么,&gt;&gt;&gt; Foo.var

      '喂!'

      【讨论】:

      • 也就是说没有简单的开箱即用的方法
      • @mehmet 这不简单吗? Foo 是它的元类的一个实例,@property 可以用于它的方法,就像它可以用于Foo 的实例一样。
      • 您必须为一个类定义另一个类,假设元类不可重用,这将是复杂度的两倍。
      • 类方法适用于类和实例。此属性仅适用于类。我不认为这是要求的。
      • @AaronHall 如果这很重要,可以轻松添加到Foo.__new__。尽管此时可能值得使用 getattribute 代替,或者质疑假装语言功能是否真的是您想要采取的方法。
      【解决方案7】:

      没有合理的方法可以使这个“类属性”系统在 Python 中工作。

      这是使其工作的一种不合理的方法。随着元类魔法数量的增加,您当然可以使其更加无缝。

      class ClassProperty(object):
          def __init__(self, getter, setter):
              self.getter = getter
              self.setter = setter
          def __get__(self, cls, owner):
              return getattr(cls, self.getter)()
          def __set__(self, cls, value):
              getattr(cls, self.setter)(value)
      
      class MetaFoo(type):
          var = ClassProperty('getvar', 'setvar')
      
      class Foo(object):
          __metaclass__ = MetaFoo
          _var = 5
          @classmethod
          def getvar(cls):
              print "Getting var =", cls._var
              return cls._var
          @classmethod
          def setvar(cls, value):
              print "Setting var =", value
              cls._var = value
      
      x = Foo.var
      print "Foo.var = ", x
      Foo.var = 42
      x = Foo.var
      print "Foo.var = ", x
      

      问题的关键在于属性是 Python 所说的“描述符”。没有简明扼要的方法来解释这种元编程是如何工作的,所以我必须将您指向descriptor howto

      如果你正在实现一个相当高级的框架,你只需要了解这类事情。就像一个透明的对象持久化或 RPC 系统,或一种特定领域的语言。

      但是,在对先前答案的评论中,您说您

      需要修改一个类的所有实例都可以看到的属性,并且在调用这些类方法的范围内没有对类的所有实例的引用。

      在我看来,您真正想要的是Observer 设计模式。

      【讨论】:

      • 我喜欢代码示例的想法,但在实践中似乎有点笨拙。
      • 我想要完成的是非常简单的设置和获取单个属性,该属性用作修改所有实例行为的标志,所以我认为 Observer 对我来说会被夸大了试图做。如果有多个属性有问题,那么我会更倾向于。
      • 似乎只是将函数公开并直接调用它们是最简单的解决方案。我很好奇我做错了什么,或者我试图做的事情是不可能的。顺便说一下,很抱歉有多个 cmet。 300 个字符的限制很糟糕。
      • 代码示例的妙处在于,您可以一次实现所有笨重的位,然后继承它们。只需将 _var 移动到派生类中。类 D1(Foo): _var = 21 类 D2(Foo) _var = "你好" D1.var 21 D2.var 你好
      【解决方案8】:

      如果您想通过实例化对象访问类属性,则仅在元类上设置它没有帮助,在这种情况下,您还需要在对象上安装一个普通属性(它调度到类属性) .我认为以下内容更清楚:

      #!/usr/bin/python
      
      class classproperty(property):
          def __get__(self, obj, type_):
              return self.fget.__get__(None, type_)()
      
          def __set__(self, obj, value):
              cls = type(obj)
              return self.fset.__get__(None, cls)(value)
      
      class A (object):
      
          _foo = 1
      
          @classproperty
          @classmethod
          def foo(cls):
              return cls._foo
      
          @foo.setter
          @classmethod
          def foo(cls, value):
              cls.foo = value
      
      a = A()
      
      print a.foo
      
      b = A()
      
      print b.foo
      
      b.foo = 5
      
      print a.foo
      
      A.foo = 10
      
      print b.foo
      
      print A.foo
      

      【讨论】:

        【解决方案9】:

        解决了一半,类上的 __set__ 仍然不起作用。解决方案是实现属性和静态方法的自定义属性类

        class ClassProperty(object):
            def __init__(self, fget, fset):
                self.fget = fget
                self.fset = fset
        
            def __get__(self, instance, owner):
                return self.fget()
        
            def __set__(self, instance, value):
                self.fset(value)
        
        class Foo(object):
            _bar = 1
            def get_bar():
                print 'getting'
                return Foo._bar
        
            def set_bar(value):
                print 'setting'
                Foo._bar = value
        
            bar = ClassProperty(get_bar, set_bar)
        
        f = Foo()
        #__get__ works
        f.bar
        Foo.bar
        
        f.bar = 2
        Foo.bar = 3 #__set__ does not
        

        【讨论】:

          【解决方案10】:

          因为我需要修改一个属性,该属性被类的所有实例都看到,并且在调用这些类方法的范围内没有对类的所有实例的引用。

          您是否有权访问该类的至少一个实例?我可以想办法做到这一点:

          class MyClass (object):
              __var = None
          
              def _set_var (self, value):
                  type (self).__var = value
          
              def _get_var (self):
                  return self.__var
          
              var = property (_get_var, _set_var)
          
          a = MyClass ()
          b = MyClass ()
          a.var = "foo"
          print b.var
          

          【讨论】:

            【解决方案11】:

            试一试,无需更改/添加大量现有代码即可完成工作。

            >>> class foo(object):
            ...     _var = 5
            ...     def getvar(cls):
            ...         return cls._var
            ...     getvar = classmethod(getvar)
            ...     def setvar(cls, value):
            ...         cls._var = value
            ...     setvar = classmethod(setvar)
            ...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
            ...
            >>> f = foo()
            >>> f.var
            5
            >>> f.var = 3
            >>> f.var
            3
            

            property 函数需要两个 callable 参数。给他们 lambda 包装器(它将实例作为第一个参数传递),一切都很好。

            【讨论】:

            • 正如 Florian Bösch 所指出的,(第三方库或遗留代码)所需的语法是 foo.var。
            【解决方案12】:

            这是一个解决方案,它既适用于通过类进行访问,也适用于通过使用元类的实例进行访问。

            In [1]: class ClassPropertyMeta(type):
               ...:     @property
               ...:     def prop(cls):
               ...:         return cls._prop
               ...:     def __new__(cls, name, parents, dct):
               ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
               ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
               ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
               ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
               ...:
            
            In [2]: class ClassProperty(object):
               ...:     __metaclass__ = ClassPropertyMeta
               ...:     _prop = 42
               ...:     def __getattr__(self, attr):
               ...:         raise Exception('Never gets called')
               ...:
            
            In [3]: ClassProperty.prop
            Out[3]: 42
            
            In [4]: ClassProperty.prop = 1
            ---------------------------------------------------------------------------
            AttributeError                            Traceback (most recent call last)
            <ipython-input-4-e2e8b423818a> in <module>()
            ----> 1 ClassProperty.prop = 1
            
            AttributeError: can't set attribute
            
            In [5]: cp = ClassProperty()
            
            In [6]: cp.prop
            Out[6]: 42
            
            In [7]: cp.prop = 1
            ---------------------------------------------------------------------------
            AttributeError                            Traceback (most recent call last)
            <ipython-input-7-e8284a3ee950> in <module>()
            ----> 1 cp.prop = 1
            
            <ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
                  6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
                  7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
            ----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
                  9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
            
            AttributeError: can't set attribute
            

            这也适用于元类中定义的设置器。

            【讨论】:

              【解决方案13】:

              我找到了一个干净的解决方案来解决这个问题。这是一个名为 classutilities (pip install classutilities) 的包,请参阅文档 here on PyPi

              考虑例子:

              import classutilities
              
              class SomeClass(classutilities.ClassPropertiesMixin):
                  _some_variable = 8  # Some encapsulated class variable
              
                  @classutilities.classproperty
                  def some_variable(cls):  # class property getter
                      return cls._some_variable
              
                  @some_variable.setter
                  def some_variable(cls, value):  # class property setter
                      cls._some_variable = value
              

              您可以在类级别和实例级别使用它:

              # Getter on class level:
              value = SomeClass.some_variable
              print(value)  # >>> 8
              # Getter on instance level
              inst = SomeClass()
              value = inst.some_variable
              print(value)  # >>> 8
              
              # Setter on class level:
              new_value = 9
              SomeClass.some_variable = new_value
              print(SomeClass.some_variable)   # >>> 9
              print(SomeClass._some_variable)  # >>> 9
              # Setter on instance level
              inst = SomeClass()
              inst.some_variable = new_value
              print(SomeClass.some_variable)   # >>> 9
              print(SomeClass._some_variable)  # >>> 9
              print(inst.some_variable)        # >>> 9
              print(inst._some_variable)       # >>> 9
              

              如您所见,它在所有情况下都能正常工作。

              【讨论】:

                【解决方案14】:

                基于https://stackoverflow.com/a/1800999/2290820

                
                class MetaProperty(type):
                
                    def __init__(cls, *args, **kwargs):
                        super()
                
                    @property
                    def praparty(cls):
                        return cls._var
                
                    @praparty.setter
                    def praparty(cls, val):
                        cls._var = val
                
                
                class A(metaclass=MetaProperty):
                    _var = 5
                
                
                print(A.praparty)
                A.praparty = 6
                print(A.praparty)
                

                【讨论】:

                  【解决方案15】:

                  搜索了不同的地方后,我找到了一个定义类属性的方法 适用于 Python 2 和 3。

                  from future.utils import with_metaclass
                  
                  class BuilderMetaClass(type):
                      @property
                      def load_namespaces(self):
                          return (self.__sourcepath__)
                  
                  class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
                      __sourcepath__ = 'sp'        
                  
                  print(BuilderMixin.load_namespaces)
                  

                  希望这可以帮助某人:)

                  【讨论】:

                  【解决方案16】:

                  对于 Python 3.9 之前的函数式方法,您可以使用:

                  def classproperty(fget):
                    return type(
                        'classproperty',
                        (),
                        {'__get__': lambda self, _, cls: fget(cls), '__module__': None}
                    )()
                    
                  class Item:
                    a = 47
                  
                    @classproperty
                    def x(cls):
                      return cls.a
                  
                  Item.x
                  

                  【讨论】:

                    【解决方案17】:

                    这是我也缓存类属性的解决方案

                    class class_property(object):
                        # this caches the result of the function call for fn with cls input
                        # use this as a decorator on function methods that you want converted
                        # into cached properties
                    
                        def __init__(self, fn):
                            self._fn_name = fn.__name__
                            if not isinstance(fn, (classmethod, staticmethod)):
                                fn = classmethod(fn)
                            self._fn = fn
                    
                        def __get__(self, obj, cls=None):
                            if cls is None:
                                cls = type(obj)
                            if (
                                self._fn_name in vars(cls) and
                                type(vars(cls)[self._fn_name]).__name__ != "class_property"
                            ):
                                return vars(cls)[self._fn_name]
                            else:
                                value = self._fn.__get__(obj, cls)()
                                setattr(cls, self._fn_name, value)
                                return value
                    

                    【讨论】:

                      【解决方案18】:

                      这是我的建议。不要使用类方法。

                      说真的。

                      在这种情况下使用类方法的原因是什么?为什么没有普通类的普通对象?


                      如果您只是想更改值,那么属性并不是很有帮助,不是吗?只需设置属性值即可。

                      只有在需要隐藏某些内容时才应使用属性——这些内容在未来的实现中可能会发生变化。

                      也许您的示例被简化了,并且您遗漏了一些地狱般的计算。但它看起来并没有增加显着的价值。

                      受 Java 影响的“隐私”技术(在 Python 中,以 _ 开头的属性名称)并不是很有帮助。从谁私下?当您拥有源代码时(就像在 Python 中所做的那样),私有的意义有点模糊。

                      受 Java 影响的 EJB 样式的 getter 和 setter(通常在 Python 中作为属性完成)用于促进 Java 的原始内省以及通过静态语言编译器的集合。所有这些 getter 和 setter 在 Python 中都没有那么有用。

                      【讨论】:

                      • 因为我需要修改一个属性,该属性的所有实例都可以看到,并且在调用这些类方法的范围内没有对所有实例的引用类。
                      猜你喜欢
                      • 2014-02-07
                      • 2011-03-19
                      • 2023-03-23
                      • 1970-01-01
                      • 2011-06-22
                      相关资源
                      最近更新 更多