Python 使用类级原语的正确方法

Python 使用类级原语的正确方法,python,Python,Python中类变量的处理方式对我来说毫无意义。类变量的范围似乎取决于它的类型!基本类型被视为实例变量,复杂类型被视为类变量: >>> class A(object): ... my_class_primitive = True ... my_class_object = ['foo'] ... >>> a = A() >>> a.my_class_primitive, a.my_class_object (True, ['foo'

Python中类变量的处理方式对我来说毫无意义。类变量的范围似乎取决于它的类型!基本类型被视为实例变量,复杂类型被视为类变量:

>>> class A(object):
...   my_class_primitive = True
...   my_class_object = ['foo']
... 
>>> a = A()
>>> a.my_class_primitive, a.my_class_object
(True, ['foo'])
>>> b = A()
>>> b.my_class_primitive, b.my_class_object
(True, ['foo'])
>>> a.my_class_object.append('bar')
>>> b.my_class_primitive, b.my_class_object
(True, ['foo', 'bar'])
>>> a.my_class_primitive = False
>>> b.my_class_primitive, b.my_class_object
(True, ['foo', 'bar'])
>>> a.my_class_primitive, a.my_class_object
(False, ['foo', 'bar'])
请有人解释一下:

  • 为什么会有这种功能?背后的逻辑是什么
  • 如果我想使用基元类型(例如bool)作为类变量,我该如何做

  • 该特性作为Python类定义的缓存形式存在

    类定义本身中定义的属性被视为类的
    静态属性。e、 g.不应修改它们


    我敢肯定,这个决定是在假设您在修改静态属性方面遵循最佳实践的情况下做出的;)

    该功能作为Python类定义的缓存形式存在

    类定义本身中定义的属性被视为类的
    静态属性。e、 g.不应修改它们


    我敢肯定,这个决定是在假设您在修改静态属性方面遵循最佳实践的情况下做出的;)

    您应该做的适当比较是:

    >>> class A(object):
        my_class_primitive = True
        my_class_object = ['foo']
    
    
    >>> a = A()
    >>> b = A()
    >>> a.my_class_primitive = False
    >>> a.my_class_object = ['bar']
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    这不是你认为你看到的。这种“奇怪”的行为是由可变性的概念引起的。也就是说,您正在更改分配给
    my_class_object
    属性的对象,同时将不同的对象分配给
    my_class_primitive
    。在第一种情况下,它适用于所有实例(因为这是一个对象),而在第二种情况下,它适用于单个实例(您正在更改其属性)


    你不是唯一一个陷入这种困惑的人。要查看可变性如何影响代码的另一个示例,您可以选中此项:

    您应该进行的适当比较如下:

    >>> class A(object):
        my_class_primitive = True
        my_class_object = ['foo']
    
    
    >>> a = A()
    >>> b = A()
    >>> a.my_class_primitive = False
    >>> a.my_class_object = ['bar']
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    这不是你认为你看到的。这种“奇怪”的行为是由可变性的概念引起的。也就是说,您正在更改分配给
    my_class_object
    属性的对象,同时将不同的对象分配给
    my_class_primitive
    。在第一种情况下,它适用于所有实例(因为这是一个对象),而在第二种情况下,它适用于单个实例(您正在更改其属性)

    你不是唯一一个陷入这种困惑的人。要查看可变性如何影响代码的另一个示例,可以检查以下内容:

    类属性存储在
    A中

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    
    因此
    b.my_class_object
    也会受到影响:

    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo', 'bar'])
    
    赋值
    a.my\u class\u primitive=False
    a
    添加一个新的实例属性。它将一个键值对放在
    a.\uuu dict\uuu
    中:

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    
    因此
    b
    不受影响:

    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo', 'bar'])
    
    使
    a.my\u class\u原语
    返回在
    a.中找到的键的值。而不是在
    a.中找到的键的值

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    
    类属性存储在
    A中

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    
    因此
    b.my_class_object
    也会受到影响:

    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo', 'bar'])
    
    赋值
    a.my\u class\u primitive=False
    a
    添加一个新的实例属性。它将一个键值对放在
    a.\uuu dict\uuu
    中:

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    
    因此
    b
    不受影响:

    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo', 'bar'])
    
    使
    a.my\u class\u原语
    返回在
    a.中找到的键的值。而不是在
    a.中找到的键的值

    >>> A.__dict__
    >>> <dictproxy {'__dict__': <attribute '__dict__' of 'A' objects>,
     '__doc__': None,
     '__module__': '__main__',
     '__weakref__': <attribute '__weakref__' of 'A' objects>,
     'my_class_object': ['foo'],
     'my_class_primitive': True}>
    
    >>> a = A()
    >>> a.my_class_primitive, a.my_class_object
    (True, ['foo'])
    >>> b = A()
    >>> b.my_class_primitive, b.my_class_object
    (True, ['foo'])
    
    >>> a.my_class_primitive = False
    
    >>> a.__dict__
    >>> {'my_class_primitive': False}
    
    >>> a.my_class_primitive, a.my_class_object
    (False, ['foo', 'bar'])
    

    这与原始和复杂无关。当附加到
    a.my_class_对象
    时,修改现有对象。分配给变量时,不会对其进行修改。如果您像对待布尔值一样对待列表,则列表也存在同样的“问题”:

    >>> class Foo(object):
    ...     x = []
    ...
    >>> i1 = Foo()
    >>> i2 = Foo()
    >>>
    >>> i1.x = 5
    >>>
    >>> print(i2.x)
    []
    
    当您获得
    i1.x
    时,Python将查看属性的
    i1.\uuuu dict\uuuu
    。如果在那里找不到它,它会在该对象的每个父类的
    \uuu dict\uuu
    中查找,直到找到为止(或抛出
    AttributeError
    )。返回的对象根本不必是
    i1
    的属性

    当您指定给
    i1.x
    时,您专门指定给
    i1.x

    要修改类属性,请参考类,而不是实例:

    >>> class Foo(object):
    ...     x = 2
    ...
    >>> i1 = Foo()
    >>>
    >>> Foo.x = 5
    >>>
    >>> print(i1.x)
    5
    

    这与原始和复杂无关。当附加到
    a.my_class_对象
    时,修改现有对象。分配给变量时,不会对其进行修改。如果您像对待布尔值一样对待列表,则列表也存在同样的“问题”:

    >>> class Foo(object):
    ...     x = []
    ...
    >>> i1 = Foo()
    >>> i2 = Foo()
    >>>
    >>> i1.x = 5
    >>>
    >>> print(i2.x)
    []
    
    当您获得
    i1.x
    时,Python将查看属性的
    i1.\uuuu dict\uuuu
    。如果在那里找不到它,它会在该对象的每个父类的
    \uuu dict\uuu
    中查找,直到找到为止(或抛出
    AttributeError
    )。返回的对象根本不必是
    i1
    的属性

    当您指定给
    i1.x
    时,您专门指定给
    i1.x

    要修改类属性,请参考类,而不是实例:

    >>> class Foo(object):
    ...     x = 2
    ...
    >>> i1 = Foo()
    >>>
    >>> Foo.x = 5
    >>>
    >>> print(i1.x)
    5
    

    区别不在于基本类型和复杂类型之间,而在于赋值和修改变量之间

    如果使用
    instance.name=value
    ,则始终会分配新的实例变量,即使已经存在同名的类属性

    例如:

    >>> class A(object):
    ...   my_class_primitive = True
    ...   my_class_object = ['foo']
    ...
    >>> a = A()
    >>> a.my_class_primitive = False
    >>> a.__class__.my_class_primitive
    True
    >>> a.__dict__
    {'my_class_primitive': False}
    
    >>> a.my_class_object is a.__class__.my_class_object
    True
    
    在这里,添加到列表的行为不同之处在于,当您在类实例上执行属性查找时,它将首先查找实例变量,如果没有具有该名称的实例变量,它将查找类属性。例如:

    >>> class A(object):
    ...   my_class_primitive = True
    ...   my_class_object = ['foo']
    ...
    >>> a = A()
    >>> a.my_class_primitive = False
    >>> a.__class__.my_class_primitive
    True
    >>> a.__dict__
    {'my_class_primitive': False}
    
    >>> a.my_class_object is a.__class__.my_class_object
    True
    

    因此,当您执行
    a.my\u class\u object.append(x)
    时,您正在修改任何实例都可以访问的class属性。如果要执行a.my_class_object=x
    ,则它不会以任何方式修改class属性,它只会创建一个新的实例变量。

    原语和