Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.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_Descriptor - Fatal编程技术网

Python描述符`

Python描述符`,python,descriptor,Python,Descriptor,描述符类如下所示: class Des(object): def __get__(self, instance, owner): ... def __set__(self, instance, value): ... def __delete__(self, instance): ... class Sub(object): attr = Des() X = sub() 问题 我看不出所有者存在的意义,我该如何使用它 要使attr为只读,我们不应该忽略\uu

描述符类如下所示:

class Des(object):
    def __get__(self, instance, owner): ...
    def __set__(self, instance, value): ...
    def __delete__(self, instance): ...

class Sub(object):
    attr = Des()

X = sub()
问题

  • 我看不出
    所有者存在的意义,我该如何使用它

  • 要使attr为只读,我们不应该忽略
    \uuuu set\uuuu
    ,而是定义它以捕获赋值并引发异常。所以
    X.attr=123
    将失败,但是
    \uuuuuuuuuuuuuuuuuuuuuuuuu
    的参数不包含
    owner
    ,这意味着我仍然可以执行
    Sub.attr=123
    ,对吗

  • 见:

    owner
    始终是owner类,而
    instance
    是通过其访问属性的实例,或者在通过owner访问属性时为None

    使用
    owner
    的情况是创建一个classproperty:


    我遇到这个问题时也有类似的困惑,在我自己回答了这个问题之后,在这里报告我的发现似乎是明智的

    正如ThiefMaster已经指出的,“owner”参数可以进行类似
    类属性
    的构造。有时,您希望类将方法屏蔽为非方法属性,使用
    owner
    参数可以使用普通描述符实现这一点

    但这只是问题的一半。关于“只读”问题,我发现:

    我首先在这里找到了答案:。一开始我不明白,我花了大约五分钟的时间才把它团团转。最后说服我的是一个例子

    考虑最常见的描述符:
    属性
    。让我们使用一个简单的示例类,它有一个属性计数,它是变量计数被访问的次数

    class MyClass(object):
        def __init__(self):
            self._count = 0
        @property
        def count(self):
            tmp = self._count
            self._count += 1
            return tmp
        @count.setter
        def setcount(self):
            raise AttributeError('read-only attribute')
        @count.deleter
        def delcount(self):
            raise AttributeError('read-only attribute')
    
    正如我们已经建立的,
    \uuuu get\uuu
    函数的
    所有者
    参数意味着当您在类级别访问属性时,
    \uu get\uu
    函数会截取getattr调用。碰巧,
    属性
    的代码在类级别访问时很简单,但它可以做任何事情(比如返回一些静态值)

    现在,想象一下如果
    \uuuu set\uuu
    \uu del\uuu
    以同样的方式工作会发生什么。
    \uuuu set\uuuuu
    \uuuu del\uuuu
    方法将拦截除实例级别之外的类级别的所有
    setattr
    delattr
    调用

    因此,这意味着
    MyClass
    的“count”属性实际上是不可修改的。如果您习惯于使用静态编译语言(如Java)进行编程,这似乎不是很有趣,因为您无法修改应用程序代码中的类。但在Python中,您可以。类被视为对象,您可以动态分配它们的任何属性。例如,假设
    MyClass
    是第三方模块的一部分,
    MyClass
    几乎完全适合我们的应用程序(假设除了
    count
    的代码之外,还有其他代码),只是我们希望count方法的工作方式有所不同。相反,对于每个实例,我们希望它总是返回10。我们可以做到以下几点:

    >>> MyClass.count = 10
    >>> myinstance = MyClass()
    >>> myinstance.count
    10
    
    如果
    \uuuu set\uuuu
    截获了对
    setattr(MyClass,'count')
    的调用,那么就没有办法实际更改MyClass。相反,
    setcount
    的代码会截取它,并且不能对它做任何事情。唯一的解决方案是编辑MyClass的源代码。(我甚至不确定是否可以在子类中覆盖它,因为我认为在子类中定义它仍然会调用
    setattr
    代码。但我不确定,因为我们已经在处理一个反事实,所以我真的没有办法测试它。)

    现在,您可能会说,“这正是我想要的!我故意不想让我的用户重新分配我的类的属性!”对此,我只能说,您想要的是不可能使用幼稚的描述符,我将向您介绍上面的推理。允许重新分配类属性更符合当前的Python习惯用法


    如果你真的,真的想创建一个只读类属性,我不认为你能告诉你怎么做。但是如果有解决方案,可能需要使用元类,或者创建元类的
    属性
    ,或者为setattrdelattr修改元类的代码。但这是一种很深的魔法,远远超出了这个答案的范围(以及我自己在Python方面的能力)。

    所有者只是实例的类,是为了方便而提供的。您始终可以从实例计算它:

    owner = instance.__class__
    

    您可以尝试以下示例:

    # the descriptor protocol defines 3 methods:
    #    __get__()
    #    __set__()
    #    __delete__()
    
    # any class implementing any of the above methods is a descriptor
    # as in this class
    class Trace(object):
        def __init__(self, name):
            self.name = name
    
        def __get__(self, obj, objtype):
            print "GET:" + self.name + " = " + str(obj.__dict__[self.name])
            return obj.__dict__[self.name]
    
        def __set__(self, obj, value):
            obj.__dict__[self.name] = value
            print "SET:" + self.name + " = " + str(obj.__dict__[self.name])
    
    # define the attributes of your class (must derive from object)
    #  to be references to instances of a descriptor
    
    class Point(object):
    # NOTES:
    # 1. descriptor invoked by dotted attribute access:  A.x or a.x
    # 2. descripor reference must be stored in the class dict, not the instance dict
    # 3. descriptor not invoked by dictionary access: Point.__dict__['x']
    
        x = Trace("x")
        y = Trace("y")
    
        def __init__(self, x0, y0):
            self.x = x0
            self.y = y0
    
        def moveBy(self, dx, dy):
            self.x = self.x + dx     # attribute access does trigger descriptor
            self.y = self.y + dy
    
    
    # trace all getters and setters    
    p1 = Point(15, 25)
    p1.x = 20
    p1.y = 35
    result = p1.x
    p2 = Point(16, 26)
    p2.x = 30
    p2.moveBy(1, 1)
    

    就只读属性而言(见上面的讨论),下面的示例显示了它是如何完成的:

    ############################################################
    #
    #    descriptors
    #
    ############################################################
    
    # define a class where methods are invoked through properties
    class Point(object):
        def getX(self):
        print "getting x"
        return self._x
    
        def setX(self, value):
        print "setting x"
        self._x = value
    
        def delX(self):
        print "deleting x"
        del self._x
    
        x = property(getX, setX, delX)
    
    p = Point()
    p.x = 55    # calls setX
    a = p.x     # calls getX
    del p.x     # calls delX
    
    # using property decorator (read only attributes)
    class Foo(object):
        def __init__(self, x0, y0):
        self.__dict__["myX"] = x0
        self.__dict__["myY"] = y0
    
        @property
        def x(self):
        return self.myX
    
    f = Foo(4,6)
    print f.x
    try:
        f.x = 77        # fails: f.x is read-only
    except Exception,e:
        print e
    
  • \uuuuu set\uuuu
    方法应该更改实例的属性。但是,如果您想更改一个由所有实例共享并因此存在于类中的属性(例如,是类属性),该怎么办?只有在您有权访问该类(因此有owner参数)时才能执行此操作

  • 是的,如果通过类指定属性,则可以覆盖属性/描述符。这是经过设计的,因为Python是一种动态语言


  • 希望这能回答这个问题,尽管这个问题很久以前就被问到了。

    是的,我知道
    所有者是什么,但是我们如何使用这个
    所有者
    ?我看不出
    所有者存在的意义。我想你没有回答我的第二个问题。我的猜测是,描述符不应该写在类级别,而应该写在实例级别。事实上,我也这么认为,但找不到具体的证据。只有在实例上访问描述符时,这才是真的。如果在类上访问它,
    实例
    将是
    所有者
    wi
    ############################################################
    #
    #    descriptors
    #
    ############################################################
    
    # define a class where methods are invoked through properties
    class Point(object):
        def getX(self):
        print "getting x"
        return self._x
    
        def setX(self, value):
        print "setting x"
        self._x = value
    
        def delX(self):
        print "deleting x"
        del self._x
    
        x = property(getX, setX, delX)
    
    p = Point()
    p.x = 55    # calls setX
    a = p.x     # calls getX
    del p.x     # calls delX
    
    # using property decorator (read only attributes)
    class Foo(object):
        def __init__(self, x0, y0):
        self.__dict__["myX"] = x0
        self.__dict__["myY"] = y0
    
        @property
        def x(self):
        return self.myX
    
    f = Foo(4,6)
    print f.x
    try:
        f.x = 77        # fails: f.x is read-only
    except Exception,e:
        print e