Реализация экземпляра класса, инициализация экземпляра - из питона SICP - PullRequest
0 голосов
/ 09 июня 2018

Я пытаюсь понять функцию инициализации в реализации системы классов 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): принимает аргумент 'class' -> 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 Ответ

0 голосов
/ 15 июня 2018

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

init_instance создает новый экземпляр с instance = make_instance(cls), затем ищет метод init cls иесли он существует, он вызывает метод init с новым экземпляром и всем, что было передано в args.Ни make_instance, ни init_instance не изменяют словарь cls или словарь attributes, которые были переданы в make_class при создании cls.На самом деле происходит то, что каждый вызов make_instance создает новый attributes dict для экземпляра, который он создает, на который могут ссылаться функции 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'))

output

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
...