目标是创建一个类似于db结果集的模拟类.
因此,例如,如果数据库查询使用dict表达式返回{'ab':100, 'cd':200},那么我想看到:
>>> dummy.ab
100
Run Code Online (Sandbox Code Playgroud)
起初我想也许我可以这样做:
ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
def __init__(self, ks, vs):
for i, k in enumerate(ks):
self[k] = vs[i]
setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))
def fn_readonly(self, v)
raise "It is ready only"
if __name__ == "__main__":
c = C(ks, vs)
print c.ab
Run Code Online (Sandbox Code Playgroud)
但是c.ab返回一个属性对象.
更换setattr线路k = property(lambda x: vs[i])完全没用.
那么在运行时创建实例属性的正确方法是什么?
对于这个问题:
为什么描述符不能成为实例属性?
有人回答说:
描述符对象需要存在于类中,而不是实例中
因为这是实施的方式__getattribute__.
一个简单的例子.考虑描述符:
class Prop(object):
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj._value * obj._multiplier
def __set__(self, obj, value):
if obj is None:
return self
obj._value = value
class Obj(object):
val = Prop()
def __init__(self):
self._value = 1
self._multiplier = 0
Run Code Online (Sandbox Code Playgroud)
考虑每个obj都有多个Prop的情况:我需要使用唯一的名称来标识值和乘数(比如这里.拥有一个每个实例描述符对象将允许将_multiplier(和_value)存储在描述符本身中,简化了一些事情.
要实现每个实例描述符属性,您需要:
我知道之前已经提出过类似的问题,但我还没有找到真正的解释:
我想创建一个具有某些属性的对象。我想动态添加它们。与向现有对象实例添加方法类似,但使用属性而不是方法。下面是一个简单的例子。
我喜欢动态创建:
class A():
@property
def a(self):
return self._a
@a.setter
def a(self, x):
self._a = 10*x
@property
def b(self):
return self._b
@b.setter
def b(self, x):
self._b = 10*x
Run Code Online (Sandbox Code Playgroud)
要使用方法来做到这一点,我会这样做:
class B():
def __init__(self):
for i in range(70,80):
self.__dict__[chr(i)] = types.MethodType(lambda self,x: x*i, self)
Run Code Online (Sandbox Code Playgroud)
对于我尝试过的属性:
class B():
def __init__(self):
for i in range(70,80):
def tmp(self, x):
self._x = i*x
self.__dict__[chr(i)] = property(fget=lambda self: self._i, fset=tmp)
Run Code Online (Sandbox Code Playgroud)
我也找到了types.DynamicClassAttribute,但我不确定这是否有帮助。
这里提出了一个相关问题,关于向类添加属性(在 python 2 中): Dynamically add @property in python。我不知道如何将其扩展到类的实例。
我希望能够将属性http://docs.python.org/library/functions.html#property添加到对象(类的特定实例).这可能吗?
关于python中鸭子打孔/猴子修补的其他一些问题:
更新:由delnan在评论中回答
我X这里有一个描述符类.我尝试X在另一个类中使用描述符Y
class X:
def __init__(self, value):
self.value = value
def __get__(self, instance, owner):
print('#### X.__get__ ####')
return self.value
def __set__(self, instance, value):
print('#### X.__set__ ####')
self.value = value
class Y:
def __init__(self):
self.x = X(10)
y = Y()
print(y.x)
y.x = 20
Run Code Online (Sandbox Code Playgroud)
我希望语句print(y.x)会调用x.__get__并且语句y.x = 20会调用x.__set__,但它不会发生.当我运行上面的程序时,我得到了这个输出.
<__main__.X object at 0x7fc65f947950>
Run Code Online (Sandbox Code Playgroud)
为什么没有调用描述符方法?
我基本上有一个围绕词典列表的精心设计的包装器:
class Wrapper(object):
def __init__(self, data):
self.data = data
def get(self, attr):
return [d[attr] for d in self.data]
Run Code Online (Sandbox Code Playgroud)
所以,
Wrapper([{'x': 23}, {'x': 42}, {'x': 5}]).get('x')
Run Code Online (Sandbox Code Playgroud)
回报[23, 42, 5].现在我想分配速记属性,以便Wrapper.x返回相同的Wrapper.get('x').我不知道data先验中存在哪些键,所以我目前的方法是(改编自这个问题:
class Wrapper(object):
def __init__(self, data):
self.data = data
for key in data[0].keys():
setattr(self, key, property(lambda self: self.get(key)))
Run Code Online (Sandbox Code Playgroud)
因此,假设数据的所有元素都具有相同的密钥,并且它们在python中都是有效的标识符.但是,Wrapper(...).x返回,<property at 0x10a3d4838>我做错了什么?