关于python:为什么Class property.setter不是方法重载的情况?

Why is Class property.setter not a case of method overloading?

方法重载在Python中是不可能的!您能解释一下为什么Python中的Properties.setter不是方法重载的情况吗?

1
2
3
4
5
6
7
8
9
class newOne():
    def __init__(self):
            self.__x = 0
    @property
    def val(self):
            return self.__x
    @val.setter
    def val(self,value):
            self.__x = value

在上面的代码中,我有两个名为"val"(但参数集不同)的方法,它们的行为都不同。


这不是方法重载,因为没有两个具有不同签名的方法可以调用。如果是方法重载,可以这样做:

1
2
3
4
obj = newOne()

print(obj.val())
obj.val(5)

但这不起作用,因为val是一个属性,而不是重载方法。

那那里发生了什么?为什么我们要用相同的名称定义两个方法,如果不重载它们会发生什么?

魔法发生在装饰工身上。作为前提条件,你必须知道

1
2
3
@deco
def func(...):
    ...

等于

1
2
3
4
def func(...):
    ...

func = deco(func)

因此,首先发生的事情是@property修饰器将getter函数转换为一个属性,该函数作为getter函数:

1
2
3
4
5
6
7
8
9
10
class newOne:
    @property
    def val(self):
        return self.__x

print(newOne.val)
print(newOne.val.fget)
# output:
# <property object at 0x002B1F00>
# <function newOne.val at 0x0052EAE0>

在此之后,@val.setter装饰器使用getter和setter函数创建一个新属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class newOne:
    @property
    def val(self):
        return self.__x

    @val.setter
    def val(self, value):
        self.__x = value

print(newOne.val)
print(newOne.val.fget)
print(newOne.val.fset)
# output:
# <property object at 0x0221B7B0>
# <function newOne.val at 0x0226EB70>
# <function newOne.val at 0x0226EAE0>

(getter和setter函数具有相同的名称,因为它们都被定义为def val(...),但它们仍然是不同的函数。所以他们有不同的身份证。)

所以最后,您有一个带有getter和setter函数的val属性。您没有重载方法。

有关属性如何工作以及如何调用getter和setter函数的详细信息,请参阅描述符文档。


首先,@property修饰器创建一个名为val的描述符,并将其放在一边,以便在定义类后将其添加到类中。然后,@val.setter修饰了它的函数,并简单地将它的引用添加到val描述符中。

您的代码大致相当于

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
d = {}

def __init__(self):
    self.__x = 0

d['__init__'] = __init__

def val(self):
    return self.__x

d['val'] = property(val)

def val(self, value):
    self.__x = value

# Not d['val'].__set__ = val, as previously stated
d['val'] = property(fget=d['val'], fset=val)

newOne = type('newOne', (object,), d)

# These are all"local" to, or part of the implementation of,
# the class statement, so they don't stick around in the current
# namespace.
del __init__, val, d  # These are all"local" to or part of the imple