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

Class instance implementation, initializing instance - from SICP python

我试图理解 python class 系统实现中的初始化函数,摘自本书 (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'

的新 class 对象
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']

我的理解

由于这是 classes 的功能实现,因此比较的是内置的 python classes。在下面我说 Python Class/object/instance 的地方,我的意思是内置的。

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

init_instancemake_class 中的 return 到 new(*args)。这意味着实例字典被return编辑为new(*args)。但是,make_class returns cls 这意味着我们必须以某种方式更新 cls 以包含 instance 属性。那是怎么做到的?很可能是 init (instance, *args) 这个语句,但我不知道如何分解这个语句。我还没有看到 init 作为 fn,参数是如何传递给它的?

这段代码有点棘手,所以您发现其中的一些内容令人费解也就不足为奇了。要理解它,你需要理解closures. There's some info about closures in Python in this answer.

init_instanceinstance = make_instance(cls)创建一个新的实例,然后查找clsinit方法,如果存在,就调用[=14] =] 方法与新实例以及 args 中传递的任何内容。 make_instanceinit_instance 都不会修改 cls 字典,或者在创建 cls 时传递给 make_classattributes 字典。实际发生的是 make_instance 的每次调用都会为其创建的实例创建一个新的 attributes 字典,实例字典中的 getset 函数可以引用它。

您的 make_my_class 定义没有多大意义。它有一个冗余的 pass 语句,并且 make_class({'__init__': __init__}) 不会工作,因为你没有在任何地方定义 __init__,它需要一个函数来初始化你的 class 实例.

这是您的代码的修改版本。我为 my_class 创建了一个简单的 __init__ 函数,并添加了几个 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