Python @property及getter setter原理详解

1. Python @property原理

Python中的@property装饰器可以让一个类的实例属性变成只读或者读写的属性,它是通过把类的方法装饰成属性来实现的。使用@property的好处有以下三点:

简化代码逻辑,使属性的调用更加简单明了

保护属性不被外部直接更改

可根据属性的不同需求设计getter和setter方法,方便使用

1.1 @property实例

下面是一个简单的使用@property的例子:

class Temperature:

def __init__(self, temperature):

self._temperature = temperature

@property

def temperature(self):

return self._temperature

t = Temperature(50)

print(t.temperature) # 输出50

在这个例子中,我们定义了一个Temperature类,它有一个私有属性_temperature。由于这个属性是私有的,如果需要调用它,就需要编写getter方法,而使用@property可以省略这一步骤。temperature属性可以通过调用temperature()方法来得到,访问属性的形式更加简洁明了。

2. Python getter和setter方法的原理

在Python中,通过getter和setter方法可以对一个属性进行存取控制。

2.1 getter方法

所谓getter方法,就是定义一个方法用来获取属性的值。通过这个方法,我们可以在保证属性的私有性的同时,将属性的值传递给调用方。下面是一个例子:

class Student:

def __init__(self, name):

self._name = name

# 定义一个getter方法

def get_name(self):

return self._name

s = Student("小明")

print(s.get_name()) # 输出小明

在这个例子中,我们定义了一个Student类,并给它定义了一个私有属性_name。通过get_name()方法可以获取该属性的值。

2.2 setter方法

setter方法与getter方法是相对应的,它们都是用来对属性进行存取控制的。setter方法可以用来对属性进行赋值操作。下面是一个例子:

class Student:

def __init__(self, name):

self._name = name

# 定义一个getter方法

def get_name(self):

return self._name

# 定义一个setter方法

def set_name(self, name):

self._name = name

s = Student("小明")

s.set_name("小红")

print(s.get_name()) # 输出小红

在这个例子中,我们首先创建了一个Student实例,然后使用set_name()方法来为_name属性赋值。最后,使用get_name()方法来获取_name属性的值,输出结果为“小红”。

3. 使用@property和setter方法实现属性的读写和保护

使用@property和setter方法可以实现一个属性的只读和读写,同时还能保证该属性的私有性。

3.1 只读属性

对于只读属性,我们只需要定义一个getter方法即可。下面是一个例子:

class Circle:

def __init__(self, radius):

self._radius = radius

# 定义一个只读属性

@property

def radius(self):

return self._radius

c = Circle(5)

print(c.radius) # 输出5

c.radius = 10 # 这一步操作会报错

在这个例子中,我们定义了一个Circle类,该类只有一个半径属性,因为需要该属性只读,因此我们只定义了一个get_radius()方法,并使用@property装饰器来装饰。

3.2 读写属性

对于读写属性,我们需要同时定义getter和setter方法。下面是一个例子:

class Temperature:

def __init__(self, temperature):

self._temperature = temperature

# 定义一个读写属性

@property

def temperature(self):

return self._temperature

@temperature.setter

def temperature(self, value):

if value < -273.15:

raise ValueError("温度不能小于绝对零度!")

self._temperature = value

t = Temperature(50)

print(t.temperature) # 输出50

t.temperature = 100

print(t.temperature) # 输出100

t.temperature = -300 # 这一步操作会报错

在这个例子中,我们定义了一个Temperature类,并创建了一个温度属性。因为该属性是可以读写的,所以我们同时定义了一个temperature()方法和一个setter方法来完成该任务。在setter方法中,我们增加了一些规则来限制温度的范围。

4. getter和setter方法的使用场景

getter和setter方法是非常重要的控制属性访问的方法。在实际应用中,我们可以根据不同的需求编写通用的setter和getter方法。

4.1 数据验证

getter和setter方法可以用来验证用户输入的数据是否合法。下面是一个例子:

class Employee:

def __init__(self, name, age):

self._name = name

self._age = age

# 定义一个name属性,用来限制输入内容

@property

def name(self):

return self._name

@name.setter

def name(self, new_name):

if not isinstance(new_name, str):

raise TypeError("姓名必须是字符串类型")

self._name = new_name

e = Employee("小明", 20)

print(e.name) # 输出小明

e.name = 18 # 这一步操作会报错

在这个例子中,我们定义了一个Employee类,其中定义了一个name属性,该属性必须是字符串类型。在setter方法中,我们首先进行数据类型的判断,如果数据类型不符合要求,就会抛出一个自定义的异常。

4.2 保护私有属性

私有属性通常是指那些以“_”开头的变量,它们不能被直接访问。在Python中,我们可以通过getter和setter方法来访问私有属性,同时还能保证数据的安全性。下面是一个例子:

class Account:

def __init__(self, balance):

self._balance = balance

# 获取余额方法

def get_balance(self):

return self._balance

# 设置余额方法

def set_balance(self, new_balance):

if not isinstance(new_balance, (int, float)):

raise TypeError("余额必须是数字类型")

if new_balance < 0:

raise ValueError("余额不能小于0")

self._balance = new_balance

a = Account(1000)

print(a.get_balance()) # 输出1000

a.set_balance(-200) # 这一步操作会报错

在这个例子中,我们定义了一个Account类,它包含有一个私有变量_balance,该变量不能被直接访问。使用get_balance()方法可以获取balance的值。使用set_balance()方法可以设置balance变量的值。在setter方法中,我们对balance进行了一系列限制,以保证数据的安全性。

4.3 计算属性

有些属性的值并不是由用户直接输入的,而是需要通过其他属性的计算才能得到。在这种情况下,我们可以借助于getter方法来实现。下面是一个例子:

class Circle:

def __init__(self, radius):

self._radius = radius

# 定义radius属性,它是一个计算属性

@property

def radius(self):

return self._radius

# 周长属性的计算方法

@property

def circumference(self):

return 2 * Circle.pi * self.radius

# 定义一个pi属性

@property

def pi(self):

return 3.14

c = Circle(5)

print(c.circumference) # 输出31.4

在这个例子中,我们定义了一个Circle类,并定义了radius、circumference和pi属性。circumference属性是一个计算属性,它需要通过radius的值来计算,因此我们通过@property装饰器来实现它。在circumference属性的计算方法中,我们使用了pi属性来进行计算。因为pi属性也需要被访问到,所以我们也定义了一个getter方法用来实现它的计算。

后端开发标签