Python 延迟加载描述符
我想实现变量的延迟加载,但我似乎有点误解了描述符。我想要对象变量,它在第一次访问时将调用obj.load()函数,该函数将用变量的实际值初始化变量。我写Python 延迟加载描述符,python,lazy-loading,descriptor,Python,Lazy Loading,Descriptor,我想实现变量的延迟加载,但我似乎有点误解了描述符。我想要对象变量,它在第一次访问时将调用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, "_loade
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”?还有别的办法吗
该死,不能回答我自己的问题。。。因此,这里是
编辑:
谢谢你的意见!但是,my 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)
可以吗?我不确定我是否打碎了东西。你想要的可能更像这样:
class Test(object):
def __init__(self, y):
self.y=y
def __getattr__(self, attr):
return self.load(attr)
def load(self, attr):
print("Loading `{}`".format(attr)) # ie "Loading `x`"
# get the value for `attr` somewhere, here always self.y
val = self.y
# store it on this object to avoid reloading it
setattr(self, attr, val)
return val
t1=Test(1)
t2=Test(2)
print("A", t1.x)
print("B", t2.x)
print("C", t1.x)
要使代码正常工作,您需要一些return
s:
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
return 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
return self.x
t1=Test(1)
t2=Test(2)
print("A", t1.x)
print("B", t2.x)
print("C", t1.x)
描述符知道它们存储在哪个对象上,但不知道存储在哪个属性上。您希望拦截对属性的访问,而不是更改返回值,因此希望使用
\uuuu getattr\uuuu
而不是描述符 这里有两个问题:
\uuu get\uuu
返回None
,而它应该是希望x
表示的值x=y
,但是您的描述符没有实现\uuuuuuuu设置\uuuuuu
\uuuu设置\uuu
。否则,返回值并让\uuuuu get\uuu
处理赋值,而不是load
中的self.x=self.y
class ToLoad(object):
def __init__(self, var, func):
self.var = var
self.func = func
# style note: try to avoid overshadowing built-ins (e.g. type)
def __get__(self, obj, cls):
try:
return getattr(obj, self.var)
except AttributeError:
value = getattr(obj, self.func)()
setattr(obj, self.var, value)
return value
class Foo(object):
x = ToLoad('x', '_load_x')
def __init__(self, y):
self.y = y
def _load_x(self):
print('Loading {0} into x'.format(self.y))
return self.y
a = Foo(1)
b = Foo(2)
print(a.x)
print(b.x)
print(a.x)
实际上,我不希望返回,因为我的load()函数不返回我在编辑中提到的装饰器的概念的值(请参见编辑)。我希望避免两次提到变量名,而且只有一个加载函数(通常从SQL和其他来源获取内容,我只是不想过早或不必要地连接到这些内容)