延迟加载描述符
我想实现变量的延迟加载,但我似乎有点误解描述符。我想要对象变量,第一次访问时将调用 obj.load() 函数,该函数将使用变量的实际值初始化变量。我写的
class ToLoad(object):
def __init__(self, loader_name="load")
self.loader_name=loader_name
def __get__(self, obj, type):
if not (hasattr(obj, "_loaded") and obj._loaded):
obj._loaded=True
getattr(obj, self.loader_name)()
return None
class Test(object):
x=ToLoad()
def __init__(self, y):
self.y=y
def load(self):
print("Loading {}".format(self.y))
self.x=self.y
t1=Test(1)
t2=Test(2)
print("A", t1.x)
print("B", t2.x)
print("C", t1.x)
至少在第一次加载时无法返回实际值。有人可以建议另一种方法来解决这个问题吗?我不确定如何在 get 中返回正确的值,因为此时我不知道该属性称为“x”?还有其他办法吗?
该死,无法回答我自己的问题...所以这是 编辑: 感谢您的投入!但是,我的 load() 函数不返回变量本身,因为它加载了许多不同的变量。我想最小化使用延迟加载的符号。所以我想出了一个装饰器
class to_load:
def __init__(self, *vars, loader="load"):
self.vars=vars
self.loader=loader
def __call__(self, cls):
def _getattr(obj, attr):
if attr in self.vars:
getattr(obj, self.loader)()
return getattr(obj, attr)
else:
raise AttributeError
cls.__getattr__=_getattr
return cls
@to_load("a", "b")
class Test:
def load(self):
print("Loading")
self.a=1
self.b=2
t=Test()
print("Starting")
print(t.a)
print(t.b)
#print(t.c)
可以吗?我不确定我是否破坏了东西。
I wanted to implement lazy loading of variables, but I seem to misunderstand descriptors a bit. I'd like to have object variables, which on first access will call the obj.load() function which will initialize the variables with their real value. I wrote
class ToLoad(object):
def __init__(self, loader_name="load")
self.loader_name=loader_name
def __get__(self, obj, type):
if not (hasattr(obj, "_loaded") and obj._loaded):
obj._loaded=True
getattr(obj, self.loader_name)()
return None
class Test(object):
x=ToLoad()
def __init__(self, y):
self.y=y
def load(self):
print("Loading {}".format(self.y))
self.x=self.y
t1=Test(1)
t2=Test(2)
print("A", t1.x)
print("B", t2.x)
print("C", t1.x)
which fails to return the actual value on loading at least the first time. Could someone suggest another way to solve that problem? I'm not sure how to return the correct value in get since at that point I do not know that the attribute is called "x"? Any other way?
DAMN, can't answer my own question... So here is the
EDIT:
Thanks for the input! However, my load() function does not return the variable itself, since it loads many different variables. And I want to minimize the notation for using lazy loading. So I came up with a decorator
class to_load:
def __init__(self, *vars, loader="load"):
self.vars=vars
self.loader=loader
def __call__(self, cls):
def _getattr(obj, attr):
if attr in self.vars:
getattr(obj, self.loader)()
return getattr(obj, attr)
else:
raise AttributeError
cls.__getattr__=_getattr
return cls
@to_load("a", "b")
class Test:
def load(self):
print("Loading")
self.a=1
self.b=2
t=Test()
print("Starting")
print(t.a)
print(t.b)
#print(t.c)
Is that OK? I'm not sure if I'm breaking things.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,这里有两个问题:
__get__
返回None
,而它应该是您想要x
表示的值。x = y
,但您的描述符没有实现__set__
。因此,您应该创建一个具有实际值的属性,并检查它,而不是设置“已加载”标志。如果你不希望它是只读的,你应该实现
__set__
。否则,返回值并让__get__
处理赋值,而不是load
中的self.x = self.y
。Well, there are two problems here:
None
from__get__
, whereas it should be the value you wantx
to represent.x = y
, but your descriptor doesn't implement__set__
.So, instead of setting a "is loaded" flag, you should rather create an attribute with the actual value, and check for that. If you don't want it to be read-only, you should implement
__set__
. Otherwise, instead ofself.x = self.y
inload
, return the value and let__get__
to take care of the assignment.您想要的可能更像是这样:
为了使您的代码正常工作,您需要一些
return
:描述符知道它们存储在哪个对象上,但它们不知道存储在哪个属性上。您想要拦截属性的访问,而不是更改返回值,因此您需要
__getattr__
而不是描述符。What you want is probably more like this:
To make your code work you need a few
return
s:Descriptors know on which object they are stored, but they don't know on which attribute. You want to intercept the access of a attribute, not change the returned value, so you want
__getattr__
instead of descriptors.