引言
在前面的章节中,我们讲解了python使用函数指针设置测试状态。在那里,我们只需要通过将定义的函数名赋值给变量,然后在调用就可以。但是还有一个问题,就是我们需要手动填写被调用的状态的维度,这个在有些时候会出现问题。不管是在训练或者在复现的时候,都会因为马虎忘记改写。
而且传统的python字典不支持自引用查找,就是设置字典里的键,其值与字典中其他的键值有关。因此今天来讲解下python自引用字典的代码。
自引用字典
首先给出完整代码:
class ParamDict(dict):
def __getitem__(self, key):
val = dict.__getitem__(self, key)
return callable(val) and val(self) or val
P=ParamDict({
'a':1,
'b':lambda self:self['a']
})
以此代码为例进行讲解。在这个类中,分别用到了__getitem__内置方法以及lambda方法以及callable函数。
__getitem__
这个类内置函数实现的功能是,当使用类[key]这样的语句后,就会自动查找类中定义的__getitem__方法,并返回这个方法的return 值。
不论数据结构是否是字典,只要在类中定义了这样的函数,就可以返回。
lambda
lambda这个函数应该是比较常见的了,他实际起到了函数的作用。其用法是:
a = lambda:x:x+1
针对上面的代码,当我们执行这样的语句时:
a = lambda x:x+1
print(a(2))
得到的结果是:
可以看到,它并没有像传统的函数定义那样使用def,就可以实现函数调用的效果。
callable
这个函数的作用是,判断一个对象是否是可以调用的,如果是,返回True;不是,返回False。
注意像a = 1这样的就不是一个可以调用的对象。
对于类来说,其需要在其中实现__call__方法,才可以被认为是可以调用的对象。而__call__方法的作用是,使类具有像函数一样的使用形式,如:
class a():
def __init__(self,data):
a = data
def __call__(self, b):
print(b)
yes = a(4)
yes(3)
这里这样写是为了提醒大家,虽然__init__也可传参,但是其传参数的位置却和__call__方法需要的地方不一样。__init__需要在实例一个类的时候传入参数,而__call__需要在使用的时候传入。
解析
class ParamDict(dict):
def __getitem__(self, key):
val = dict.__getitem__(self, key)
return callable(val) and val(self) or val
P=ParamDict({
'a':1,
'b':lambda self:self['a']
})
P['b']
在此回到代码,我们看到,这里从函数的执行顺来看,需要执行两次__getitem__。
第一次:P['b']
这时候val是一个lambda对象,从callable()也可以看到是True
第二次:self['a']
第二次再执行,是因为第一次返回的True的同时执行了val(self)。
而这时候再次执行__getitem__时,得到的val是一个具体的值,因为从父类继承的dict方法中可以检索到这个值(这里源代码隐藏了,看不到具体的代码,但是从分析也可以i知道其意义)。
在这时正好callable为false,可以返回真正的需要的值了。
妙啊~~~
我们通过print对上面的分析进行检验
class ParamDict(dict):
def __getitem__(self, key):
val = dict.__getitem__(self, key)
print(val)
print(callable(val))
print(val)
return callable(val) and val(self) or val
P=ParamDict({
'a':1,
'b':lambda self:self['a']
})
print(P['b'])
当我们把val(self)去掉后
class ParamDict(dict):
def __getitem__(self, key):
val = dict.__getitem__(self, key)
print(val)
print(callable(val))
print(val)
return callable(val)
P=ParamDict({
'a':1,
'b':lambda self:self['a']
})
print(P['b'])
可以看到,只调用了一次。
May the force be with you!
评论(0)
您还未登录,请登录后发表或查看评论