基础认知
- Python 中的 类名大写
- Python 中无 私有属性 和 私有方法;如果要模拟私有方法可以使用 _加变量名或方法名表示
- 初始化的 init 方法为两个下划线;注意到`init
方法的第一个参数永远是self`,表示创建的实例本身
三大特性
1.封装
封装(encapsulation)包含两个概念。第一个概念是在面向对象编程中,对象将变量(状态)和方法(用来改变状态或执行涉及状态的计算)集中在一个地方 — 即对象本身。
实例
calss Rectange():def _init_(self,w,l):self.width = wself.height = ldef area(self):return self.width * self.height
封装包含的第二个概念,指的是隐藏类的内部数据,以避免客户端(client)代码(即类外部的代码)直接进行访问。
2.抽象
抽象(abstraction)指的是“剥离事物的诸多特征,使其只保留最基本的特质”的过程。
举个例子,我们创建一个 Person 类,但是忽略其眼睛颜色和身高等特征,这就是在进行抽象。Person 对象是对人的抽象,代表的是只具备解决当前问题所需的基本特征的人。
3.多态
多态(polymorphism)指的是“为不同的基础形态(数据类型)提供相关接口的能力”。接口,指的是函数或方法。
假设我们要编写一个程序,创建 3 个对象,用对象分别画出三角形、正方形和圆形。可以定义 3 个不同的类 Triangle、Square 和 Circle,并各自定义 draw 方法来实现 。 Triangle.draw() 用 来 画 三 角 形 , Sqaure.draw() 用 来 画 正 方 形 ,Circle.draw()则用来画圆形。这样设计的话,每个对象都有一个 draw 接口,支持画出自身类所对应的图形。这样就为 3 个不同的数据类型提供了相同的接口。
4.继承
编程语境中的继承(inheritance),与基因继承类似。在基因继承中,子女会从父母那继承眼睛颜色等特征。类似地,在创建类时,该类也可以从另一个类那里继承方法和变量。被继承的类,称为父类(parent class);继承的类则被称为子类(child class)。
示例
class Shape():def __init__(self,w,h):self.width = wself.height = hdef print_size(self):print("{} by {}".format(self.width,self.height))# 继承 shape 类class Square(Shape):def area(self):return self.width * self.height# 调用类a_square = Square(12,5)print( a_square.area() )>>> 60
多类继承
在Python中,同时支持单继承与多继承,一般语法如下
class SubClassName(ParentClass1 [, ParentClass2, ...]):class_suite
子类判断 insubclass()
子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类:
方法覆盖
当子类继承父类的方法时,我们可以定义一个与继承的方法名称相同的新方法,从而覆盖父类中的方法。子类改变从父类中继承方法的实现能力,被称为方法覆盖(method overriding),
继承 (方法覆盖) 实现简单的多态
class Animal():def run(self):print("Animal is runing")# 在狗和猫身上分别重写Animal的run方法clss Dog(Animal):def run(self):print('Dog is running...')def eat(self):print('Eating meat...')clss Cat(Animal):def run(self):print('Cat is running...')def eat(self):print('Eating fish...')
继承中的 _init _
当在Python中出现继承的情况时,一定要注意初始化函数init的行为
- 如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。
- 如果子类定义了自己的初始化函数,而在子类中没有显示调用父类的初始化函数,则父类的属性不会被初始化
- 如果子类定义了自己的初始化函数,在子类中显示调用父类,子类和父类的属性都会被初始化
pass 表示子类只继承并不会做任何事
#定义父类:Parentclass Parent(object):def __init__(self, name):self.name = nameprint("create an instance of:", self.__class__.__name__)print("name attribute is:", self.name)#定义子类Child ,继承父类Parentclass Child(Parent):pass#子类实例化时,由于子类没有初始化,此时父类的初始化函数就会默认被调用#且必须传入父类的参数name
super
super主要来调用父类方法来显示调用父类
# 子类中调用父类的属性class Parent(object):def __init__(self, name):self.name = nameclass Child(Parent):def __init__(self):print("call __init__ from Child class")super(Child,self).__init__("data from Child") #要将子类Child和self传递进去d = Parent('tom')c = Child()print(c.name)# 子类中调用父类的方法class Parent(object):Value = "Hi, Parent value"def fun(self):print("This is from Parent")class Child(Parent):Value = "Hi, Child value"def fun(self):print("This is from Child")Parent.fun(self) #调用父类Parent的fun函数方法c = Child()c.fun()
五大基本原则
单一职责原则SRP(Single Responsibility Principle)
是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
开放封闭原则OCP(Open-Close Principle)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。
替换原则(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。
依赖原则(the Dependency Inversion Principle DIP)
具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。
接口分离原则(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来
