一.面向对象的三大特性
1.封装
-
封装就是对对象成员进行访问控制
- 封装的三个级别:
- 公开:public
- 受保护的:protected
- 私有的:private
(public、protected、private都不是关键字)
- 判断对象的位置:
- 对象内部
- 对象外部
- 子类中
- 私有:private
- 私有成员是最高级别的封装,只能在当前类或者对象中访问
- 封装方法:在成员前面添加两个下划线即可
注:python的私有不是真的私有,只是一种改名策略,可以使用对象._classname_attributename访问
class Person():
name = 'liu' #name是共有的成员
__age = 18 #age是私有成员
p = Person()
print(p.name)
print(p.__age) #报错,没有这个变量
***通过__dict__查看所有对象得:
print(Person.__dict__)
***用改后的名字可以访问
p = Person()
print(p.name)
#print(p.__age) #报错,没有这个变量
p._Person__age=19
print(p._Person__age)
- 受保护的:protected
- 受保护的封装是将对象成员进行一定级别的封装,然后在类或者子类中都可以进行访问,但在外部不可以
- 封装方法:在成员名称前添加一个下划线
- 公开的:public
- 公开的封装对成员没有任何操作,任何地方都可以访问
2.继承
- 继承就是一个类可以获得另一个类中的成员属性和成员方法
- 人:姓名、年龄、吃、睡(父类)
- 老师:继承人的成员属性和方法,再定义自已单独的成员属性和方法即可(子类)
- 作用:减少代码,增加代码的复用功能,可以设置类与类之间的关系
- 继承与被继承:
- 被继承的类叫父类、基类、超类, 用于继承的类叫子类、派生类
- 继承与被继承一定存在一个 is-a 的关系
- 继承的特征:
- 所有的类都继承自object类
- 自类继承父类后,可以使用父类除私有成员外的所有内容(可以继承公共的和受保护的)
- 子类继承父类后并没有将父类成员完全赋值到子类中,而是通过引用关系访问调用
- 子类中可以定义独有的成员属性和方法
- 子类中定义的成员和父类相同时,优先使用子类成员
- 子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 父类名.父类成员 的格式来调用父类成员,也可以使用 super().父类成员 的格式来调用
class Person():
name = 'NoName'
age = 18
_petname = 'sec' #小名是受保护的,子类可以用,但不能公用
__score = 0 #考试成绩是私有的,只能自己知道
def sleep(self):
print('sleep')
def work(self):
print('make some money')
class Teacher(Person): #父类写在括号里,除父类的私有属性,其他都被子类继承
id = '123456'
name = 'liu' #子类的成员变量与父类相同了
def make_test(self):
print('you have a test today')
def work(self): #扩充父类的功能,只需要调用父类相应的函数
Person.work(self) #可以用 super().work() 代替
self.make_test()
t = Teacher()
print(t.name) #自类继承父类的公共成员,但与父类成员变量同名时优先使用子类成员变量
print(t._petname) #子类继承父类受保护的成员
t.sleep() #子类继承父类的方法
#print(t.__score) #报错,子类不能继承父类的私有成员变量
print('*'*20)
t.work() #扩充父类功能
- 构造函数
- 是一类特殊的函数,在类进行实例化之前自动调用
- 构造函数必须有一个self参数,self不是关键字,名字可以不是self但必须有
class Dog():
def __init__(self): # __init__就是构造函数,每次实例化的时候第一个被自动调用,主要工作是初始化
print('i am a dog')
self.name = 'xiaobai'
self.age = 2
d = Dog()
- 继承变量函数的查找顺序问题
- 优先查找自己的变量
- 没有则查找父类
- 构造函数如果本类中没有定义,则自动查找调用父类构造函数,直到找到为止,如果本类有定义,则不再继续向上查找
- 如果子类没定义,父类的构造函数含参数,则构造对象时的参数应该按父类参数来构造
class Animel():
def __init__(self):
print('i am an animel')
class PaXingAni(Animel):
def __init__(self,name): ####如果没有self只有name参数时报错,self换成其他的名字也不会报错
print('{} is a paxingAni'.format(name))
class Dog(PaXingAni):
def __init__(self): #__init__就是构造函数,每次实例化的时候第一个被自动调用,主要工作是初始化
print('i am a dog')
class Cat(PaXingAni):
pass
d = Dog()
c = Cat('kkk') #如果不传参数则报错
- super
- super不是关键字,而是一个类
- super的作用是获取MRO(method resolustion order)列表中的第一个类,这个类一般就是父类
- super和父类直接没有任何实质性关系,但是通过super可以调用到父类
- super使用的两个方法,参见在构造函数中调用父类的构造函数
#扩充父类的构造函数例子一:
#使用super调用
class PaXingAni():
def __init__(self,name): ####如果没有self只有name参数时报错,self换成其他的名字也不会报错
print('hhh',name)
class Dog(PaXingAni):
def __init__(self,name): #__init__就是构造函数,每次实例化的时候第一个被自动调用,主要工作是初始化
super(Dog,self).__init__(name) #或super().__init__(name)
print('dog的附加功能')
d = Dog('kkk')
#扩充父类的构造函数例子二:
#调用父类名改变
class PaXingAni():
def __init__(self,name): ####如果没有self只有name参数时报错,self换成其他的名字也不会报错
print('hhh',name)
class Dog(PaXingAni):
def __init__(self,name): #__init__就是构造函数,每次实例化的时候第一个被自动调用,主要工作是初始化
PaXingAni.__init__(self,name)
print('dog的附加功能')
d = Dog('kkk')
- 单继承和多继承
- 单继承:每个类只能继承一个类(只有一个父类)
优点:逻辑清晰,简单
缺点:功能不能无限扩展,只能在当前唯一的继承链中扩展
- 多继承:每个类允许继承多各类
优点:功能扩展方便
缺点:继承关系混乱
#继承的例子
class Fish():
def __init__(self,name):
self.name = name
def swim(self):
print('swim')
class Bird():
def __init__(self,name):
self.name = name
def fly(self):
print('fly')
class SuperMan(Fish,Bird):
def __init__(self,name):
self.name = name
liu = SuperMan('hhh')
liu.swim()
菱形继承/钻石继承:多个子类继承同一个父类,这些子类又被同一个类继承
#菱形继承
class A():
pass
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
多继承的MRO:MRO是多继承中用于保存继承顺序的列表,python用C3算法计算
MRO列表计算原则:
子类永远在父类前
如果多个父类,根据继承语法括号中书写的顺序
如果多个类继承与同一个父类,孙子类中只会选取括号中第一个父类的父类
3.多态
- 多态就是一个对象在不同情况下有不同的状态出现
- 多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。
- python中多态不是语法,是一种设计思想
- 多态:同一事物的不同形态,比如动物分为人、狗、猫
- Mixin设计模式:主要采用多继承方式对类进行扩展
Mixin实现多继承时:
-首先它表示某一单一功能,而不是某一物品
-职责必须单一,如果有多个功能则写多个Mixin
-Mixin不依赖于子类的实现
-子类即使没有继承Mixin功能也照样工作,只是缺少了某个功能
Mixin优点:
-可以在不对类修改的前提下扩充功能
-避免创建很多类,导致类继承混乱
#
class Person():
name = 'xiaobai'
age = 2
def eat(self):
print('eat******')
def drink(self):
print('drink******')
class Teacher(Person):
def work(self):
print('work******')
class Student(Person):
def study(self):
print('study******')
class Tutor(Teacher,Student):
pass
t = Tutor()
print(t.__dict__)
print(Tutor.__mro__)
print(Tutor.__dict__)
print('*'*20)
#Mixin的写法
class TeacherMixin(): #老师和学生没有父类
def work(self):
print('work')
class StudentMixin():
def study(self):
print('study')
class TutorM(Person,TeacherMixin,StudentMixin):
pass
tt = TutorM()
print(tt.__dict__)
print(TutorM.__mro__)
print(TutorM.__dict__)
4.类的函数
- issubclass:检测一个类是否是另一个类的子类
class A():
pass
class B(A):
pass
class C():
pass
print(issubclass(B,A))
print(issubclass(C,A))
print(issubclass(C,object))
- isinstance:检测一个对象是否是一个类的实例
class A():
pass
a = A()
print(isinstance(a,A))
- hasattr:检测一个对象是否有成员***
class A():
name = 'liu'
a = A()
print(hasattr(a,'name'))
- getattr: get attribute
- setattr:set attribute
- delattr:delete attribute
help(setattr)
- dir :获取对象成员列表
class A():
name = 'liu'
a = A()
print(dir(a))
视频参考图灵学院