为什么在__init__函数中声明描述符类会破坏描述符功能?

时间:2021-01-12 18:21:30

In class B below I wanted the __set__ function in class A to be called whenever you assign a value to B().a . Instead, setting a value to B().a overwrites B().a with the value. Class C assigning to C().a works correctly, but I wanted to have a separate instance of A for each user class, i.e. I don't want changing 'a' in one instance of C() to change 'a' in all other instances. I wrote a couple of tests to help illustrate the problem. Can you help me define a class that will pass both test1 and test2?

在下面的B类中,每当你为B()赋值时,我都希望调用A类中的__set__函数。而是将值设置为B()。a用值覆盖B()。a。分配给C()。a的C类工作正常,但我想为每个用户类分别设置一个A实例,即我不想在C()的一个实例中更改'a'来改变'a'in所有其他情况。我写了几个测试来帮助说明问题。你能帮我定一个会传递test1和test2的类吗?

class A(object):
    def __set__(self, instance, value):
        print "__set__ called: ", value

class B(object):
    def __init__(self):
        self.a = A()

class C(object):
    a = A()

def test1( class_in ):
    o = class_in()
    o.a = "test"
    if isinstance(o.a, A):
        print "pass"
    else:
        print "fail"

def test2( class_in ):
    o1, o2 = class_in(), class_in()
    if o1.a is o2.a:
        print "fail"
    else:
        print "pass"

3 个解决方案

#1


Accordingly to the documentation:

根据文件:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in the class dictionary of another new-style class, known as the owner class. In the examples below, “the attribute” refers to the attribute whose name is the key of the property in the owner class’ __dict__. Descriptors can only be implemented as new-style classes themselves.

以下方法仅适用于包含该方法的类的实例(所谓的描述符类)出现在另一个新样式类的类字典中,称为所有者类。在下面的示例中,“属性”是指属性,其名称是所有者类'__dict__中属性的键。描述符只能作为新式类本身实现。

So you can't have descriptors on instances.

所以你不能在实例上有描述符。

However, since the descriptor gets a ref to the instance being used to access it, just use that as a key to storing state and you can have different behavior depending on the instance.

但是,由于描述符获取了用于访问它的实例的ref,因此只需将其用作存储状态的键,您可以根据实例使用不同的行为。

#2


Here's a class that can pass the original tests, but don't try using it in most situations. it fails the isinstance test on itself!

这是一个可以通过原始测试的类,但在大多数情况下不要尝试使用它。它没有通过isinstance测试本身!

class E(object):
    def __new__(cls, state):
        class E(object):
            a = A(state)
            def __init__(self, state):
                self.state = state
        return E(state)

#>>> isinstance(E(1), E)
#False

#3


I was bitten by a similar issue in that I wanted to class objects with attributes governed by a descriptor. When I did this, I noticed that the attributes were being overwritten in all of the objects such that they weren't individual.

我被一个类似的问题所困扰,因为我想用具有描述符的属性对象进行分类。当我这样做时,我注意到所有对象中的属性都被覆盖,因此它们不是个体。

I raised a SO question and the resultant answer is here: class attribute changing value for no reason

我提出了一个SO问题,结果答案就在这里:类属性无缘无故改变值

A good document link discussing descriptors is here: http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/

讨论描述符的好文档链接在这里:http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/

An example descriptor from the aforementioned link is below:

上述链接的示例描述符如下:

class Numberise(object):
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        if self.name not in instance.__dict__:
            raise (AttributeError, self.name)
        return '%o'%(instance.__dict__[self.name])

    def __set__(self, instance, value):
        print ('setting value to: %d'%value)
        instance.__dict__[self.name] = value

#1


Accordingly to the documentation:

根据文件:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in the class dictionary of another new-style class, known as the owner class. In the examples below, “the attribute” refers to the attribute whose name is the key of the property in the owner class’ __dict__. Descriptors can only be implemented as new-style classes themselves.

以下方法仅适用于包含该方法的类的实例(所谓的描述符类)出现在另一个新样式类的类字典中,称为所有者类。在下面的示例中,“属性”是指属性,其名称是所有者类'__dict__中属性的键。描述符只能作为新式类本身实现。

So you can't have descriptors on instances.

所以你不能在实例上有描述符。

However, since the descriptor gets a ref to the instance being used to access it, just use that as a key to storing state and you can have different behavior depending on the instance.

但是,由于描述符获取了用于访问它的实例的ref,因此只需将其用作存储状态的键,您可以根据实例使用不同的行为。

#2


Here's a class that can pass the original tests, but don't try using it in most situations. it fails the isinstance test on itself!

这是一个可以通过原始测试的类,但在大多数情况下不要尝试使用它。它没有通过isinstance测试本身!

class E(object):
    def __new__(cls, state):
        class E(object):
            a = A(state)
            def __init__(self, state):
                self.state = state
        return E(state)

#>>> isinstance(E(1), E)
#False

#3


I was bitten by a similar issue in that I wanted to class objects with attributes governed by a descriptor. When I did this, I noticed that the attributes were being overwritten in all of the objects such that they weren't individual.

我被一个类似的问题所困扰,因为我想用具有描述符的属性对象进行分类。当我这样做时,我注意到所有对象中的属性都被覆盖,因此它们不是个体。

I raised a SO question and the resultant answer is here: class attribute changing value for no reason

我提出了一个SO问题,结果答案就在这里:类属性无缘无故改变值

A good document link discussing descriptors is here: http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/

讨论描述符的好文档链接在这里:http://martyalchin.com/2007/nov/24/python-descriptors-part-2-of-2/

An example descriptor from the aforementioned link is below:

上述链接的示例描述符如下:

class Numberise(object):
    def __init__(self, name):
        self.name = name

    def __get__(self, instance, owner):
        if self.name not in instance.__dict__:
            raise (AttributeError, self.name)
        return '%o'%(instance.__dict__[self.name])

    def __set__(self, instance, value):
        print ('setting value to: %d'%value)
        instance.__dict__[self.name] = value