Как python обрабатывает атрибут в классе? Всегда ли нужно инициализировать их в методе __init__? - PullRequest
0 голосов
/ 22 апреля 2020

Я читаю Python 3 объектно-ориентированных книги. И запутаться в коде ниже. Класс в приведенном ниже коде не имеет метода __init__, так как большая часть учебника, который я искал, внезапно self.student появляется в уроке метода.

class IntroToPython:
    def lesson(self):
        return f""" 
        Hello {self.student}. define two variables,
        an integer named a with value 1 and a string named b with value 'hello
        """

    def check(self, d):
        return code == "a = 1\nb = 'hello'"

Я все еще могу назначить значение для self.student, и оно все еще работаю, как ревет. Класс ищет и распределяет все свои атрибуты, когда создает объект без __init__ метода?

b= IntroToPython()
b.student = "John"

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

__init__() - это просто метод, который вызывается при инициализации объекта. В Python память объекта не фиксируется во время инициализации. Объект Python сильно отличается от объекта C ++ или Java. Объект Python можно рассматривать как более близкий к пространству имен в Python, что позволяет вам содержать в нем коллекцию членов (функций и значений). Эта коллекция может быть легко расширена в Python в любой момент времени жизни объекта. Объект не содержит этих членов сам по себе, он просто поддерживает ссылки на них.

Когда вы пишете {obj}.{name} = {some_val}, Python проверяет, имеет ли объект атрибут {name}. Если это так, атрибуту присваивается значение {some_val}, в противном случае Python добавляет имя {name} в пространство имен объекта и инициализирует его как {some_val}. Обратите внимание, что Python не нужно создавать дополнительное пространство для name в объекте, он просто должен отслеживать новую переменную name, которая была введена в пространство имен (я описал, как это происходит позже) , Это связано с тем, что модель данных Python основана на именах, что отличается от языков, подобных C ++. Пространство для name выделено в другом месте, name - это просто ссылка на этот объект.

На самом деле вы можете увидеть, что это происходит под капотом, используя функцию dir(). Для каждого объекта в Python, Python поддерживает атрибут __dir__, который представляет собой список всех имен, присутствующих в области действия объекта. Это включает в себя имена переменных и имена функций.

Итак, в вашем случае, если вы позвоните dir(b) до b.student = "John", вы получите следующее:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'check', 'lesson']

Обратите внимание, что это включает много более сложных методов, наряду с методами check и lesson, которые вы определили.

После запуска b.student = "John" мы получим

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'check', 'lesson', 'student']

Обратите внимание, как называется student был добавлен в пространство имен b в конце списка.

Итак, {x}.{y}={something} - это простой способ, которым имя y можно добавить в пространство имен x. Зная это, можно увидеть, что функции __init__() не являются специальными. Они делают то же самое, просто __init__() вызывается всякий раз, когда инициализируется объект.

Еще одна интересная вещь, которую следует отметить, это то, что все в Python является объектом (классы и функции также объекты!); так что совершенно нормально написать что-то вроде:

>>> def f():
    f.ctr += 1 #f.ctr stores number of times f has been called
    #do something

>>> f.ctr = 0
>>> f()
>>> f()
>>> f()
>>> f.ctr
3
1 голос
/ 22 апреля 2020

Вы можете добавить произвольные атрибуты к экземпляру класса, как показано выше, но в целом это, вероятно, не очень хорошая идея. В этом случае только объект b будет иметь атрибут student; все остальные члены класса и само определение класса остаются неизменными. Например, не имеет значения, что вы ссылаетесь на self.student в методе lesson(); Вы можете определить атрибут b.whatever где хотите. Это быстро запутается, хотя.

Лучше express атрибутов и методов, которые вы хотите получить в классе, в самом определении класса, либо в методе __init__(), либо в более поздних методах 'getter' и 'setter', чтобы избежать путаницы с точечной нотацией и включением тихих ошибок, но это вопрос кодирования, а не python исполнения.

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