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方法用来实现它的计算。