Поиск по блогу

вторник, 11 ноября 2014 г.

Инструкция "class" в Python - это не объявления, ...class создает объект и является неявной инструкцией присваивания (конспект гл. 28)

...в отличие от инструкции в C++, в языке Python она не является объявлением. Подобно инструкции def, инструкция class создает объект и является неявной инструкцией присваивания – когда она выполняется, создается объект класса, ссылка на который сохраняется в имени, использованном в заголовке инструкции.

Когда в области видимости создается объект класса?

Кроме того, как и инструкция def, инструкция class является настоящим выполняемым программным кодом – класс не существует, пока поток выполнения не достигнет инструкции class, которая определяет его (обычно при импортировании модуля, в котором она находится, но не ранее).

Здесь можно было бы импортировать какой-нибудь модуль и распечатать его атрибуты командой dir..., но сейчас я думаю о том, что понимаю, почему принято использовать instances ... но как соотносятся (взаимодействуют) пространства имен класса и пространство имен экземпляра(ов)?

...функция с именем init, если она определена, вызывается во время создания объекта экземпляра (770).

Так как же инструкция class порождает пространство имен?

А вот как. Так же как и в модулях, инструкции, вложенные в тело инструкции class, создают атрибуты класса. Когда интерпретатор достигает инструкции class (а не тогда, когда происходит вызов класса), он выполняет все инструкции в ее теле от начала и до конца.

Все присваивания, которые производятся в ходе этого процесса, создают имена в локальной области видимости класса, которые становятся атрибутами объекта класса. Благодаря этому классы напоминают модули и функции:

In []:
•• Подобно функциям, инструкции class являются локальными областями
видимости, где располагаются имена, созданные вложенными операциями
присваивания.
•• Подобно именам в модуле, имена, созданные внутри инструкции class, ста-
новятся атрибутами объекта класса.

Основное отличие классов состоит в том, что их пространства имен также составляют основу механизма наследования в языке Python, – ссылки на атрибуты, отсутствующие в классе или в объекте экземпляра, будут получены из других классов.

Все инструкции внутри инструкции class выполняются, когда выполняется сама инструкция class (а не когда позднее класс вызывается для создания экземпляра).

In []:
 
In [3]:
class SharedData:
    spam = 42
In [4]:
>>> x = SharedData() # Создать два экземпляра
>>> y = SharedData()
>>> x.spam, y.spam # Они наследуют и совместно используют атрибут spam
#(42, 42)
Out[4]:
(42, 42)
In [5]:
>>> SharedData.spam = 99
>>> x.spam, y.spam, SharedData.spam
Out[5]:
(99, 99, 99)

*Здесь мы обращаемся к объекту класса, а не к экземпляру... Оба экземпляра не находят атрибута spam в своих пространствах имен, начинаю искать (и находят) в пространстве имен родителя(ей)...

Почему я вернулся к этой "очевидной теме"? Потому, что разбирал чужой код (Scrapy doc 7.5.1 Using Item Exporters), в котором использовался метод класса: *

In []:
@classmethod
def from_crawler(cls, crawler):
pipeline = cls()
crawler.signals.connect(pipeline.spider_opened, signals.spider_opened)
crawler.signals.connect(pipeline.spider_closed, signals.spider_closed)
return pipeline

здесь переменной pipeline присваивается имя (объекта) класса. При появлении сигнала (наступлении события) signals.spider_opened вызывается метода pipeline.spider_opened

In []:
def spider_opened(self, spider):
file = open(%s_products.xml % spider.name, w+b)
self.files[spider] = file
self.exporter = XmlItemExporter(file)
self.exporter.start_exporting()

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

Вот пример использование одного имени атрибута 'data' в разных пространствах имен

In [6]:
class MixedNames: # Определение класса
    data = 'spam' # Присваивание атрибуту класса
    def __init__(self, value): # Присваивание имени метода
        self.data = value # Присваивание атрибуту экземпляра
    def display(self):
        print(self.data, MixedNames.data) # Атрибут экземпляра, атрибут класса
In [7]:
>>> x = MixedNames(1)        # Создаются два объекта экземпляров,
>>> y = MixedNames(2)        # каждый из которых имеет свой атрибут data
>>> x.display(); y.display() # self.data - это другие атрибуты,
                             # а MixedNames.data - тот же самый
(1, 'spam')
(2, 'spam')

Несмотря на то что операция поиска в дереве наследования позволяет отыскивать имена, мы всегда можем получить доступ к ним в любой точке дерева, обратившись непосредственно к нужному объекту

обратим внимание, что функция с именем init, если она определена, вызывается во время созда- ния объекта экземпляра, а не класса



Посты чуть ниже также могут вас заинтересовать

Комментариев нет:

Отправить комментарий