面向对象三大特性
一、继承
1、定义:
继承是一种创建新类的方式,在python中新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
2、继承的使用场景:什么是什么
3、查看父类的双下方法:Foo.__bases__
4、种类:
①单继承
- 父类中没有的属性在子类中出现叫做派生属性
- 父类中没有的方法在子类中出现叫做派生方法
- 只要是子类的对象调用,子类中有的名字一定用子类的,子类中没有才找父类的,如果父类也没有报错
- 如果父类、子类都有则用子类的
- 如果还想用父类的,单独调用父类的:
1、父类名.方法名 需要自己传self参数
2、super().方法名 不需要自己传self
- 正常的代码中单继承 ===> 减少了代码的重复
- 继承表达的是一种子类是父类的关系
②多继承
- 在python2中
- 新式类:继承object类的才是新式类——>遵循广度优先原则
可以用Foo.\_\_mro\_\_方法查看继承顺序,mro方法只在新式类中存在
- 经典类:直接创建一个类默认是经典类——>遵循深度优先原则
- 在python3中
- 所有在python3中创建的类都是新式类——>遵循广度优先原则
- 可以用Foo.__mro__方法查看继承顺序,mro方法只在新式类中存在
5、super()关键字
①super()只在python3中存在
②super的本质 :不是单纯找父类而是根据调用者的节点位置的广度优先顺序来的
二、抽象类&接口类、多态
抽象类与接口类
1、前言
①所谓的接口类是借了其他面向对象语言(Java)的设计模式概念
②在Java中抽象类与接口类的特性
- 接口类interface支持多继承,接口类中的所有的方法都必须不能实现—Java
- 抽象类不支持多继承,抽象类中方法可以有一些代码的实现—Java
③接口隔离原则:
- 使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些不需要的接口。
2、抽象类
①python原生支持
②抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
③python的抽象类保持了java的特性,使用抽象类的时候尽量单继承
④python中的抽象类需要借助模块来实现,抽象类是一个特殊的类,只能被继承,不能被实例化
⑤为了帮助理解,我们可以认为抽象类就是从一堆类中抽取相同的内容而来的,正如类是从一堆对象中抽取相同的内容而来的相同
⑥举例:
from abc import abstractclassmethod,ABCMeta
class Payment(metaclass=ABCMeta):
@abstractclassmethod
def pay(self):
print('支付ing....')
class Wechatpay(Payment):
def pay(self):
print('微信支付ing...')
class Alipay(Payment):
def pay(self):
print('阿里支付ing...')
class Applepay(Payment):
def pay(self):
print('苹果支付ing...')
wechat = Wechatpay()
ali = Alipay()
apple = Applepay()
3、接口类
①python原生不支持
②python的抽象类保持了java的特性,使用接口类的时候鼓励多继承
多态与多态性
1、前言
①定义:多态指的是一类事物有多种形态
②python语言天生自带多态的属性,所以该概念也是类比其他面向对象语言(Java)而言而提及的,因为类似Java等其他面向对象的强类型语言中如果参数是对象的话前面的对象类型指代就是有问题,所以会用对象的父类来代替,这样表现出来的就是父类的子类都可以作为参数,而调用不同的子类就会表现出不同的结果,也就是多态的表现;但是针对python语言而言是动态强类型语言所以不会发生该问题,即天生即解决了多态的问题
2、多态动态绑定(在继承的背景下使用时,也称为多态性)
①多态性是指在不考虑实例类型的情况下使用实例
3、鸭子类型
①出处:鸭子类型的名称来源于西方谚语:一只鸟长得像鸭子,叫声像鸭子,走路也像鸭子,那它就是鸭子!
②原则:如果想编写现有对象的自定义版本,可以继承该对象也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
③优缺点:
- 优点:低耦合,每个相似的类之间都没有影响
- 缺点:对自觉性要求较高
④应用实例:list、tuple该两个类极为相似,但却没有用继承来实现,它们互为鸭子类型
封装
1、定义:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
2、作用:
①将变化隔离
②便于使用
③提高复用性
④提高安全性
3、封装原则:
①将不需要对外提供的内容都隐藏起来
②把属性都隐藏,提供公共方法对其访问
4、私有变量和私有方法
①适用场景
- 在python中用双下划线开头的方式将属性隐藏起来,即设置成私有的
- 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
②实例:
class Foo:
__VAR = 100
def __init__(self,name,password):
self.name = name
self.__password = password
def get_password(self):
return self.__password
foo = Foo('python',123)
foo.get_password()
③私有化变形的特点
- 类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
- 这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
- 在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
④私有化变形的注意点:
- 这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
- 变形的过程只在类的内部生效,在定义后的赋值操作,不会变形
5、私有化属性、方法的适用场景
①禁止在类的外部调用
②保护属性避免被随意改变
③保护属性不想被子类继承
6、property属性
①原理:property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
②作用:property属性会将原本是类中的方法改变成类似于属性调用的形式,用户可以直接按照属性的方式进行调用,似的某些需要进行计算或逻辑处理的类属性调用方式更加合理,这种特性的使用方式遵循了统一访问的原则
③举例:
from math import pi
class Circle:
def __init__(self,radius):
self.radus = radius
@property
def area(self):
return self.radus**2*pi
@property
def perimeter(self):
return self.radus*2*pi
c = Circle(5)
print(c.area)
print(c.perimeter)
>>> 78.53981633974483
>>> 31.41592653589793
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现,一个静态属性property本质就是实现了get,set,delete三种方法
class Foo:
@property
def AAA(self):
print('get的时候运行我啊')
@AAA.setter
def AAA(self,value):
print('set的时候运行我啊')
@AAA.deleter
def AAA(self):
print('delete的时候运行我啊')
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
④注意事项:
7、classmethod
①定义:类方法,即不需要进行实例化,用类名就可以直接调用的方法,语法:类名.方法名()
②适用场景:
- 当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法
③举例
class Classmethod_Demo():
role = 'dog'
@classmethod
def func(cls):
print(cls.role)
Classmethod_Demo.func()
④注意:
8、staticmethod
①定义:静态方法,即
②适用场景:
- 如果一个函数既和对象没有关系也和类没有关系,那么就用staticmethod将这个函数变成一个静态方法
③举例
class Staticmethod_Demo():
role = 'dog'
@staticmethod
def func():
print("当普通方法用")
Staticmethod_Demo.func()
④注意