Python 3.x 修饰符意外地改变了Python中的构造函数行为

Python 3.x 修饰符意外地改变了Python中的构造函数行为,python-3.x,python-decorators,Python 3.x,Python Decorators,下面,我展示了一个更复杂代码的简化示例,但它完全代表了我遇到的问题 第1部分:这很好,没有问题: class Animal(): def __init__(self, animal_name = "no name given"): self.set_name(animal_name) def get_name(self): return self._animal_name def set_n

下面,我展示了一个更复杂代码的简化示例,但它完全代表了我遇到的问题

第1部分:这很好,没有问题:

class Animal():
    def __init__(self, animal_name = "no name given"):    
        self.set_name(animal_name) 
    
    def get_name(self):
        return self._animal_name
    
    def set_name(self, animal_name):
        self._animal_name = animal_name

class Dog(Animal):
    def __init__(self, dog_breed = "no breed", dog_name = "no name given"):
        self._dog_breed = dog_breed
        super().__init__(dog_name)
        
    def get_breed(self):
        print(self._dog_breed)

x = Dog('Greyhound', 'Rich')
第2部分:引入getter和setter装饰器后,代码停止工作:

class Animal():
    def __init__(self, animal_name = "no name given"):
        #THE LINE BELOW SEEMS TO CAUSE AN ISSUE
        self.name(animal_name)
    
    @property
    def name(self):
        return self._animal_name
    
    @name.setter
    def name(self, animal_name):
        self._animal_name = animal_name

class Dog(Animal):
    def __init__(self, dog_breed = "no breed", dog_name = "no name given"):
        self._dog_breed = dog_breed
        super().__init__(dog_name)
        
    def get_breed(self):
        print(self._dog_breed)

x = Dog('Greyhound', 'Rich')
输出:AttributeError:“Dog”对象没有属性“\u animal\u name”

当我在第2部分中保留decorators,但将Animal类中的构造函数更改为:

class Animal():
    def __init__(self, animal_name = "no name given"):
        self._animal_name=animal_name
它起作用了


我只是好奇为什么它在上面第2部分的例子中不起作用?

简短回答:

线路

self.name(animal_name)
可分为两部分:

tmp = self.name
tmp(animal_name)
首先,
self.name
调用getter,结果作为函数处理。getter使用
返回self.\u animal\u name
并且由于从未调用setter,因此会发生相应的错误

长答案:

让我们学习以下课程:

class Animal:
    def __init__(self, animal_name):
        self.name(animal_name)

    @property
    def name(self):
        return self._animal_name

    @name.setter
    def name(self, animal_name):
        self._animal_name = animal_name
要了解线路是什么

self.name(animal_name)
事实上,你首先需要了解装饰师

代码

@dec
def func(a, b, ...):
    [...]
相当于

def func_impl(a, b, ...):
    [...]
func = dec(func_impl)
self.get_name()(animal_name)
(除非您不能直接调用
func_impl
)。有关更多信息,请参见

这意味着您可以从上面编写
Animal
类,而无需使用decorator:

class Animal:
    def __init__(self, animal_name):
        self.name(animal_name)

    def get_name(self):
        return self._animal_name
    name = property(get_name)

    def set_name(self, animal_name):
        self._animal_name = animal_name
    name = name.setter(set_name)
为了理解这段代码,您需要理解内置的
属性
,它是一个类。有关详细信息,请参阅

name=property(get\u name)
创建类型为
property
的对象。检索属性值时,将调用
get\u name

name=name.setter(set\u name)
首先调用
name.setter(set\u name)
,创建属性的副本,然后用此副本覆盖
name
。为副本赋值时,调用
set\u name

总之,
name
是一个类型为
property
的对象,它使用
get\u name
作为getter,使用
set\u name
作为setter

这有什么帮助?

您需要了解这一点:
name
不是一个函数。这是一种财产。它是不可调用的

有问题的路线

self.name(animal_name)
实际上相当于

def func_impl(a, b, ...):
    [...]
func = dec(func_impl)
self.get_name()(animal_name)

这解释了错误消息:构造函数调用getter,getter尝试使用
返回self.\u animal\u name
。但是由于setter还没有被调用,
self.\u animal\u name
还没有被设置。

如果您使用
self.name=animal\u name
而不是
self.name(animal\u name)
,它会起作用吗?是的,这就解决了问题。因此,当我使用decorators时,我需要将类中的getter和setter方法视为一个属性,即使在类构造函数中也是如此:我现在就知道了。非常感谢。