1. Python访问限制
Python是一门动态语言,没有像Java和C++等语言中的private、protected、public等关键字来控制变量和方法的访问权限。这使得Python的代码更加灵活,但也让程序的安全性和可维护性变得更加重要。
1.1 面向对象编程中的访问限制
在面向对象编程中,类的封装性是一个很重要的概念。在Python中,我们可以使用以下方式对类的属性和方法进行访问限制:
将属性名或方法名前加上单下划线(_):这表示这是一个内部使用的属性或方法,供类自己内部使用,不建议从外部直接访问;
将属性名或方法名前加上双下划线(__):这表示这是一个私有属性或方法,不能从外部直接访问。
下面是一个示例类:
class Person:
def __init__(self, name, age):
self.name = name
self._age = age
self.__weight = 60
def speak(self):
print("{0} is speaking".format(self.name))
在这个示例中,我们定义了一个Person类,它有三个属性:name、_age和__weight,以及一个方法speak。在这个类中,name和_age是可以从外部直接访问的,但是_weight是私有属性,不能直接访问。
如果我们尝试从外部访问_weight属性,Python会报错:
p = Person("Alice", 20)
print(p.__weight)
这会输出以下错误:
AttributeError: 'Person' object has no attribute '__weight'
这是因为Python在解释__weight属性时,会将其名字变形为_类名__weight的形式,这是为了防止子类中的命名冲突。如果我们改用这个形式的名字来访问这个属性,是可以访问到的:
print(p._Person__weight)
这会输出60,表示我们成功访问了这个私有属性。
1.2 使用@property实现属性的访问限制
除了上述方法外,Python还提供了@property装饰器来帮助我们实现对属性的更加灵活的控制。
假设我们有一个学生类,它包括姓名、年龄和成绩三个属性:
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
现在我们要对成绩属性进行访问限制,使得它只能是0-100的整数,否则抛出异常。这时,我们可以使用@property装饰器和对应的setter装饰器:
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.__score = score
@property
def score(self):
return self.__score
@score.setter
def score(self, score):
if not isinstance(score, int):
raise TypeError('Score must be an integer')
if score < 0 or score > 100:
raise ValueError('Score must be between 0 and 100')
self.__score = score
在这个示例中,我们将score属性变为私有属性__score,并同时定义了一个score的getter方法和一个setter方法。
getter方法使用@property装饰器来标记,这表示我们可以通过类的实例对象直接访问score属性,但实际上这个属性是通过调用getter方法来实现的。
setter方法使用@score.setter装饰器来标记,这表示我们可以通过类的实例对象直接对score属性进行赋值,但实际上这个赋值操作是通过调用setter方法来实现的。
这样,我们就可以限制score属性的取值范围,以保证程序的正确性和安全性。如果我们尝试将score属性的值设为一个非整数的值,会抛出TypeError异常:
s = Student('Alice', 20, 90)
s.score = 95.5 # 这会抛出TypeError异常
如果将score属性的值设置成一个超出0-100范围的整数,会抛出ValueError异常:
s = Student('Alice', 20, 90)
s.score = 120 # 这会抛出ValueError异常
1.3 总结
Python中的访问限制机制有两种:一种是在类的属性名或方法名前加上单下划线或双下划线来表示内部使用或私有属性/方法;另一种是通过@property装饰器和setter方法来对属性的取值范围进行限制。
使用这些方法可以有效保护程序的安全性和可维护性,使得我们可以更加灵活地控制类的封装性。