Почему доступ к переменной класса изнутри класса "я". в Python?
Возможный дубликат:
Само объяснение Python
Я изучаю Python, и у меня есть вопрос, более теоретический, чем практический, относительно переменных класса доступа из метода этого класса.
Например, мы имеем:
class ExampleClass:
x = 123
def example_method(self):
print(self.x)
Почему обязательно писать точно self.x
, а не только x
? x
принадлежит пространству имен класса, и его использование также принадлежит ему. Что мне не хватает? Какое обоснование стоит за таким стилем?
В С++ вы можете написать:
class ExampleClass {
public:
int x;
void example_method()
{
x = 123;
cout << x;
};
};
И это сработает!
Ответы
Ответ 1
Из История Python: добавление поддержки для пользовательских классов:
Вместо этого я решил отказаться от идеи неявных ссылок на переменные экземпляра. Языки, подобные С++, позволяют вам писать this- > foo to явно ссылается на переменную экземпляра foo (в случае, если отдельная локальная переменная foo). Таким образом, я решил сделать такое явное ссылается только на способ ссылки на переменные экземпляра. К тому же, Я решил, что вместо создания текущего объекта ("this") специальное ключевое слово, я просто сделал бы "this" (или его эквивалент) первый аргумент метода. Переменные экземпляра всегда будут ссылаться как атрибуты этого аргумента.
С явными ссылками нет необходимости иметь специальный синтаксис для определения методов, и вам не нужно беспокоиться о сложных семантики относительно поиска переменных. Вместо этого можно просто определить функция, первый аргумент которой соответствует экземпляру, который конвенция называется "я". Например:
def spam(self,y):
print self.x, y
Этот подход напоминает то, что я видел в Модуле-3, которая уже предоставил мне синтаксис для импорта и обработки исключений. Modula-3 не имеет классов, но позволяет создавать типы записей содержащие полностью типизированные элементы указателя функции, которые инициализируются по умолчанию функции, определенные рядом, и добавляет синтаксический сахар, поэтому что если x является такой переменной записи, а m является указателем на функцию член этой записи, инициализированный функцией f, а затем вызов x.m(args) эквивалентно вызову f (x, args). Это соответствует типичная реализация объектов и методов и позволяет для сопоставления переменных экземпляра с атрибутами первого аргумента.
Таким образом, заявленный самим BDFL, единственной реальной причиной, по которой он решил использовать явное я в отношении неявного я, является то, что:
- он явно
- его проще реализовать, поскольку поиск должен выполняться во время выполнения (а не во время компиляции, например, на других языках), и с неявным я мог бы увеличить сложность (и, следовательно, стоимость) поисковых запросов.
Изменить: есть также ответ на Python FAQ.
Ответ 2
Кажется, что это связано с обработкой области с модулем vs., в Python:
COLOR = 'blue'
class TellColor(object):
COLOR = 'red'
def tell(self):
print self.COLOR # references class variable
print COLOR # references module variable
a = TellColor()
a.tell()
> red
> blue
Ответ 3
Здесь содержимое, которое я сделал в древнем ответе относительно этой функции:
Проблема, с которой вы столкнулись, связана с этим:
Блок представляет собой часть текста программы Python, которая выполняется как единое целое. Ниже приведены блоки: модуль, тело функции и класс определение.
(...)
Область определяет видимость имени внутри блок.
(...)
Объем имен, определенных в блоке класса, ограничен блок класса; он не распространяется на кодовые блоки методов - это включает выражения генератора, поскольку они реализованы с использованием функции. Это означает, что следующее не будет выполнено:
класс A:
a = 42
b = list(a + i for i in range(10))
http://docs.python.org/reference/executionmodel.html#naming-and-binding
Вышеуказанное означает:
тело функции является блоком кода, а метод является функцией, тогда имена, определенные из тела функции, присутствующие в определении класса, не распространяются на тело функции.
Мне показалось странным, когда я читал это, но то, как создается Python:
Объем имен, определенных в блоке класса, ограничен блоком класса; он не распространяется на кодовые блоки методов
Это официальная документация, которая говорит об этом.
.
ИЗМЕНИТЬ
heltonbiker написал интересный код:
COLOR = 'blue'
class TellColor(object):
COLOR = 'red'
def tell(self):
print self.COLOR # references class variable
print COLOR # references module variable
a = TellColor()
a.tell()
> red
> blue
Мне стало интересно, как инструкция print COLOR
, написанная внутри метода tell()
, провоцирует печать значения глобального объекта COLOR, определенного вне класса.
Я нашел ответ в этой части официальной документации:
Методы могут ссылаться на глобальные имена так же, как обычные функции. Глобальной областью, связанной с методом, является модуль содержащий его определение. (Класс никогда не используется в качестве глобальной области.) В то время как человек редко сталкивается с серьезной причиной использования глобальных данных в метод, существует много законных видов использования глобальной сферы: для одного вещи, функции и модули, импортированные в глобальную область, могут быть используемых методами, а также функций и классов, определенных в нем. Обычно класс, содержащий этот метод, сам определяется в этом глобальный охват (...)
http://docs.python.org/2/tutorial/classes.html#method-objects
Когда интерпретатор должен выполнить print self.COLOR
, поскольку ЦВЕТ не является атрибутом экземпляра (то есть идентификатор "COLOR" не принадлежит пространству имен экземпляра) интерпретатор входит в пространство имен класса экземпляра в поисках идентификатора "COLOR" и находит его, поэтому он печатает значение TellColor.COLOR
Когда интерпретатор должен выполнить print COLOR
, так как в этой инструкции нет доступа к атрибуту, он будет искать идентификатор "COLOR" в глобальном пространстве имен, который в официальной документации говорит об этом пространстве имен модулей.
Ответ 4
Какие имена атрибутов привязаны к объекту (а его класс и предки этого класса) не разрешимы во время компиляции. Таким образом, вы либо делаете поиск атрибутов явным, либо вы:
- уничтожить локальные переменные (в методах) и всегда использовать переменные экземпляра. Это не делает ничего хорошего, поскольку он существенно удаляет локальные переменные со всеми их преимуществами (по крайней мере, в методах).
- решить, относится ли база
x
к атрибуту или локальному во время выполнения (с некоторыми дополнительными правилами, когда x = ...
добавляет новый атрибут, если нет self.x
). Это делает код менее читаемым, так как вы никогда не знаете, какое имя должно быть, и по существу превращает каждую локальную переменную во все методы в часть открытого интерфейса (поскольку привязка атрибута этого имени изменяет поведение метода).
Оба имеют дополнительный недостаток: для них требуется специальная оболочка. В настоящее время "метод" - это просто регулярная функция, доступная через атрибут класса. Это очень полезно для широкого использования хороших случаев.