Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 延迟加载描述符_Python_Lazy Loading_Descriptor - Fatal编程技术网

Python 延迟加载描述符

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

我想实现变量的延迟加载,但我似乎有点误解了描述符。我想要对象变量,它在第一次访问时将调用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”?还有别的办法吗

该死,不能回答我自己的问题。。。因此,这里是 编辑: 谢谢你的意见!但是,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和其他来源获取内容,我只是不想过早或不必要地连接到这些内容)