1、面向对象有哪些特性
三种:封装性、继承性、多态性
2、Python中的封装
在Python代码中,封装有两层含义:
① 把现实世界中的主体中的属性和方法书写到类的里面的操作即为封装
② 封装可以为属性和方法添加为私有权限,不能直接被外部访问
3、封装中的私有属性和私有方法
在面向对象代码中,我们可以把属性和方法分为两大类:==公有(属性、方法)==、==私有(属性、方法)==
Python:公有(属性、方法),私有(属性、方法)
Java:公有(属性、方法),受保护(属性、方法),私有(属性、方法)
公有属性和公有方法:无论在类的内部还是在类的外部我们都可以对属性和方法进行操作。
但是有些情况下,我们不希望在类的外部对类内部的属性和方法进行操作。我们就可以把这个属性或方法封装成私有形式。
4、私有属性的访问限制
设置私有属性和私有方法的方式非常简单:在属性名和方法名 前面 加上两个下划线 __
即可。
5、私有属性设置与访问"接口"
外部可以通过特定的"接口"来实现对私有属性的方法。
接口就是我们通常说的一个函数,这个函数可以实现对某些属性的访问(设置与获取)
在Python中,一般定义函数名' get_xx '用来获取私有属性,定义' set_xx '用来修改私有属性值。
二、Python中的继承
1、什么是继承
我们接下来来聊聊Python代码中的“继承”:类是用来描述现实世界中同一组事务的共有特性的抽象模型,但是类也有上下级和范围之分,比如:生物 => 动物 => 哺乳动物 => 灵长型动物 => 人类 => 黄种人
从哲学上说,就是共性与个性之间的关系,比如:白马和马!所以,我们在OOP代码中,也一样要体现出类与类之间的共性与个性关系,这里就需要通过类的继承来体现。简单来说,如果一个类A使用了另一个类B的成员(属性和方法),我们就可以说A类继承了B类,同时这也体现了OOP中==代码重用的特性==!
2、继承的基本语法
假设A类要继承B类中的所有属性和方法(私有属性和私有方法除外)
class B(object):passclass A(B):passa = A()
a.B中的所有公共属性
a.B中的所有公共方法
3、与继承相关的几个概念
继承:一个类从另一个已有的类获得其成员的相关特性,就叫作继承!
派生:从一个已有的类产生一个新的类,称为派生!
很显然,继承和派生其实就是从不同的方向来描述的相同的概念而已,本质上是一样的!
父类:也叫作基类,就是指已有被继承的类!
子类:也叫作派生类或扩展类
扩展:在子类中增加一些自己特有的特性,就叫作扩展,没有扩展,继承也就没有意义了!
单继承:一个类只能继承自一个其他的类,不能继承多个类,单继承也是大多数面向对象语言的特性!
多继承:一个类同时继承了多个父类, (C++、Python等语言都支持多继承)
4、单继承
单继承:一个类只能继承自一个其他的类,不能同时继承多个类。这个类会有具有父类的属性和方法。
5、单继承特性(多层继承):传递性
在Python继承中,如A类继承了B类,B类又继承了C类。则根据继承的传递性,则A类也会自动继承C类中所有属性和方法(公共)
6、编写面向对象代码中的常见问题
问题1:在定义类时,其没有遵循类的命名规则
答:在Python中,类理论上是区分大小写的(在Python中类可以全部大写也可以全部小写)。但是要遵循一定的命名规范:首字母必须是字母或下划线,其中可以包含字母、数字和下划线,而且要求其命名方式采用大驼峰。
电动汽车:EletricCar
父类:Father
子类:Son
问题2:父类一定要继承object么?Car(object)
答:在Python面向对象代码中,建议在编写父类时,让其自动继承object类。但是其实不写也可以,因为默认情况下,Python中的所有类都继承自object。
7、多继承
什么是多继承?
Python语言是少数支持多继承的一门编程语言,所谓的多继承就是允许一个类同时继承自多个类的特性。
8、子类扩展:重写父类属性和方法
扩展特性:继承让子类继承父类的所有公共属性和方法,但是如果仅仅是为了继承公共属性和方法,继承就没有实际的意义了,应该是在继承以后,子类应该有一些自己的属性和方法。
什么是重写?
重写也叫作==覆盖==,就是当子类成员与父类成员名字相同的时候,从父类继承下来的成员会重新定义!
此时,通过子类实例化出来的对象访问相关成员的时候,真正其作用的是子类中定义的成员!
class Father(object):
属性
方法
class Son(Father):
父类属性和方法
自己的属性和方法(如果子类中的属性和方法与父类中的属性或方法同名,则子类中的属性或方法会对父类中同名的属性或方法进行覆盖(重写))
上面单继承例子中 Animal 的子类 Cat和Dog 继承了父类的属性和方法,但是我们狗类Dog 有自己的叫声'汪汪叫',猫类 Cat 有自己的叫声 '喵喵叫' ,这时我们需要对父类的 call() 方法进行重构。如下:
class Animal(object):def eat(self):print('i can eat')def call(self):print('i can call')class Dog(Animal):passclass Cat(Animal):passwangcai = Dog()
wangcai.eat()
wangcai.call()miaomiao = Cat()
miaomiao.eat()
miaomiao.call()
Dog、Cat子类重写父类Animal中的call方法:
class Animal(object):def eat(self):print('i can eat')# 公共方法def call(self):print('i can call')class Dog(Animal):# 重写父类的call方法def call(self):print('i can wang wang wang')class Cat(Animal):# 重写父类的call方法def call(self):print('i can miao miao miao')wangcai = Dog()
wangcai.eat()
wangcai.call()miaomiao = Cat()
miaomiao.eat()
miaomiao.call()
9、super()调用父类属性和方法
super():调用父类属性或方法,完整写法:super(当前类名, self).属性或方法()
,在Python3以后版本中,调用父类的属性和方法我们只需要使用super().属性或super().方法名()
就可以完成调用了。
案例:Car汽车类、GasolineCar汽油车、ElectricCar电动车
class Car(object):def __init__(self, brand, model, color):self.brand = brandself.model = modelself.color = colordef run(self):print('i can run')class GasolineCar(Car):def run(self):print('i can run with gasoline')class ElectricCar(Car):def __init__(self, brand, model, color, battery):super().__init__(brand, model, color)# 电池属性self.battery = batterydef run(self):print(f'i can run with electric,i have a {self.battery} + "kwh battery"')bwm = GasolineCar('宝马', 'X5', '白色')
bwm.run()tesla = ElectricCar('特斯拉', 'Model S', '红色', 70)
tesla.run()
10、MRO属性或MRO方法:方法解析顺序
MRO(Method Resolution Order):方法解析顺序,我们可以通过类名.__mro__
或类名.mro()
获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找到。
class Car(object):def __init__(self, brand, model, color):self.brand = brandself.model = modelself.color = colordef run(self):print('i can run')class GasolineCar(Car):def run(self):print('i can run with gasoline')class ElectricCar(Car):def __init__(self, brand, model, color, battery):super().__init__(brand, model, color)# 电池属性self.battery = batterydef run(self):print(f'i can run with electric,i has a {self.battery} + "kwh battery"')print(ElectricCar.__mro__)
print(ElectricCar.mro())
说明:有MRO方法解析顺序可知,在类的继承中,当某个类创建了一个对象时,调用属性或方法,首先在自身类中去寻找,如找到,则直接使用,停止后续的查找。如果未找到,继续向上一级继承的类中去寻找,如找到,则直接使用,没有找到则继续向上寻找...直到object类,这就是Python类继承中,其方法解析顺序。
三、Python中多态(了解)
1、什么是多态
多态指的是一类事物有多种形态。
定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。
==不同对象 => 使用相同方法 => 产生不同的执行结果。==
① 多态依赖继承(不是必须的)
② 子类方法必须要重写父类方法
首先定义一个父类,其可能拥有多个子类对象。当我们调用一个公共方法(接口)时,传递的对象不同,则返回的结果不同。
好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!
2、多态原理图
公共接口service就是多态的体现,随着传入水果对象的不同,能返回不同的结果。
3、多态代码实现
多态:可以基于继承也可以不基于继承
'''
首先定义一个父类,其可能拥有多个子类对象。当我们调用一个公共方法(接口)时,传递的对象不同,则返回的结果不同。
'''
class Fruit(object):def makejuice(self):print('i can make juice')class Apple(Fruit):# 重写父类方法def makejuice(self):print('i can make apple juice')class Banana(Fruit):# 重写父类方法def makejuice(self):print('i can make banana juice')class Orange(Fruit):# 重写父类方法def makejuice(self):print('i can make orange juice')# 定义一个公共接口(专门用于实现榨汁操作)
def service(obj):# obj要求是一个实例化对象,可以传入苹果对象/香蕉对象obj.makejuice()# 调用公共方法
service(Orange())
扩展:在Python中还有哪些多态的案例呢?
+ 多态体现
+加号只有一个,但是不同的对象调用+方法,其返回结果不同。
如果加号的两边都是数值类型的数据,则加号代表运算符
如果加号的两边传入的是字符串类型的数据,则加号代表合并操作,返回合并后的字符串
'a' + 'b' = 'ab'
如果加号的两边出入序列类型的数据,则加号代表合并操作,返回合并后的序列
[1, 2, 3] + [4, 5, 6] = [1, 2, 3, 4, 5, 6]