Реализация экземпляра класса, инициализация экземпляра - из SICP Python

Я пытаюсь понять функцию инициализации в реализации системы классов Python, взятую из этой книги (SICP python - ссылка на раздел книги).

init_instance (инициализация) функция """Return a new object with type cls, initialized with args.""" вот где у меня проблемы. Ниже я попытался сузить свой вопрос, объяснив, что я понял.

def make_instance (cls): #good with this
    """return a new object instance, which is a dispatch dictionary"""
    def get_value(name):
        if name in attributes:
            return attributes[name]
        else:
            value = cls ['get'](name)
            return bind_method (value, instance)
    def set_value (name, value):
        attributes [name] = value
    attributes = {}
    instance = {'get': get_value, 'set': set_value}
    return instance

def bind_method (value, instance): #good with this
    """Return a bound method if value is callable, or value otherwise"""
    if callable (value):
        def method(*args):
            return value (instance, *args)
        return method
    else:
        return value

def make_class (attributes, base_class = None): 
    """Return a new class, which is a dispatch dictionary."""
    def get_value(name):
        if name in attributes:
            return attributes[name]
        elif base_class is not None:
            return base_class['get'](name)
    def set_value(name,value):
        attributes[name] = value
    def new(*args):
        return init_instance(cls, *args)
    cls = {'get':get_value,'set':set_value,'new':new}
    return cls

def init_instance(cls,*args): #problem here
    """Return a new object with type cls, initialized with args"""
    instance = make_instance (cls)
    init = cls ['get'] ('__init__')
    if init:                            
        init (instance, *args)          #No return function here
    return instance

Вот вызов вышеупомянутых функций, чтобы создать новый объект класса с именем 'Jim'

def make_my_class():    #define a custom class
    pass
    return make_class({'__init__':__init__})   #return function that implements class

my_class = make_my_class()  #create a class
my_class_instance = my_class['new'] ('Jim') #create a class instance with ['new']

Что я понимаю

Поскольку это функциональная реализация классов, сравнение проводится со встроенными классами Python. Ниже, где бы я ни говорил Python Class/object/instance, я имею в виду встроенный.

  • make_instande(cls): принимает "класс" -> cls Аргумент (сам словарь fxn сообщения) и описывает поведение объекта, то есть предоставляет необходимые свойства, чтобы вести себя аналогично объекту python. Мы можем установить атрибуты, которые остаются локальными для словаря атрибутов, используя 'set". С помощью getЕсли атрибут не находится в объекте, он ищется в определении класса и bind_method функция называется.
  • bind_method(value,instance): связывает функцию в определении класса с экземпляром объекта для эмуляции методов python в экземпляре класса python. если значение не вызывается, возвращает значение (атрибут python из родительского класса).
  • make_class (attributes, base_class = None)Устанавливает поведение класса с возможностью наследования от другого класса. Использует get и set аналогично make_instance, за исключением того, что для него не требуется bind_method. Оно использует init_instance(cls, *args) создать новый экземпляр объекта с произвольным числом аргументов (для методов атрибутов). cls аргумент в пользу init_instance передает словарь диспетчеризации классов экземпляру объекта. Следовательно, объект "наследует" (из-за отсутствия лучшего слова) признаки класса.
  • init_instance(cls, *args): Здесь я немного не уверен. Во-первых, функция создает экземпляр с instance = make_instance(cls)экземпляр наследует свойства класса через cls толковый словарь. init = cls['get']('__init__'), init создается заявление, которое смотрит вверх, если __init__ ключевое слово было передано в атрибутах make_class,, if init: init(instance, *args) делает аргументы локальными для экземпляра? Возвращает экземпляр

Я могу сузить свой вопрос до -

init_instance это возврат к new(*args) в make_class, Что означает, что экземпляр словаря возвращается new(*args), Тем не мение, make_class возвращается cls что означает, что мы должны обновить cls как-то содержать instance свойства. Как это делается? Скорее всего это утверждение init (instance, *args) но я не знаю, как сломать это утверждение. Я не видела init как fn, как аргументы передаются ему?

1 ответ

Решение

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

init_instance создает новый экземпляр с instance = make_instance(cls)затем он смотрит вверх init метод clsи, если он существует, он называет это init метод с новым экземпляром и все, что было передано в args, ни make_instance ни init_instance изменить cls словарь, или attributes словарь, который был передан make_class когда cls был создан. На самом деле происходит то, что каждый вызов make_instance создает новый attributes диктовать для экземпляра, который он создает, который get а также set функции в экземпляре dict могут ссылаться.

Ваш make_my_class определение не имеет особого смысла. Имеет избыточный pass заявление и make_class({'__init__': __init__}) не будет работать, потому что вы не определили __init__ где угодно, это должна быть функция, которая будет инициализировать ваши экземпляры классов.

Вот модифицированная версия вашего кода. Я создал простой __init__ функция для my_classи добавил несколько print звонки, чтобы мы могли получить представление о том, что делает код.

def hexid(obj):
    return hex(id(obj))

def make_instance(cls): # good with this
    """ Return a new object instance, which is a dispatch dictionary """
    def get_value(name):
        print('INSTANCE GET_VALUE', name, 'from', hexid(attributes))
        if name in attributes:
            return attributes[name]
        else:
            value = cls['get'](name)
            return bind_method(value, instance)

    def set_value(name, value):
        attributes[name] = value

    attributes = {'test': 'Default Test'}
    print('Created instance attributes', hexid(attributes))
    instance = {'get': get_value, 'set': set_value}
    return instance

def bind_method(value, instance): # good with this
    """ Return a bound method if value is callable, or value otherwise """
    if callable(value):
        def method(*args):
            return value(instance, *args)
        return method
    else:
        return value

def make_class(attributes, base_class=None): 
    """ Return a new class, which is a dispatch dictionary. """
    def get_value(name):
        print('\nCLASS GET_VALUE', name, 'from', hexid(attributes))
        if name in attributes:
            return attributes[name]
        elif base_class is not None:
            return base_class['get'](name)

    def set_value(name, value):
        attributes[name] = value

    def new(*args):
        return init_instance(cls, *args)

    print('Creating class with attributes', hexid(attributes))
    cls = {'get': get_value, 'set': set_value, 'new': new}
    return cls

def init_instance(cls, *args): # problem here
    """ Return a new object with type cls, initialized with args """
    instance = make_instance(cls)
    init = cls['get']('__init__')
    if init:
        print('Calling init of', hexid(cls), 'on', hexid(instance), 'with', args)
        init(instance, *args)          #No return here
    return instance

def make_my_class(): # define a custom class
    # Create a simple __init__ for the class
    def __init__(inst, *args):
        print('INIT', hexid(inst), args)
        inst['set']('data', args)

    # return a dict that implements class
    return make_class({'__init__': __init__})

# test

#create a class
my_class = make_my_class()

#create some class instances
jim = my_class['new']('Jim')
jim['set']('test', 'Hello')

fred = my_class['new']('Fred') 

print('CLASS', hexid(my_class))
print('\nINSTANCE', hexid(jim))
print(jim['get']('data'))
print(jim['get']('test'))

print('\nINSTANCE', hexid(fred))
print(fred['get']('data'))
print(fred['get']('test'))

выход

Creating class with attributes 0xb71e67d4
Created instance attributes 0xb71373ec

CLASS GET_VALUE __init__ from 0xb71e67d4
Calling init of 0xb7137414 on 0xb71373c4 with ('Jim',)
INIT 0xb71373c4 ('Jim',)
Created instance attributes 0xb7137374

CLASS GET_VALUE __init__ from 0xb71e67d4
Calling init of 0xb7137414 on 0xb713734c with ('Fred',)
INIT 0xb713734c ('Fred',)
CLASS 0xb7137414

INSTANCE 0xb71373c4
INSTANCE GET_VALUE data from 0xb71373ec
('Jim',)
INSTANCE GET_VALUE test from 0xb71373ec
Hello

INSTANCE 0xb713734c
INSTANCE GET_VALUE data from 0xb7137374
('Fred',)
INSTANCE GET_VALUE test from 0xb7137374
Default Test
Другие вопросы по тегам