Анимация
JavaScript
|
Главная Библионтека спрятать детали реализации и при необходимости полностью контролировать доступ. Обычно первый аргумент в определении метода называют self. Это не более чем соглашение: имя self не имеет абсолютно никакого специального значения. Однако, следуя этому соглашению, Вы делаете код более понятным для других программистов. (Некоторые программы, например программы просмотра классов, рассчитаны на то, что пользователь всегда следует этому соглашению.) Любой объект-функция, являющийся атрибутом класса, определяет метод экземпляров этого класса. Совсем не обязательно, чтобы определение функции находилось в определении класса: присваивание объекта-функции локальной переменной также будет работать. Например: # Определение функции за пределами определения класса def f1(self, x, y): return min(x, x+y) class C: f = f1 def g(self): return Привет всему миру Теперь f , g и h являются атрибутами класса C и ссылаются на объекты функции и, следовательно, все они будут методами экземпляров класса C. Вы можете также использовать функцию, определенную с помощью оператора lambda. Заметим, что такая практика обычно только сбивает с толку. Методы могут вызывать другие методы, как атрибуты аргумента self , например: class Bag: def init (self): self.data = [] def add(self, x): self.data.append(x) def addtwice(self, x): self.add(x) self.add(x) Методы могут ссылаться на глобальные имена точно таким же способом, как и обычные функции. Глобальная область видимости, ассоциированная с методом - это глобальное пространство имен модуля, содержащего определение функции (так как определение функции обычно находится в определении класса, то - в глобальном пространстве имен модуля, содержащего определение класса). В то время как редко существует веская причина использовать глобальные данные в методе, глобальная область видимости все же находит множество разумных применений: использование импортированных в глобальную область видимости модулей, а также определенных в ней функций и классов. 9.5 Наследование Конечно, особенность языка не достойна называться "классом" без поддержки наследования. Определение производного класса с именем производный класс выглядит следующим образом: class производный класс(базовый класс): инструкциях инструкциям Базовый класс (базовы1й класс) должен быть определен в области видимости, в которой находится определение производного класса (производный класс). Вместо имени базового класса можно использовать выражение, например, если базовый класс определен в другом модуле: class производный класс(модуль.базовый класс): Определение производного класса выполняется так же, как и определение базового класса. Сконструированный объект-класс помнит базовый - он используется для разрешения имен атрибутов: если запрошенный атрибут не найден в классе, поиск продолжается в базовом классе. Это правило применяется рекурсивно, если базовый класс, в свою очередь, является производным от другого класса. В создании экземпляра производного класса нет ничего особенного: производный класс() порождает новый экземпляр класса. Производные классы могут переопределить методы базовых классов. Метод базового класса, вызывающего другой определенный для него метод, может, на самом деле, вызывать метод производного класса, переопределившего этот метод (говоря в терминах C++, все методы в языке Python являются виртуальными). Переопределяя метод в производном классе, Вы можете также захотеть вызвать метод базового класса с тем же именем. Это можно сделать напрямую: просто вызовите базовый класс.етод (self, список аргументов) , где базовый класс - ссылка на базовый класс в том виде, в котором он доступен в текущей области видимости. В языке Python есть ограниченная поддержка множественного наследования. Определения класса с несколькими базовыми классами выглядит следующим образом: Атрибуты классов ведут себя как статические атрибуты их экземпляров (то есть общие для всех экземпляров данного класса). Однако присвоить такому атрибуту новое значение Вы можете, только обратившись к нему как атрибуту того класса, в котором он определен (в противном случае Вы лишь создадите новый атрибут экземпляра с таким же именем). инструкциям Единственное правило, необходимое для объяснения семантики, - правило разрешения имен атрибутов. Поиск производится сначала в глубину, затем слева направо. Таким образом, если атрибут не найден в производный класс, то он ищется сначала в базовый класс1, затем (рекурсивно) в базовых классах класса базовый класс1 и только потом в базовый класс2 и т. д. (Для некоторых людей кажется более естественным другой порядок разрешения имен атрибутов - сначала в классах базо-вый класс1 , базовый класс2, базовый класс3 и только потом в базовых классах класса базовый класс1 . Однако в этом случае возникает зависимость результата от реализации каждого из базовых классов. С принятым же правилом, нет разницы между прямыми и унаследованными атрибутами базовых классов.) 9.6 Частные атрибуты Python предоставляет ограниченную поддержку частных атрибутов классов. Любой атрибут вида атрибут (имя которого содержит не менее двух символов подчеркивания в начале и не более одного в конце) заменяется на класс атрибут, где класс - имя текущего класса с "обрезанными" символами подчеркивания в начале. Такая обработка производится независимо от синтаксического расположения идентификатора, то есть может использоваться для определения частных атрибутов, доступ к которым будет возможен только из методов этого класса и методов его экземпляров. (Имя может быть обрезано, если его длина превысит 255 символов.) Если Вы ссылаетесь на имя, находясь за пределами класса, или если имя класса состоит только из символов подчеркивания, то оно преобразованию не подлежит. Преобразование имен обеспечивает классам возможность определить "частные" атрибуты, не беспокоясь о том, что производные классы могут переопределить их, а также не дают к ним доступа коду, находящемуся за пределами класса. Заметьте, что правила преобразования разработаны в основном для того, чтобы избежать случайного вмешательства. Иногда доступ к частным атрибутам необходим, например, для отладчиков - это одна из причин, почему оставлена лазейка. Если Вы из класса вызываете код с помощью exec , execfile, eval() или evalfile() , то внутри этого кода класс не будет считаться текущим: ситуация аналогична использованию инструкции global - действие ограничивается единовременно байт-компилированным кодом. Это ограничение распространяется и на getattr() , setattr() и delattr() , а также на прямое использование dict . class производный класс(базовый класс1, базовый класс2, базовый класс3): инструкциях 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [ 24 ] 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |