Разница между доступом к атрибуту экземпляра и атрибуту класса - PullRequest
3 голосов
/ 20 августа 2009

У меня есть класс Python

class pytest:
    i = 34
    def func(self):
        return "hello world"

Когда я получаю доступ к pytest.i, я получаю 34. Я также могу сделать это другим способом:

a = pytest()
a.i

Это также дает 34.

Если я пытаюсь получить доступ к (несуществующему) pytest.j, я получаю

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
pytest.j
AttributeError: class pytest has no attribute 'j'

пока я пытаюсь a.j, ошибка

Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
a.j
AttributeError: pytest instance has no attribute 'j'

Итак, мой вопрос: что именно происходит в двух случаях и в чем разница?

Ответы [ 2 ]

7 голосов
/ 20 августа 2009

Нет, это две разные вещи.

В Python все является объектом. Классы - это объекты, функции - это объекты, а экземпляры - это объекты. Поскольку все является объектом, все ведет себя аналогичным образом. В вашем случае вы создаете экземпляр класса (== объект с типом «Class») с именем «pytest». Этот объект имеет два атрибута: i и fuc. i является экземпляром "Integer" или "Number", fuc является экземпляром "Function".

Когда вы используете "pytest.j", вы говорите python "искать объект pytest, а когда он у вас есть, искать i". «pytest» является экземпляром класса, но это не имеет значения.

Когда вы создаете экземпляр «pytest» (== объект с типом «pytest»), то у вас есть объект, который имеет «значения по умолчанию». В вашем случае a является экземпляром pytest, что означает, что все, что не может быть найдено в a, будет найдено в pytest, затем.

То есть a.j означает: «Посмотрите на a. Когда его нет, посмотрите также на pytest». Но j не существует, и теперь Python должен дать вам значимое сообщение об ошибке. Можно сказать, что «у класса pytest нет атрибута« j »». Это было бы правильно, но бессмысленно: вам нужно было бы понять, что вы пытались получить доступ к j через a. Это было бы сбивающим с толку. У Гвидо этого не будет.

Следовательно, python использует другое сообщение об ошибке. Поскольку у него не всегда есть имя экземпляра (a), разработчики решили использовать тип вместо этого, поэтому вы получите «экземпляр pytest ...».

0 голосов
/ 20 августа 2009

Подводя итог, можно выделить два типа переменных, связанных с классами и объектами: переменные класса и переменные экземпляра. Переменные класса связаны с классами, но переменные экземпляра связаны с объектами. Вот пример:

class TestClass:
    classVar = 0
    def __init__(self):
        self.instanceVar = 0

classVar - это переменная класса, связанная с классом TestClass. instanceVar - это переменная экземпляра, связанная с объектами типа TestClass.

print(TestClass.classVar) # prints 0
instance1 = TestClass() # creates new instance of TestClass
instance2 = TestClass() # creates another new instance of TestClass

instance1 и instance2 совместно используют classVar, поскольку они оба являются объектами типа TestClass.

print(instance1.classVar) # prints 0
TestClass.classVar = 1
print(instance1.classVar) # prints 1
print(instance2.classVar) # prints 1

Однако у них обоих есть копии instanceVar, потому что это переменная экземпляра, связанная с отдельными экземплярами, а не с классом.

print(instance1.instanceVar) # prints 0
print(TestClass.instanceVar) # error! instanceVar is not a class variable
instance1.instanceVar = 1
print(instance1.instanceVar) # prints 1
print(instance2.instanceVar) # prints 0

Как сказал Аарон, если вы пытаетесь получить доступ к переменной экземпляра, Python сначала проверяет переменные экземпляра этого объекта, а затем переменные класса этого типа. Переменные класса функционируют как значения по умолчанию для переменных экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...