Найти - Пользователи
Полная версия: Что происходит при создании экземпляра класса?
Начало » Python для новичков » Что происходит при создании экземпляра класса?
1 2
odnochlen
1. str(1) - что вызывается, __init__ или __call__?
2.
>>> print str('a')
a
>>> print str.__init__('a')
None
>>> print str.__call__('a')
a
Почему __init__ возвращает None вместо self?

3.
MyClass(a, b) = 1
Такое может работать?
reclosedev
1. Строки - immutable. Вызывается __new__
2. __init__ не должен ничего возвращать (т.е. возвращать None)
As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.
3. Думаю нет. Результатом же будет ссылка на экземпляр или immutable, для которого вообще бессмысленно.
odnochlen
1. Ага, то есть сначала вызывается class.__new__() и возвращает новый экземпляр класса, а потом вызывается class.__init__(obj, *params)? А как быть с __call__?
Fibio
__call__ вызывается при обращении к экземпляру как к функции, str(1) - вы создаете экземпляр класса str а не вызываете его
odnochlen
Так что и в каком порядке происходит, если я пишу hz(1)?
Андрей Светлов

Вызывается hz.__call__(1) Если hz — класс, то __call__ создает его экземпляр вызывая __new__ и __init__

odnochlen
А как он вызывает __new__ и __init__?
reclosedev
odnochlen
А как он вызывает __new__ и __init__?
Как я понимаю: классы создает type, внутри его __call__ все и вызывается.

Самому стало интересно . Вот что будет если переопределить type и добавить принты:
class FooMeta(type):
    def __call__(mcs, *args, **kwargs):
        print 'mcs call', args, kwargs
        return super(FooMeta, mcs).__call__(*args, **kwargs)
 
    def __new__(mcs, name, bases, attrs):
        print 'mcs new', name, bases, attrs
        return super(FooMeta, mcs).__new__(mcs, name, bases, attrs)
 
    def __init__(mcs, *args, **kwargs):
        print 'mcs init', args, kwargs
        return super(FooMeta, mcs).__init__(*args, **kwargs)
 
 
class Foo(object):
    __metaclass__ = FooMeta
 
    def __new__(cls, *args):
        print 'ex new', cls, args
        return super(Foo, cls).__new__(cls, *args)
     
    def __init__(self, *args):
        print 'ex init', args
 
foo = Foo(123)
foo = Foo(321)
Вот какая очередность получается:
mcs new Foo (<type 'object'>,) {'__module__': '__main__', '__metaclass__': <class '__main__.FooMeta'>, '__new__': <function __new__ at 0x015751F0>, '__init__': <function __init__ at 0x01575230>}
mcs init ('Foo', (<type 'object'>,), {'__module__': '__main__', '__metaclass__': <class '__main__.FooMeta'>, '__new__': <function __new__ at 0x015751F0>, '__init__': <function __init__ at 0x01575230>}) {}
mcs call (123,) {}
ex new <class '__main__.Foo'> (123,)
ex init (123,)
mcs call (321,) {}
ex new <class '__main__.Foo'> (321,)
ex init (321,)
Сначала создается класс Foo (один раз), класс инициализируется (тоже один раз). Потом уже используется __call__ этого класса для создания экземпляров. Так как мы в нем вызываем базовый type.__call__, он вызывает __new__ (если бы его не было, использовался бы object.__new__), а базовый object.__new__ вызывает Foo.__init__
odnochlen
Т.е. переопределение __new__ и __call__ в классах ничем хорошим не закончится?
reclosedev
odnochlen
Т.е. переопределение __new__ и __call__ в классах ничем хорошим не закончится?
Если базовые методы не вызывать то да. Но для своих модификаций immutable типов или при реализации штук наподобие декларативного Django ORM, Enthought Traits и т.п., без этого не обойтись.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB