Подтвердить что ты не робот

Члены класса Python

Я просто изучаю Python, и я родом из C-фона, поэтому, пожалуйста, дайте мне знать, если у меня есть путаница/смешение между ними.

Предположим, что у меня есть следующий класс:

class Node(object):
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

    @classmethod
    def tree(cls, element, left, right):
        node = cls(element)
        node.left = left
        node.right = right
        return node

Это класс с именем Node, который перегружает конструктор, чтобы иметь возможность обрабатывать различные аргументы, если это необходимо.

В чем разница между определением self.element только в __init__ (как показано выше), а не следующим образом:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Является ли self.element в __init__ тем же, что и переменная класса element? Разве это не просто перезаписать element от None до значения element, переданного в __init__?

4b9b3361

Ответ 1

Один атрибут класса, а другой - атрибут экземпляра. Они разные, но они тесно связаны друг с другом способами, которые заставляют их выглядеть одинаково время от времени.

Это связано с тем, как python ищет атрибуты. Там есть иерархия. В простых случаях это может выглядеть так:

instance -> Subclass -> Superclass -> object (built-in type)

Когда вы ищете атрибут на instance, как это...

`instance.val`

... что на самом деле происходит, так это то, что сначала Python ищет val в самом экземпляре. Тогда, если он не находит val, он выглядит в своем классе Subclass. Тогда, если он не найдет там val, он выглядит в родительском элементе Subclass, Superclass. Это означает, что когда вы это сделаете...

>>> class Foo():
    foovar = 10  
    def __init__(self, val):
        self.selfvar = val

... все экземпляры Foo share foovar, но имеют свои собственные различные selfvar s. Вот простой, конкретный пример того, как это работает:

>>> f = Foo(5)
>>> f.foovar
10
>>> Foo.foovar
10

Если мы не касаемся foovar, это то же самое для f и Foo. Но если мы изменим f.foovar...

>>> f.foovar = 5
>>> f.foovar
5
>>> Foo.foovar
10

... мы добавляем атрибут экземпляра, который эффективно маскирует значение Foo.foovar. Теперь, если мы непосредственно меняем Foo.foovar, это не влияет на наш экземпляр Foo:

>>> Foo.foovar = 7
>>> f.foovar
5

Но это влияет на новый экземпляр Foo:

>>> Foo(5).foovar
7

Также имейте в виду, что изменяемые объекты добавляют еще один слой косвенности (как напомнил мне Милльсон). Здесь f.foovar относится к тому же объекту, что и Foo.foovar, поэтому, когда вы изменяете объект, изменения распространяются по иерархии:

>>> Foo.foovar = [1]
>>> f = Foo(5)
>>> f.foovar[0] = 99
>>> Foo.foovar
[99]

Ответ 2

В python можно иметь переменные класса и переменные экземпляра с тем же именем. Они расположены по отдельности в памяти и доступны по-разному.

В вашем коде:

class Node(object):
    element, left, right = None
    def __init__(self, element):
        self.element = element
        self.left = self.right = None

Первый набор переменных (вне функции __init__) называется переменными класса. К ним можно получить доступ с помощью Node.element и т.д. Они эквивалентны статическим переменным-членам в С++, и они разделяются всеми экземплярами класса.

Второй набор переменных (внутри функции __init__) называется переменными экземпляра. Доступ к ним осуществляется через объект self, например. self.element, или именем экземпляра, например. myNode.element вне класса.

Важно отметить, что вам нужно использовать форму self.variable или Node.variable для доступа к любому из них изнутри функции-члена. Просто доступ к variable будет пытаться получить доступ к локальной переменной с именем variable.

Ответ 3

self.element внутри конструктора является переменной экземпляра (если объект node изменяет свое значение, он изменяется только для этого объекта), где тот, который во второй версии является переменной класса (поэтому, если один объект node изменяет его значение изменится для всех объектов node).

Аналогия в С++ была бы нестатической или статической переменной-членом в вашем классе.

Ответ 4

Важной частью является аргумент self для __init__. Фактически, в любом случае метод, это будет первым аргументом. Это делается по дизайну; в Python, единственный раз, когда вы действительно имеете доступ к экземпляру, находится во время вызовов метода, и он явно показан с аргументом self.

Когда вы находитесь внутри определения class, у вас пока нет каких-либо экземпляров, так что вы действительно изменяете сам класс. Таким образом, если вы определяете атрибуты на уровне класса, то они действительно становятся атрибутами класса, а не экземпляром.

Сравнивая это с C (++), вы, вероятно, могли бы сказать, что "классы" на этих языках являются в основном чертежами для объектов, которые они представляют. "Эти объекты должны иметь атрибуты foo и bar и, кроме того, следующие методы". Однако в Python классы - это сами объекты, и их основная сила заключается в том, что они могут создавать копии (экземпляры) самих себя, которые также используют методы класса. Таким образом, это больше похоже на "У вас должны быть foo и bar как атрибуты класса, и, кроме того, следующий метод, который вы будете использовать для создания экземпляров".

Итак, вместо чертежа это более пошаговое руководство.

Ответ 5

self.element в init - это переменная экземпляра, вы можете получить/установить ее в любую другую функцию-член, набрав self.element. элемент, объявленный в классе, является переменной класса, вы можете получить/установить его, набрав Node.element.

Ответ 6

когда вы пытаетесь получить доступ к переменной с классом, на который он смотрит только

cls.__dict__

но когда вы пытаетесь получить доступ к переменной с экземпляром, она выглядит сначала

self.__dict__ 

если find вернется или если не удается найти, то он также выглядит в

cls.__dict__

здесь cls - это класс

class Test:
    temp_1=10
    temp_2=20

    def __init__(self):
        self.test_1=10
        self.test_2=20

    @classmethod
    def c_test(cls):
        pass

    def t_method(self):
        pass


print Test.__dict__
print Test().__dict__

Выход

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20}

{'test_2': 20, 'test_1': 10}

Подробнее специальный атрибут класса