关于在子类中扩展属性的问题

huangapple go评论78阅读模式
英文:

Question about extending a property in a sub class

问题

I am working through the O'Reilly Python Cookbook.

I have a question about the following code, to do with extending a property in a sub class:

class Person:
    def __init__(self, name):
        self.name = name

    # Getter function
    @property
    def name(self):
        return self._name

    # Setter function
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value

    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")

class SubPerson(Person):
    @property
    def name(self):
        print('Getting name')
        return super().name

    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson, SubPerson).name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson, SubPerson).name.__delete__(self)

I'm confused about:

super(SubPerson, SubPerson).name.__set__(self, value)

With super(SubPerson, SubPerson), it seems to be accessing the method as a class variable. Why can't it access the method as an instance variable instead?

Also, how does __set__ and @name.setter relate to one another? Aren't they effectively the same thing?

Could the same line be written as:

super(SubPerson, SubPerson).name.settr(self, value)
英文:

I am working through the O Reilly Python Cookbook.

I have a question about the following code, to do with extending a property in a sub class:

class Person:
    def __init__(self, name):
        self.name = name

    # Getter function
    @property
    def name(self):
        return self._name

    # Setter function
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value

    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")

class SubPerson(Person):
    @property
    def name(self):
        print('Getting name')
        return super().name

    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson, SubPerson).name.__set__(self, value)

    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson, SubPerson).name.__delete__(self)

I'm confused about:

super(SubPerson, SubPerson).name.__set__(self, value)

With super(SubPerson,SubPerson) it seems to be accessing the method as a class variable, why cant it access the method as an instance variable instead?

Also, how does set and @name.setter relate to one another? Aren't they effectively the same thing?

Could the same line be written as:

super(SubPerson, SubPerson).name.settr(self,value)

答案1

得分: 1

第一个问题涉及到 super(SubPerson, SubPerson)。这只是一种访问实际的 property 对象的技巧,该对象是类的属性之一。在这里需要的是 Person.name,因为一旦我们有了它,就可以使用属性的设置器和删除器函数。使用 super().name 或任何实例类型的访问存在问题,因为 super() 不会返回一个对象,而是返回一个代理。代理上的属性名称只会提供对获取器的访问。

第二个问题涉及到 @name.setter。事实上,property 作为初始装饰器将 name 定义为一个属性对象。属性的 setter 属性也是一个装饰器,它在其对象上设置了设置器函数并返回该对象。这意味着它只能在类定义时使用。实际上,@name.setter 块大致相当于在类定义后的以下代码:

def foo(self, value):
    ...
SubPerson.name = SubPerson.name.setter(foo)

您想要使用的方法是属性的 fset 属性。这意味着设置器部分可以这样编写:

@name.setter
def name(self, value):
    print('Setting name to', value)
    super(SubPerson, SubPerson).name.fset(self, value)
英文:

There are two questions here.

First is about super(SubPerson, SubPerson). It is just a trick to access the actual property object which is an attribute of the class. What is wanted here is Person.name, because once we have it, we can use the setter and deleter functions of the property. The problem with super().name or with any instance type access is that super() does not return an object but a proxy. And the property name on the proxy will only give access to the getter.

The latter is about @name.setter. In fact property as the initial decorator defines name as a property object. The setter attribute of a property is also a decorator that sets the setter function on its object and returns the object. That means that it is only intented to be used at class definition time. In fact the @name.setter bloc is roughly equivalent to the following code after the class definition:

def foo(self, value):
    ...
SubPerson.name = SubPerson.name.setter(foo)

The method that you wanted to use is the fset attribute of the property. That means that the setter part could have been written as :

@name.setter
def name(self, value):
    print('Setting name to', value)
    super(SubPerson, SubPerson).name.fset(self, value)

huangapple
  • 本文由 发表于 2020年1月6日 17:41:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/59609750.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定