前言
养成一个好的习惯只需要坚持21天,Day9
访问限制
由上一节定义的Student类来看,我们可以在外部代码修改name、score属性。比如我们想要修改对象的成绩,可以直接对score
赋值。
bart.score = 60
print(bart.score)
# 60
如果要让内部的属性不被外部访问和修改,我们可以在属性的名称前面加上两个下划线__
,这样就变成了一个私有对象,只有内部可以访问,外部不可以访问。即在外部即不能访问也不能进行修改。
class Student(object):
def __init__(self,name,score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
bart = Student('Bart Simpon',99)
在外部访问实例变量的属性:
bart.__name
# ---------------------------------------------------------------------------
# AttributeError Traceback (most recent call last)
# <ipython-input-2-b54cbc8ec6d2> in <module>()
# ----> 1 bart.__name
#AttributeError: 'Student' object has no attribute '__name'
这样确保了外部代码不能随便的改变对象内部的状态,如果在限制访问的同时想要允许外部代码进行访问或者修改的话,就可以给类增加get
和set
方法。
class Student(object):
...
# get方法,获取对象的name、score属性
def get_name(self):
return self.__name
def get_score(self):
return self.score
# set方法,改变对象的name、score属性
def set_name(self,name):
self.__name = name
def set_score(self,score):
if 0 <=score<= 100:
self.__score = score
else:
raise ValueError('bad score')
在Python中,类似__xxx__
的变量是特殊变量,特殊变量在外部是可以访问的,不是私有变量。有时候我们会看到一个下划线开头的变量名,比如_name
,这样命名的意思是“虽然我可以被访问,但是请把我视为私有变量,不要随意访问。”
双线划线开头的变量也不是一定不能访问,而是不能直接访问,如果使用baer._Student__name
来访问也可以等到name
变量。
bart._Student__name
# 'Bart Simpson'
练习
请把下面的Student对象的gender字段对外隐藏起来,用get_gender()和set_gender()代替,并检查参数有效性:
class Student(object):
def __init__(self, name, gender):
self.name = name
self.__gender = gender
def get_gender(self):
return self.__gender
def set_gender(self,gender):
if gender in ('male','female'):
self.__gender = gender
else:
raise ValueError('bad gender')
# 测试:
bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
print('测试失败!')
else:
bart.set_gender('female')
if bart.get_gender() != 'female':
print('测试失败!')
else:
print('测试成功!')
# 测试成功!
继承和多态
在OOP程序设计中,当我们定义一个class类时,我们可以从已有的class继承,新的class类成为子类(Subclass),原有的class称为父类(Base class)。
首先,我们编写一个animal
类,使用run()
方法直接打印:
class Animal(object):
def run(self):
print('Animal is running...')
继续编写Dog
和Cat
类时,就可以直接从Animal
类继承,把Animal
写在类名后面的括号里,就代表Dog
继承Animal
类,Cat
同理:
class Dog(Animal):
pass
class Cat(Animal):
pass
继承之后,子类获得了父类的全部功能。在此处,Dog
和Cat
类就继承了Animal
类的run()
方法。
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# Animal is running...
# Animal is running...
接着对子类增加一些方法:
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
对子类增加方法后执行:
dog = Dog()
dog.run()
cat = Cat()
cat.run()
# Dog is running...
# Cat is running...
虽然子类继承的父类中也有run()
方法,但是子类的run()
覆盖了父类的run()
,这就是继承的多态表现。要判断一个变量是否是某个类型可以使用isinstance()
判断:
b = Dog()
isinstance(b,Dog)
# true