文章目录
  1. 1. 概述
  2. 2. @property装饰器
    1. 2.1. property()函数
    2. 2.2. @property装饰器
  3. 3. @classmethod装饰器
  4. 4. @staticmethod装饰器
  5. 5. @classmethod vs @staticmethod
  6. 6. 参考

概述

在Python中,装饰器是随处可见的,并且装饰器也是很有用的一种语法糖。

本篇文章主要介绍Python类中常见的几个内建装饰器。

@property装饰器

在面向对象中,为类的属性创建getterssetters通常被认为是最佳实践。许多语言允许通过不同的方法实现getterssetters,或许是通过使用函数,或许是通过语言特有的getset构造函数。

在Python中,通过使用@property装饰器来实现getterssetters

property()函数

除了@property装饰器,property()函数也可以在Python中是getterssetters

下面定义了一个包含gettersetter方法的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Persone:
def __init__(self, name='Jim Green'):
self.__name = name

def getname(self):
return self.__name

def setname(self, name):
self.__name = name


person = Persone()
print(person.getname())

person.setname('David')
print(person.getname())

输出:

Jim Green
David

从输出可以看出,getname()方法返回了__name属性的值,setname()方法设置了__name属性的值。但是,如果在修改和获取__name属性的时候,能隐式的调用settergetter方法,就会方便很多。在Python中,提供了propterty()函数达到这种目的。

Python中property()方法提供了一个访问实例属性的接口,property()方法将get, ‘set’, delete方法作为参数,返回一个属性(property)类的对象。

下面为类增加一个property()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Persone:
def __init__(self, name='Jim Green'):
self.__name = name

def getname(self):
print('getname()...called')
return self.__name

def setname(self, name):
print('setname()...called')
self.__name = name

name = property(getname, setname)

在上面的例子中,property(getname, setname)返回了一个属性对象,并赋值给了namename属性隐藏了对象的私有属性__namename属性可以被直接访问,但是隐式调用了setname()getname()方法。

除了gettersetter,还可以为属性设置个del方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Person:
def __init__(self, name='Jim Green'):
self._name = name

def getname(self):
print('getname()...called')
return self._name

def setname(self, name):
print('setname()...called')
self._name = name

def delname(self):
print('delname()...called')
del self._name

name = property(getname, setname, delname)


person = Person('Hi')
print(person.name)

person.name = 'David'
print(person.name)

del person.name

输出:

getname()...called
Hi
setname()...called
getname()...called
David
delname()...called

@property装饰器

相比property()函数,@property装饰器提供了一种简单的方法来定义gettersetter

@property装饰器是Python内建的装饰器。

下面的代码使用了@property装饰器为类定义了gettersetter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Person:
def __init__(self, name="Jim"):
self.__name = name

@property
def name(self):
print('call name with property()')
return self.__name + 'Hi'

@name.setter
def name(self, name):
print('call setter')
self.__name = name

@name.deleter
def name(self):
print('call deleter')
del self.__name


person = Person('Davi')
print(person.name)

person.name = 'Jim'
print(person.name)

del person.name

输出:
call name with property()
Davi Hi
call setter
call name with property()
Jim Hi
call deleter

使用property()或者@property为类设置属性的好处有以下几点:

  • 校验: 在设置类内部属性之前,可以对传入的值进行校验,只有当满足条件后,才能设置属性,如果不满足条件,则抛出错误。
  • 懒加载: 资源可以被延迟加载,只有当真正使用的时候才被加载,可以节省时间和资源。
  • 抽象: getter和setter可以对类内部数据的真正表示进行抽象,如上面的例子,调用name返回的其实是拼接出来的数据,并不是__name属性真正的值。

@classmethod装饰器

@classmethod装饰器可以被用在任何一个类方法上,它允许我们使用类名直接调用方法,而不用先创建一个对象。

@classmethod装饰器装饰的方法,第一参数不是self, 而是cls, 代表类本身。

@classmethod装饰器使用方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person:
total = 0

def __init__(self):
Person.total = Person.total + 1

@classmethod
def showTotal(cls):
print(f'Total: {cls.total}')


person1 = Person()
Person.showTotal()

person2 = Person()
Person.showTotal()

输出:

Total: 1
Total: 2

@classmethod装饰器装饰的方法,除了可以通过类名直接调用,也可以通过对象调用。

@staticmethod装饰器

@staticmethod同样是Python内建的装饰器,该装饰器在Python类中用来定义静态方法。

静态方法在被类实例或者类自身调用时,不接受任何参数。

@staticmethod使用方法如下:

1
2
3
4
class person:
@staticmethod
def greet():
print("Hello!")

同样的,静态方法同时支持被类名和类实例调用。

@classmethod vs @staticmethod

  • classmethod将cls作为第一个参数,而staticmethod不需要
  • classmethod可以访问和修改类状态,staticmethod不能
  • 通常会使用classmethod创建工厂方法。工厂方法会返回类对象。
  • 通常会使用staticmethod创建工具函数。

参考