python @property、@.setter

python @property、@.setter

函数作为参数

b站:Python中各种@property、@xxx.setter、@classmethod、@staticmethod 都是些啥啊?

函数作为参数,可以传入函数,但是没写return的话,就会变成返回NoneType

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
def say():
print("something")

def func_1(func):
print("start")
func()
print("end")

func_1(say)
# 输出
start
something
end

但是由于func_1没有return,当执行的函数赋给一个变量时,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
my_func = func_1(say)
# 输出
start
something
end

# my_func 是一个class NoneType的对象
# 所以不能:
my_func()
# 输出
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

由于没有return,这个变量是一个NoneType类的对象。

my_func = func_1(say)这句话,我们希望的是拿到函数的引用,然后去用这个变量做其它事情,执行其它代码。

如何使得这个变量也是一个函数呢?!通过 定义内部方法,然后返回这个引用

1
2
3
4
5
6
7
8
9
def func_1(func):
def inner_func():
print("start")
func()
print("end")
return inner_func

my_func = func_1(say)
my_func()

因此,这里 func_1 是为了改变、优化传入进来的函数的执行结果。

内部的inner_func通常名字叫“wrapper”

Python中的@property、@xxx.setter

廖雪峰:使用@property

举例,一个检查分数,返回分数的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Student(object):

def get_score(self):
return self._score

def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

# 输出
>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!

用@后面添加一个要进行额外操作的方法名称。

能检查参数,又可以用类似属性这样简单的方式来访问类的变量。

Python内置的@property装饰器就是负责把一个方法变成属性调用的:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student(object):

@property
def score(self):
return self._score

@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

1
2
3
4
5
6
7
8
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!

注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。

chatgpt的回答:

Python 中的 property 是一个内置装饰器,它可以把一个类中的方法设置为属性的读取/设置/删除方法。

使用方法如下:

  1. 定义 getter 方法,返回需要作为属性读取的值。

    1
    2
    3
    4
    5
    6
    class Example:
    def __init__(self, value):
    self._value = value

    def get_value(self):
    return self._value
  2. 在 getter 方法上使用 @property 装饰器,将其标记为属性。

    1
    2
    3
    4
    5
    6
    7
    class Example:
    def __init__(self, value):
    self._value = value

    @property
    def value(self):
    return self._value
  3. 如果需要为属性提供写入操作,可以定义一个 setter 方法,并在该方法上使用 @property 名称的 setter 装饰器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Example:
    def __init__(self, value):
    self._value = value

    @property
    def value(self):
    return self._value

    @value.setter
    def value(self, value):
    self._value = value
  4. 如果需要为属性提供删除操作,可以定义一个 deleter 方法,并在该方法上使用 @property 名称的 deleter 装饰器。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class Example:
    def __init__(self, value):
    self._value = value

    @property
    def value(self):
    return self._value

    @value.setter
    def value(self, value):
    self._value = value

    @value.deleter
    def value(self):
    del self._value

然后,你可以使用如下语句来读取、写入和删除属性值:

1
2
3
4
example = Example(10)
print(example.value) # 读取属性值
example.value = 20 # 写入属性值
del example.value # 删除

b站:Python中各种@property、@xxx.setter、@classmethod、@staticmethod 都是些啥啊? 说得不好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class User:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, name):
if len(name) < 5:
raise Exception("至少5个字符")
self._name = name
@classmethod
def get_user(cls):
return (cls('people'))
@staticmethod
def lenght():
return 18

@property和@.setter搭配使用