第十一天
上次已经简单说了Python面向对象编程,其实大多数面向对象编程语言Java、C#等都具备 3 个典型特征,即封装、继承和多态。今天我们来简单说下面Python向对象中的三大特性:封装、继承和多态。
1、封装
我们需要先理解什么是封装,其实封装在我们生活中随处可见。比如说空调,对于空调来说可以加热、制冷、抽风...但是对于用户而言,不需要知道这些功能在内部是如何实现的,我们要做的就是当需要某项功能的时候,选择对应的功能键即可实现对应的功能就可以了,这就是封装的具体实现。
1.1、编程中的封装
编程中的封装其实就是在设计类时,将一些属性和方法隐藏在类的内部,这样在使用此类时,将无法直接以类对象.属性名访问属性或者通过类对象.方法名(参数)的形式调用这些属性或方法,而只能用未隐藏的类方法间接操作这些隐藏的属性和方法。简而言之就是隐藏对象的属性和实现细节,仅对外提供公共访问方式。
分析如下代码:
class Student():
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self): #类似Java、C#中的toString方法,方便输出查看
return ('我的名字是%s,今年%d碎了'%(self.name,self.age))
if __name__ == '__main__':
stu1 = Student('张三',200)
print(stu1)
上述传递的参数age明显是不合适的,这个时候我们就需要使用封装的思想来优化我们的代码了。
1.2、Python中的封装
Python和其它面向对象的编程语言Java、C#等不同,Python 并没有提供 public公共的、private私有的等这些修饰符。但是Python也有自己的一套方案,就是:
1、默认情况下,Python 类中的变量和方法都是公有(public)的,它们的名称前都没有下划线,类似public,在类的外部、类内部以及子类均可以访问;
2、如果类中的变量和函数,其名称以双下划线“_”开头,则该变量/函数为私有变量/私有函数,类似private,只能在本类内部使用,类的外部以及子类都无法使用。
class Student():
def getname(self,name):
return self.name
def setname(self,name):
self.name = name
def getage(self,age):
return self.__age
def setage(self,age):
if age > 150:
raise ValueError('年龄不符合自然规则')
self.__age = age
def __str__(self): #类似Java、C#中的toString方法,方便输出查看
return ('我的名字是%s,今年%d岁了'%(self.name,self.__age))
if __name__ == '__main__':
stu1 = Student()
stu1.setage(100)
stu1.name = '张三'
print(stu1)
#name不是私有的,age是私有的
其实这种封装机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:类名_属性
class Student():
def getname(self,name):
return self.name
def setname(self,name):
self.name = name
def getage(self,age):
return self.__age
def setage(self,age):
if age > 150:
raise ValueError('年龄不符合自然规则')
self.__age = age
def __str__(self): #类似Java、C#中的toString方法,方便输出查看
return ('我的名字是%s,今年%d岁了'%(self.name,self.__age))
if __name__ == '__main__':
stu1 = Student()
stu1.name = '张三'
stu1._Student__age = 30 #看这里 看这里 看这里
print(stu1)
注意,Python 类中有双下划线开头和结尾的类方法(构造函数init),这些都是 Python 内部定义的,用于 Python 内部调用。我们自己定义类属性或者类方法时,禁止使用这种格式。
1.3、装饰器property
为一个类的成员属性增加getter和setter方法时,可以调用property方法,其实就是装饰器。装饰器用来将getter方法/setter方法转换为对象的属性,添加为property装饰器以后,我们就可以像调用属性一样使用getter方法或者setter方法。
注意:使用property装饰的方法,必须和属性名是一样的
class Student():
def getname(self,name):
return self.__name
def setname(self,name):
if len(name) < 2:
raise ValueError('名字长度不可小于2')
self.__name = name
name = property(getname,setname) # name的装饰器
def getage(self,age):
return self.__age
def setage(self,age):
if age > 150:
raise ValueError('年龄不符合自然规则')
self.__age = age
age = property(getage,setage) #age的装饰器
def __str__(self): #类似Java、C#中的toString方法,方便输出查看
return ('我的名字是%s,今年%d岁了'%(self.__name,self.__age))
if __name__ == '__main__':
stu1 = Student()
stu1.name = '张三'
stu1.age = 20
print(stu1)
1.4、封装小结
使用封装,确保了我们数据的安全性和合理性:
1.隐藏了属性名,使调用者无法随意的修改对象中的属性;
2.增加getter和setter方法,很好的控制的属性是否是只读的,如果希望属性是只读的,我们直接去掉setter方法即可,同样如何不希望希望外部访问属性,则可以直接去掉getter方法即可;
3.要想控制数据的合理性,我们需要在setter中增加数据的验证,确保数据正确、合理;
4.可以加入property装饰器优化代码;
2、继承
在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系。
继承一般用于创建和现有类功能类似的新类(已有Animal类,想要创建一个Monkey类)或者新类只需要在现有类基础上添加一些成员(属性和方法),但又不想直接将现有类代码复制给新类。也就是说,通过使用继承这种机制,可以轻松实现类的重复使用。新的class称为子类,而被继承的 class称为基类、父类或超类。
2.1、Python中的继承
在Python中,子类继承父类时,只需在定义子类时,将父类(可以是多个)放在子类之后的圆括号里即可。语法格式如下:
class 类名(父类1, 父类2, ...):
#类定义部分
注意:
1、如果该类没有显式指定继承自哪个类,则默认继承 object 类;
2、Python 的继承是多继承机制,和Java、C#不同;
class Animal():
def say(self):
print('这是基类Animal')
class Monkey(Animal):
def xue(self):
print('这是子类Monkey')
if __name__ == '__main__':
monkey = Monkey()
monkey.say() # 这是基类Animal
monkey.xue() # 这是子类Monkey
从上可以看出通过继承,子类拥有父类所有的公共的属性和方法。那么具体如何实现的呢?
class Person():
def __init__(self,name,gender):
self.name = name
self.gender = gender
def say(self):
print('这是Person类,名字是%s,性别是%s'%(self.name,self.gender))
class Student(Person):
def __init__(self,name,gender,score):
super(Student,self).__init__(name,gender) #调用父类指定构造方法,默认__init__(self)
self.score = score
def say(self):
print('这是Student类,名字是%s,性别是%s,得分是%d'
%(self.name,self.gender,self.score))
if __name__ == '__main__':
student = Student('张三','男',90)
student.say()
# 如果子类没有say方法,输出这是Person类,名字是张三,性别是男
# 如果子类有say方法,输出这是Student类,名字是张三,性别是男,得分是90
注意:在Python中首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找。
2.2、Python多继承
简而言之,多重继承就是有多个父类的继承,所以子类就会继承多个基类的公共的属性和方法。比如沙发床是沙发和床的功能的组合。这一点同其他大多数语言不同,大部分面向对象的编程语言,都只支持单继承,即子类有且只能有一个父类。其实多继承很容易让代码逻辑复杂、思路混乱。我们简单以一个案例说下:
class Person():
def __init__(self,name,gender):
self.name = name
self.gender = gender
def say(self):
print('这是Person类,名字是%s,性别是%s'%(self.name,self.gender))
class Animal():
def __init__(self,name,gender):
self.name = name
self.gender = gender
def hao(self):
print('这是Animal类,名字是%s,性别是%s'%(self.name,self.gender))
class Student(Person,Animal):
def __init__(self,name,gender,score):
super(Student,self).__init__(name,gender)
self.score = score
def study(self):
print('这是Student类,名字是%s,性别是%s,得分是%d'
%(self.name,self.gender,self.score))
if __name__ == '__main__':
student = Student('张三','男',90)
student.say()
student.hao()
student.study()
注意:多个父类中包含同名的类方法。对于这种情况,Python 的处置措施是:根据子类继承多个父类时这些父类的前后次序决定,即排在前面父类中的类方法会覆盖排在后面父类中的同名类方法。
3、多态
多态是指一类事物有多种形态,比如人类,根据肤色可以划分为黄种人、黑种人、白种人,根据民族分,更多。在python中,不同的对象调用同一个接口,表现出不同的状态,称为多态。
那么Python如何实现多态呢?两个特点:
1、多态的前提是继承,存在继承才会有多态;
2、子类重写了父类的方法;
class Animal():
def eat(self,who):
who.eat()
class Dog(Animal):
def eat(self):
print('狗狗在吃饭')
class Cat(Animal):
def eat(self):
print('猫猫在吃饭')
if __name__ == '__main__':
animal = Animal()
animal.eat(Dog()) # 狗狗在吃饭
animal.eat(Cat()) # 猫猫在吃饭
多态增加了程序的灵活性,增加了程序的可扩展性。
4、总结
这次依然还是面向对象编程的知识,包括面向对象的三大特征(封装、继承和多态),是对上次Python面向对象编程的补充。下次我们来说说Python中的抽象类和接口。
网友评论