Почему доступ к переменной класса изнутри класса "я". в 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). Это делает код менее читаемым, так как вы никогда не знаете, какое имя должно быть, и по существу превращает каждую локальную переменную во все методы в часть открытого интерфейса (поскольку привязка атрибута этого имени изменяет поведение метода).

Оба имеют дополнительный недостаток: для них требуется специальная оболочка. В настоящее время "метод" - это просто регулярная функция, доступная через атрибут класса. Это очень полезно для широкого использования хороших случаев.