问题
I'm trying to the understand the initialization function in a python class system implementation, taken from this book (SICP python - reference to book section).
The init_instance
(initialization) function """Return a new object with type cls, initialized with args."""
is where I'm having trouble. Below I've tried to narrow down my question, by explaining what I've understood.
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
Here is a call to above functions, to create a new class object called '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']
What I understand
Since this is an functional implementation of classes, the comparison is with inbuilt python classes. Below wherever I say Python Class/object/instance, I mean inbuilt.
make_instande(cls)
: takes the 'class' ->cls
argument (a message fxn dictionary itself) and describes the behaviour of an object , i.e. provides required properties to behave in a similar way to a python object. We can set attributes, that stay local to attributes dictionary using 'set
'. Usingget
, if the attribute is not in object, it is looked up in class definition and abind_method
function is called.bind_method(value,instance)
: binds a function in class definition to the object instance to emulate python methods in a python class instance. if value is not callable, returns value (python attribute from parent class).make_class (attributes, base_class = None)
: Sets the behaviour of a class, with ability to inherit from another class. Uses get and set to in a similar fashion to make_instance, except, it doesn't require a bind_method. It usesinit_instance(cls, *args)
to create a new object instance with arbitrary number of arguments (for methods of the attributes).cls
argument forinit_instance
passes class dispatch dictionary to the object instance. Hence, the object 'inherits' (for lack of a better word) the class features.init_instance(cls, *args)
: Here I am a little unsure. Firstly, the function makes an instance withinstance = make_instance(cls)
, the instance inherits features of the class throughcls
dictionary.init = cls['get']('__init__')
,init
is created, a statement that looks up if__init__
keyword was passed in attributes tomake_class
, ,if init: init(instance, *args)
makes args local to the instance? Returns an instance.
I can narrow down my question to -
init_instance
is a return to new(*args)
in make_class
. Which means an instance dictionary is returned to new(*args)
. However, make_class
returns cls
which means we have to update cls
somehow to contain instance
properties. How is that that being done? It's most likely this statement init (instance, *args)
but I don't know how to break down this statement. I haven't seen init
as fn, how are arguments being passed to it?
回答1:
This code is a little tricky, so it's not surprising that you find some of it puzzling. To understand it, you need to understand closures. There's some info about closures in Python in this answer.
init_instance
creates a new instance with instance = make_instance(cls)
, then it looks up the init
method of cls
, and if it exists, it calls that init
method with the new instance and whatever was passed in args
. Neither make_instance
nor init_instance
modify the cls
dictionary, or the attributes
dictionary that was passed to make_class
when cls
was created. What actually happens is that each call of make_instance
creates a new attributes
dict for the instance it creates, which the get
and set
functions in the instance dict can reference.
Your make_my_class
definition doesn't make much sense. It has a redundant pass
statement, and make_class({'__init__': __init__})
won't work because you haven't defined __init__
anywhere, that needs to be a function which will initialize your class instances.
Here's a modified version of your code. I've created a simple __init__
function for my_class
, and added several print
calls so we can get an idea of what the code's doing.
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
来源:https://stackoverflow.com/questions/50769327/class-instance-implementation-initializing-instance-from-sicp-python