python封装是什么意思
Python中的封装是面向对象编程中最重要的概念之一。简单地说,封装是将数据和代码组合到一个单元中,以便可以隐藏它们,实现对外接口的保护和控制,从而确保了程序的正确性和安全性。
封装在Python中的实现方式主要有两种:访问限制和属性装饰器。接下来,我将分别介绍这两种方式的实现方法以及其优缺点。
一、访问限制
访问限制是Python中最基本的封装方式。通过将属性或方法定义为私有的或保护的,从而限制了对这些属性和方法的直接访问,只能通过类提供的接口来访问。
1. 私有属性和方法
在Python中,可以通过将属性或方法的名称前面加上双下划线来定义私有属性或方法。这样一来,这些属性或方法就不能被直接访问,只能在类内部进行访问。
例如:
class Student:
def __init__(self, name, age):
self.__name = name
self.__age = age
def study(self):
print('I am studying...')
s = Student('Bob', 18)
print(s.__name) # 错误,无法直接访问私有属性
这里,我们定义了一个Student类,其中包含了两个私有属性__name和__age和一个普通方法study。在类外部,我们尝试直接访问私有属性__name,但会报错。但是,我们还是可以通过类提供的接口来访问这些私有属性和方法。
例如:
class Student:
def __init__(self, name, age):
self.__name = name
self.__age = age
def study(self):
print('I am studying...')
def get_name(self):
return self.__name
def set_age(self, age):
if age < 0 or age > 100:
print('Age is invalid!')
else:
self.__age = age
s = Student('Bob', 18)
print(s.get_name()) # Bob
s.set_age(-1) # Age is invalid!
s.set_age(101) # Age is invalid!
s.set_age(20)
print(s.__age) # 错误,无法直接访问私有属性
print(s.get_age()) # 错误,无法直接访问私有属性
在类内部,我们可以正常地访问私有属性和方法。在类外部,我们通过类提供的接口来访问这些私有属性和方法。例如,我们通过get_name()和set_age()方法来访问私有属性__name和__age。这样,我们就能够对属性进行必要的保护,确保数据的正确性和安全性。
2. 保护属性和方法
在Python中,同样可以通过将属性或方法的名称前面加上单下划线来定义保护属性或方法。这样一来,这些属性或方法仍然可以被访问,但是建议在类的子类内部或模块内部使用,而不是在类的外部直接访问。
例如:
class Student:
def __init__(self, name, age):
self._name = name
self._age = age
def study(self):
print('I am studying...')
def get_name(self):
return self._name
def set_age(self, age):
if age < 0 or age > 100:
print('Age is invalid!')
else:
self._age = age
s = Student('Bob', 18)
print(s._name) # Bob,但不建议在类的外部直接访问该保护属性
s.set_age(-1) # Age is invalid!
s.set_age(101) # Age is invalid!
s.set_age(20)
print(s._age) # 20,但不建议在类的外部直接访问该保护属性
在这个例子中,我们定义了一个Student类,其中包含了两个保护属性_name和_age和一个普通方法study。在类外部,我们可以直接访问这些保护属性,但并不建议这样使用。在类内部,我们依然要使用get_name()和set_age()方法来访问这些保护属性或方法。
二、属性装饰器
Python中的另一种封装方式是属性装饰器。属性装饰器可以帮助我们直接访问属性值,同时也可以在访问属性时进行一些逻辑上的处理。属性装饰器的实现方法主要有@property和@<属性名>.setter两种。
1. @property装饰器
@property装饰器可以将一个方法变成一个只读属性,直接访问该属性时,实际上是调用了这个方法并返回其结果。
例如:
class Student:
def __init__(self, name, age):
self._name = name
self._age = age
def study(self):
print('I am studying...')
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age < 0 or age > 100:
print('Age is invalid!')
else:
self._age = age
s = Student('Bob', 18)
print(s.name) # Bob
print(s.age) # 18
s.age = -1 # Age is invalid!
s.age = 101 # Age is invalid!
s.age = 20
print(s.age) # 20
这里,我们定义了一个Student类,其中包含了两个保护属性_name和_age和一个普通方法study。通过@property装饰器,我们将两个方法name和age都变成了只读属性。在类外部,我们直接访问name和age属性时,实际上是调用了这两个方法并返回其结果。此外,我们还使用了@property装饰器和<属性名>.setter来定义可写属性age。这样一来,我们就能够对属性进行必要的保护,并在属性赋值时进行一些逻辑上的处理。
2. @<属性名>.setter装饰器
除了@property装饰器外,我们还可以使用@<属性名>.setter装饰器将一个方法变成可写属性。通过这种方式,我们可以在属性被赋值时进行一些逻辑上的处理,例如进行参数的检查、转化等操作。
例如:
class Student:
def __init__(self, name, age):
self._name = name
self._age = age
def study(self):
print('I am studying...')
@property
def name(self):
return self._name
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age < 0 or age > 100:
print('Age is invalid!')
else:
self._age = age
@name.setter
def name(self, name):
if len(name) < 3:
print('Name is too short!')
else:
self._name = name
s = Student('Bob', 18)
print(s.name) # Bob
print(s.age) # 18
s.age = -1 # Age is invalid!
s.age = 101 # Age is invalid!
s.age = 20
print(s.age) # 20
s.name = 'Bo' # Name is too short!
s.name = 'Alice'
print(s.name) # Alice
在这个例子中,我们定义了一个Student类,其中包含了两个保护属性_name和_age和一个普通方法study。通过@property和@<属性名>.setter装饰器,我们将两个方法name和age都变成了可读、可写属性。在这两个方法中,我们分别对属性是否符合某些规则进行了判断。如果不符合,我们
