类实例实现,初始化实例 - 来自SICP python

时间:2018-06-08 22:54:03

标签: python python-3.x python-2.7 class sicp

我正在尝试理解python类系统实现中的初始化函数,取自本书(SICP python - reference to book section)

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方法。如果value不可调用,则返回value(父类的python属性)。
  • make_class (attributes, base_class = None):设置一个类的行为,具有从另一个类继承的能力。使用get和set以与make_instance类似的方式,除了它不需要bind_method。它使用init_instance(cls, *args)创建具有任意数量参数的新对象实例(对于属性的方法)。 cls的{​​{1}}参数将类调度字典传递给对象实例。因此,对象'继承'(缺乏更好的词)的类特征。
  • init_instance:我有点不确定。首先,该函数使用init_instance(cls, *args)创建一个实例,该实例通过instance = make_instance(cls)字典继承该类的功能。 cls创建了init = cls['get']('__init__'),这是一个查找init关键字是否已在属性中传递给__init__的语句,make_class使得args在实例的本地?返回一个实例。

我可以将我的问题缩小到 -

if init: init(instance, *args)返回init_instance中的new(*args)。这意味着实例字典将返回make_class。但是,new(*args)会返回make_class,这意味着我们必须以某种方式更新cls以包含cls属性。那怎么样?这很可能就是instance,但我不知道如何打破这种说法。我没有看到init (instance, *args)为fn,如何将参数传递给它?

1 个答案:

答案 0 :(得分:1)

这段代码有点棘手,所以你发现它的一些令人费解并不奇怪。要理解它,您需要了解closures。在this answer中有关于Python中闭包的一些信息。

init_instance使用instance = make_instance(cls)创建新实例,然后查找init的{​​{1}}方法,如果它存在,则会调用cls使用新实例的方法以及init中传递的任何内容。 argsmake_instance都不会修改init_instance字典,也不会修改cls创建attributes时传递给make_class的字典。实际发生的是每次调用cls都会为它创建的实例创建一个新的make_instance dict,实例dict中的attributesget函数可以引用它。

您的set定义没有多大意义。它有一个冗余的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'))