python类实例变量和类变量

时间:2012-01-02 13:38:21

标签: python class variables instance

我在理解类/实例变量在Python中的工作方式时遇到了问题。我不明白为什么当我尝试这个代码时,list变量似乎是一个类变量

class testClass():
    list = []
    def __init__(self):
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

输出:

['thing']
['thing', 'thing']

当我这样做时,它似乎是一个实例变量

class testClass():
    def __init__(self):
        self.list = []
        self.list.append('thing')

p = testClass()
print p.list

f = testClass()
print f.list

输出:

['thing']
['thing']

4 个答案:

答案 0 :(得分:44)

这是因为Python使用.解析名称的方式。当您编写self.list时,Python运行时首先尝试通过在实例对象中查找它来解析list名称,如果在那里找不到它,那么在类实例中。

让我们一步一步地研究它

self.list.append(1)
  1. 对象list中是否有self个名称?
    • 是的:使用它!完成。
    • 否:转到2。
  2. 对象list的类实例中是否有self个名称?
    • 是的:使用它!完成
    • 否:错误!
  3. 但是当你绑定一个名字时,事情会有所不同:

    self.list = []
    
    1. 对象list中是否有self个名称?
      • 是:覆盖它!
      • 不:绑定它!
    2. 所以,这总是一个实例变量。

      您的第一个示例在类实例中创建了一个list,因为这是当时的活动范围(任何地方都没有self)。但是,您的第二个示例在list范围内明确创建了self

      更有趣的是例子:

      class testClass():
          list = ['foo']
          def __init__(self):
              self.list = []
              self.list.append('thing')
      
      x = testClass()
      print x.list
      print testClass.list
      del x.list
      print x.list
      

      那将打印:

      ['thing']
      ['foo']
      ['foo']
      

      当您删除实例名称时,通过self引用可以看到类名。

答案 1 :(得分:5)

Python有关于查找名称的有趣规则。如果您真的想弯曲,请尝试以下代码:

class testClass():
    l = []
    def __init__(self):
        self.l = ['fred']

这将为每个实例提供一个名为l的变量,用于屏蔽类变量l。如果你self.__class__.l,你仍然可以获得类变量。

我想到的方式就是这样......每当你做instance.variable时(即使对于方法名称,它们只是变量的值恰好是函数)它会在实例的字典中查找它。如果它找不到它,它会尝试在实例的类字典中查找它。这仅在变量被“读取”时才有效。如果它被分配给它,它总是在实例字典中创建一个新条目。

答案 2 :(得分:3)

在第一个示例中,list是类的一个属性,由它的所有实例共享。这意味着您甚至可以在不具有testClass类型的对象的情况下访问它:

>>> class testClass():
...     list = []
...     def __init__(self):
...             self.list.append("thing")
... 
>>> testClass.list
[]
>>> testClass.list.append(1)
>>> testClass.list
[1]

但是所有对象与该类共享list属性并相互共享:

>>> testObject = testClass()
>>> testObject.list
[1, 'thing']
>>> testClass.list
[1, 'thing']
>>> 
>>> testObject2 = testClass()
>>> testClass.list
[1, 'thing', 'thing']
>>> testObject2.list
[1, 'thing', 'thing']

答案 3 :(得分:0)

实例化类时,会自动执行__init__方法。

在第一种情况下,您的列表是一个类属性,并由其所有实例共享。你得到了两件事,因为你在p瞬时附加了一个,而在实例化f时附加了另一个(第一个已经在第一次调用时附加了第一个)。