Как выделяется память при создании объекта из класса?

#python #python-3.x #python-2.7

#python #python-3.x #python-2.7

Вопрос:

Я читал, что __init__ это не создает объект (выделяет память).

Я не смог найти, кто выполняет фактическое создание объекта. Как это создание объекта происходит внутри?

Ответ №1:

Вы, вероятно, ищете __new__ .

С точки зрения Python, происходит что-то вроде следующего, предполагая, что у вас есть класс, A , который наследуется непосредственно от object :

  • A.__new__ вызывается метод
  • object.__new__ вызывается с cls=A
  • A.__init__ вызывается метод с аргументами, переданными из вашего A.__new__

Пример:

 class A():

    def __new__(cls, *args, **kwargs):
        print(f'__new__ called with args {args} and kwargs {kwargs}')
        return super().__new__(cls)  # object.__new__

    def __init__(self, *args, **kwargs):
        print(f'__init__ called with args {args} and kwargs {kwargs}')
        # args are discarded
        for key, arg in kwargs.items():
            setattr(self, key, arg)

a_instance = A('arg', kwarg=1)
a_instance.kwarg
 

Вывод:

 __new__ called with args ('arg',) and kwargs {'kwarg': 1}
__init__ called with args ('arg',) and kwargs {'kwarg': 1}
1
 

В общем, с этим ничего не нужно делать __new__ , потому что объекты Python обычно изменчивы, и поэтому нет различия между инициализацией атрибутов экземпляра и их изменением.

По моему опыту, основной вариант использования переопределения __new__ — это когда вы наследуете от неизменяемых типов, таких как tuple . В таких случаях вы должны инициализировать все атрибуты экземпляра при создании, и поэтому __init__ слишком поздно.

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

1. Является ли определение и вызов __new__ неявными?

2. @ak_app Да, когда вы вызываете A(*args, **kwargs) , вы на самом деле вызываете A.__new__(*args, **kwargs) . args и kwargs пересылаются A.__init__ .

3. У вас есть # tuple.__new__ комментарий, но вы на самом деле не наследуете от tuple .

4. @user2357112 Исправлено, я рассматривал возможность использования примера tuple подкласса, затем отбросил его, но забыл изменить комментарий.

Ответ №2:

Когда вы вводите что-то подобное MyClass() в Python, среда выполнения Python вызовет __new__ MyClass , которая должна создать объект; за этим последует вызов __init__ для вновь созданного объекта. Таким образом, __new__ называется «конструктором» и __init__ «инициализатором». Эта последовательность кодируется вне Python (в C, в случае CPython). Посетите документацию Python, чтобы узнать больше о __new__ и __init__ .

Ответ №3:

Короткий ответ

В качестве короткого ответа метод, который создает объект, — это __new__ and __init__ просто инициализирует созданный объект.

Длинный ответ

Однако продолжайте читать, если хотите получить более глубокое представление о том, что происходит, когда объект будет создан в python.


В python 2.x в python было два типа классов — классы старого и нового стилей.

 class C: # A old-style class sample 
     pass
 

 class C(object): # A old-style class sample 
     pass
 

В классах старого стиля не __new__ было метода, поэтому __init__ был конструктор.
Однако в python 3.x остается только класс нового стиля (независимо от того, какое определение вы выберете для своего класса, оно будет унаследовано от базового класса «Object»). В классах нового стиля доступны оба __new__ __init__ метода и . __new__ и __init__ является конструктором и инициализатором соответственно, и вам разрешено переопределять их оба (будьте осторожны, как правило, вам не нужно переопределять __new__ метод expect в некоторых случаях, таких как определение метаклассов и т. Д., Поэтому Не манипулируйте им, если в этом нет необходимости.)
Наконец, когда объект будет создан, конструктор будет вызван перед инициализатором.

 class A(object):  # -> don't forget the object specified as base

def __new__(cls):
    print "A.__new__ called"
    return super(A, cls).__new__(cls)

def __init__(self):
    print "A.__init__ called"

A()
 

Вывод будет:

 A.__new__ called
A.__init__ called