- 一、面向对象
- 二、类
- print(stu1obj.dict)
# print(stu2obj.dict)
# print(stu3_obj.__dict) - 为对象定制自己独有的属性
# 问题1:代码重复
# 问题2:属性的查找顺序
# stu1obj.stuname=’egon’ # stu1obj.dict[‘stuname’]=’egon’
# stu1obj.stuage=18 # stu1obj.dict[‘stuage’]=18
# stu1_obj.stu_gender=’male’ # stu1_obj.__dict[‘stu_gender’]=’male’
# # print(stu1_obj.__dict)
#
# stu2_obj.stu_name=’lili’
# stu2_obj.stu_age=19
# stu2_obj.stu_gender=’female’
# # print(stu2_obj.__dict)
#
# stu3_obj.stu_name=’jack’
# stu3_obj.stu_age=20
# stu3_obj.stu_gender=’male’
# # print(stu2_obj.__dict) - 解决问题一:
# 解决方案一:
# def init(obj,x,y,z):
# obj.stu_name=x
# obj.stu_age=y
# obj.stu_gender=z
#
# init(stu1_obj,’egon’,18,’male’)
# init(stu2_obj,’lili’,19,’female’)
# init(stu2_obj,’jack’,20,’male’) - 解决方案二:
- print(stu1_obj.count)
# print(stu2_obj.count)
# print(stu3_obj.count) - 类中存放的是对象共有的数据与功能
# 一:类可以访问:
# 1、类的数据属性
# print(Student.stu_school)
# 2、类的函数属性
# print(Student.tell_stu_info)
# print(Student.set_info) - 二:但其实类中的东西是给对象用的
# 1、类的数据属性是共享给所有对象用的,大家访问的地址都一样
# print(id(Student.stu_school)) - print(id(stu1_obj.stu_school))
# print(id(stu2_obj.stu_school))
# print(id(stu3_obj.stu_school)) - Student.stu_school=’OLDBOY’
# stu1_obj.stu_school=’OLDBOY’
# print(stu1_obj.stu_school) - print(Student.stu_school)
# print(stu2_obj.stu_school)
# print(stu3_obj.stu_school) - 2、类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同
- 类调用自己的函数属性必须严格按照函数的用法来
# print(Student.tell_stu_info)
# print(Student.set_info) - Student.tell_stu_info(stu1_obj)
# Student.tell_stu_info(stu2_obj)
# Student.tell_stu_info(stu3_obj) - Student.set_info(stu1_obj,’EGON’,19,’MALE’)
# Student.tell_stu_info(stu1_obj) - 绑定方法的特殊之处在于:谁来调用绑定方法就会将谁当做第一个参数自动传入
# print(Student.tell_stu_info)
# print(stu1_obj.tell_stu_info)
# print(stu2_obj.tell_stu_info)
# print(stu3_obj.tell_stu_info) - stu1_obj.tell_stu_info() #tell_stu_info(stu1_obj)
# stu2_obj.tell_stu_info() #tell_stu_info(stu2_obj)
# stu3_obj.tell_stu_info() #tell_stu_info(stu3_obj)
# stu1_obj.choose(‘python全栈开发’)
# print(stu1_obj.course)
#
# stu2_obj.choose(‘linux运维’)
# print(stu2_obj.course)
#
# stu3_obj.choose(‘高级架构师’)
# print(stu3_obj.course)- l1.append(‘dd’)
# l2.append(‘dd’)
# print(l1)
# print(l2) - list.append(l1,’dd’)
# list.append(l2,’dd’)
# print(l1)
# print(l2) - 了解:
- print(abs(-1))
# print(all([1,’aaa’,’1’]))
# print(all([])) - print(any([0,None,1]))
# print(any([])) - print(bin(11))
# print(oct(11))
# print(hex(11)) - print(bool(‘’))
- def func():
# pass
# class Foo:
# pass
# print(callable(Foo)) # 方 - print(chr(65))
# print(ord(‘A’)) - 不可变集合
# s=frozenset({1,2,3}) - hash(不可变类型)
- print(round(1.5))
# print(round(1.4)) - 10 ** 2 % 3
# print(pow(10,2,3))
# s=slice(1,4,2)
# l1=[‘a’,’b’,’c’,’d’,’e’]
# l2=[‘aaa’,’bbb’,’ccc’,’ddd’,444]
#
# print(l1[1:4:2]) # l1[s]
# print(l2[1:4:2]) # l2[s] - =================》掌握
# v1=’hello’
# v2=[111,222,333,444,5555,6666]
# res=zip(v1,v2)
# print(list(res)) - =================》掌握
# print(divmod(10000,33)) - =================》掌握
# class Foo:
# pass
# obj=Foo()
# obj.xxx=1111
# print(dir(obj)) # obj.哪些属性 - =================》掌握
# for i,v in enumerate([‘a’,’b’,’c’]):
# print(i,v) - =================》掌握
# res=eval(‘{“a”:1}’) # 执行字符串中的表达式
# print(res,type(res)) - =================》掌握
# class Foo:
# pass
# obj=Foo()
# print(isinstance(obj,Foo))
# print(isinstance([],list)) # 类型判断推荐使用isinstance
# print(type([]) is list) # 不推荐使用 - =================》掌握
# import ‘time’ # 错误
time=import(‘time’)
time.sleep(3) - 下个周:反射
# setattr
# getattr
# delattr
# hasattr
一、面向对象
面向过程:
核心是”过程”二字
过程的终极奥义就是将程序流程化
过程是”流水线”,用来分步骤解决问题的
面向对象:
核心是”对象”二字
对象的终极奥义就是将程序”整合”
对象是”容器”,用来盛放数据与功能的
类也是”容器”,该容器用来存放同类对象共有的数据与功能
python这门语言到底提供了什么语法来允许我们将数据与功能很好地整合好一起呢???
程序=数据+功能
学生的容器=学生的数据+学生的功能
课程的容器=课程的数据+课程的功能
粉扑、眼影、各种颜料=》原材料=》数据
眉笔、小刷子 =》工具 =》功能
学生的功能
def tell_stu_info(stu_obj):
print('学生信息:名字:%s 年龄:%s 性别:%s' %(
stu_obj['stu_name'],
stu_obj['stu_age'],
stu_obj['stu_gender']
))
def set_info(stu_obj,x,y,z):
stu_obj['stu_name']=x
stu_obj['stu_age']=y
stu_obj['stu_gender']=z
stu_obj={
'stu_school':'oldboy',
'stu_name':'egon',
'stu_age':18,
'stu_gender':'male',
'tell_stu_info': tell_stu_info,
'set_info':set_info
}
stu1_obj={
'stu_school':'oldboy',
'stu_name':'lili',
'stu_age':19,
'stu_gender':'female',
'tell_stu_info': tell_stu_info,
'set_info':set_info
}
# 课程的数据
course_name='python'
course_period='6mons'
course_score=10
# 课程的功能
def tell_coure_info():
print('课程信息:名字:%s 周期:%s 学分:%s' %(course_name,course_period,course_score))
二、类
1、先定义类
类是对象相似数据与功能的集合体
所以类体中最常见的是变量与函数的定义,但是类体其实是可以包含任意其他代码的
注意:类体代码是在类定义阶段就会立即执行,会产生类的名称空间
class Student:
# 1、变量的定义
stu_school='oldboy'
# 2、功能的定义
def tell_stu_info(stu_obj):
print('学生信息:名字:%s 年龄:%s 性别:%s' %(
stu_obj['stu_name'],
stu_obj['stu_age'],
stu_obj['stu_gender']
))
def set_info(stu_obj,x,y,z):
stu_obj['stu_name']=x
stu_obj['stu_age']=y
stu_obj['stu_gender']=z
# print('========>')
# print(Student.__dict__)
# 属性访问的语法
# 1、访问数据属性
print(Student.stu_school) # Student.__dict__['stu_school']
# 2、访问函数属性
print(Student.set_info) # Student.__dict__['set_info']
# Student.x=1111 #Student.__dict__['x]=111
# print(Student.__dict__)
2、再调用类产生对象
stu1_obj=Student()
stu2_obj=Student()
stu3_obj=Student()
print(stu1obj.dict)
# print(stu2obj.dict)
# print(stu3_obj.__dict)
为对象定制自己独有的属性
# 问题1:代码重复
# 问题2:属性的查找顺序
# stu1obj.stuname=’egon’ # stu1obj.dict[‘stuname’]=’egon’
# stu1obj.stuage=18 # stu1obj.dict[‘stuage’]=18
# stu1_obj.stu_gender=’male’ # stu1_obj.__dict[‘stu_gender’]=’male’
# # print(stu1_obj.__dict)
#
# stu2_obj.stu_name=’lili’
# stu2_obj.stu_age=19
# stu2_obj.stu_gender=’female’
# # print(stu2_obj.__dict)
#
# stu3_obj.stu_name=’jack’
# stu3_obj.stu_age=20
# stu3_obj.stu_gender=’male’
# # print(stu2_obj.__dict)
解决问题一:
# 解决方案一:
# def init(obj,x,y,z):
# obj.stu_name=x
# obj.stu_age=y
# obj.stu_gender=z
#
# init(stu1_obj,’egon’,18,’male’)
# init(stu2_obj,’lili’,19,’female’)
# init(stu2_obj,’jack’,20,’male’)
解决方案二:
# 一:先定义类
class Student:
# 1、变量的定义
stu_school='oldboy'
# 空对象,'egon',18,'male'
def __init__(obj,x,y,z):
obj.stu_name=x # 空对象.stu_name='egon'
obj.stu_age=y # 空对象.stu_age=18
obj.stu_gender=z # 空对象.stu_gender='male'
# return None
# 2、功能的定义
def tell_stu_info(stu_obj):
print('学生信息:名字:%s 年龄:%s 性别:%s' %(
stu_obj['stu_name'],
stu_obj['stu_age'],
stu_obj['stu_gender']
))
def set_info(stu_obj,x,y,z):
stu_obj['stu_name']=x
stu_obj['stu_age']=y
stu_obj['stu_gender']=z
# print('========>')
# 二:再调用类产生对象
# 调用类的过程又称之为实例化,发生了三件事
# 1、先产生一个空对象
# 2、python会自动调用类中的__init__方法然将空对象已经调用类时括号内传入的参数一同传给__init__方法
# 3、返回初始完的对象
stu1_obj=Student('egon',18,'male') # Student.__init__(空对象,'egon',18,'male')
# stu2_obj=Student('lili',19,'female')
# stu3_obj=Student('jack',20,'male')
# print(stu1_obj.__dict__)
# print(stu2_obj.__dict__)
# print(stu3_obj.__dict__)
# 总结__init__方法
# 1、会在调用类时自动触发执行,用来为对象初始化自己独有的数据
# 2、__init__内应该存放是为对象初始化属性的功能,但是是可以存放任意其他代码,想要在
# 类调用时就立刻执行的代码都可以放到该方法内
# 3、__init__方法必须返回None
class Student:
# 1、变量的定义
stu_school=’oldboy’
count=0
# 空对象,'egon',18,'male'<br /> def __init__(self,x,y,z):<br /> Student.count += 1
self.stu_name=x # 空对象.stu_name='egon'<br /> self.stu_age=y # 空对象.stu_age=18<br /> self.stu_gender=z # 空对象.stu_gender='male'<br /> # return None
# 2、功能的定义<br /> def tell_stu_info(self):<br /> print('学生信息:名字:%s 年龄:%s 性别:%s' %(<br /> self.stu_name,<br /> self.stu_age,<br /> self.stu_gender<br /> ))
def set_info(self,x,y,z):<br /> self.stu_name=x<br /> self.stu_age=y<br /> self.stu_gender=z
def choose(self,x):<br /> print('正在选课')<br /> self.course=x
stu1obj=Student(‘egon’,18,’male’) # Student._init(空对象,’egon’,18,’male’)
stu2_obj=Student(‘lili’,19,’female’)
stu3_obj=Student(‘jack’,20,’male’)
print(stu1_obj.count)
# print(stu2_obj.count)
# print(stu3_obj.count)
类中存放的是对象共有的数据与功能
# 一:类可以访问:
# 1、类的数据属性
# print(Student.stu_school)
# 2、类的函数属性
# print(Student.tell_stu_info)
# print(Student.set_info)
二:但其实类中的东西是给对象用的
# 1、类的数据属性是共享给所有对象用的,大家访问的地址都一样
# print(id(Student.stu_school))
print(id(stu1_obj.stu_school))
# print(id(stu2_obj.stu_school))
# print(id(stu3_obj.stu_school))
Student.stu_school=’OLDBOY’
# stu1_obj.stu_school=’OLDBOY’
# print(stu1_obj.stu_school)
print(Student.stu_school)
# print(stu2_obj.stu_school)
# print(stu3_obj.stu_school)
2、类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同
类调用自己的函数属性必须严格按照函数的用法来
# print(Student.tell_stu_info)
# print(Student.set_info)
Student.tell_stu_info(stu1_obj)
# Student.tell_stu_info(stu2_obj)
# Student.tell_stu_info(stu3_obj)
Student.set_info(stu1_obj,’EGON’,19,’MALE’)
# Student.tell_stu_info(stu1_obj)
绑定方法的特殊之处在于:谁来调用绑定方法就会将谁当做第一个参数自动传入
# print(Student.tell_stu_info)
# print(stu1_obj.tell_stu_info)
# print(stu2_obj.tell_stu_info)
# print(stu3_obj.tell_stu_info)
stu1_obj.tell_stu_info() #tell_stu_info(stu1_obj)
# stu2_obj.tell_stu_info() #tell_stu_info(stu2_obj)
# stu3_obj.tell_stu_info() #tell_stu_info(stu3_obj)
# stu1_obj.choose(‘python全栈开发’)
# print(stu1_obj.course)
#
# stu2_obj.choose(‘linux运维’)
# print(stu2_obj.course)
#
# stu3_obj.choose(‘高级架构师’)
# print(stu3_obj.course)
l1=[‘aa’,’bb’,’cc’] # l=list([1,2,3])
l2=[111,222,333] # l=list([1,2,3])
# print(l1.append)
# print(list.append)
l1.append(‘dd’)
# l2.append(‘dd’)
# print(l1)
# print(l2)
list.append(l1,’dd’)
# list.append(l2,’dd’)
# print(l1)
# print(l2)
三、封装
1、封装介绍
2、将封装的属性进行隐藏操作
1、如何隐藏:在属性名前加前缀,就会实现一个对外隐藏属性效果
该隐藏需要注意的问题:
I:在类外部无法直接访问双下滑线开头的属性,但知道了类名和属性名就可以拼出名字:_类名属性,然后就可以访问了,如Foo._A__N,
所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。
class Foo:
__x = 1 # _Foo__x
def __f1(self): # _Foo__f1
print('from test')
# print(Foo.__dict__)
# print(Foo._Foo__x)
# print(Foo._Foo__f1)
II:这种隐藏对外不对内,因为__开头的属性会在检查类体代码语法时统一发生变形
class Foo:
__x = 1 # _Foo__x = 1
def __f1(self): # _Foo__f1
print('from test')
def f2(self):
print(self.__x) # print(self._Foo__x)
print(self.__f1) # print(self._Foo__f1)
print(Foo.__x)
print(Foo.__f1)
obj=Foo()
obj.f2()
III: 这种变形操作只在检查类体语法的时候发生一次,之后定义的__开头的属性都不会变形
class Foo:
__x = 1 # _Foo__x = 1
def __f1(self): # _Foo__f1
print('from test')
def f2(self):
print(self.__x) # print(self._Foo__x)
print(self.__f1) # print(self._Foo__f1)
Foo.__y=3
print(Foo.__dict__)
print(Foo.__y)
class Foo:
__x = 1 # _Foo__x = 1
def __init__(self,name,age):
self.__name=name
self.__age=age
obj=Foo('egon',18)
print(obj.__dict__)
print(obj.name,obj.age)
3、为何要隐藏?
I、隐藏数据属性”将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制:
# 设计者:egon
class People:
def __init__(self, name):
self.__name = name
def get_name(self):
# 通过该接口就可以间接地访问到名字属性
# print('小垃圾,不让看')
print(self.__name)
def set_name(self,val):
if type(val) is not str:
print('小垃圾,必须传字符串类型')
return
self.__name=val
# 使用者:王鹏
obj = People('egon')
# print(obj.name) # 无法直接用名字属性
# obj.set_name('EGON')
obj.set_name(123123123)
obj.get_name()
II、隐藏函数/方法属性:目的的是为了隔离复杂度
四、proerty
装饰器是在不修改被装饰对象源代码以及调用方式的前提下为被装饰对象添加
新功能的可调用对象
print(property)
property是一个装饰器,是用来绑定给对象的方法伪造成一个数据属性
“””
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
“””
案例一:
class People:
def __init__(self, name, weight, height):
self.name = name
self.weight = weight
self.height = height
# 定义函数的原因1:
# 1、从bmi的公式上看,bmi应该是触发功能计算得到的
# 2、bmi是随着身高、体重的变化而动态变化的,不是一个固定的值
# 说白了,每次都是需要临时计算得到的
# 但是bmi听起来更像是一个数据属性,而非功能
@property
def bmi(self):
return self.weight / (self.height ** 2)
obj1 = People('egon', 70, 1.83)
print(obj1.bmi())
obj1.height=1.86
print(obj1.bmi())
print(obj1.bmi)
案例二(老方法):
class People:
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_name(self, val):
if type(val) is not str:
print('必须传入str类型')
return
self.__name = val
def del_name(self):
print('不让删除')
# del self.__name
name=property(get_name,set_name,del_name)
obj1=People('egon')
# print(obj1.get_name())
# obj1.set_name('EGON')
# print(obj1.get_name())
# obj1.del_name()
# 人正常的思维逻辑
print(obj1.name) #
# obj1.name=18
# del obj1.name
案例三(推荐):
class People:
def __init__(self, name):
self.__name = name
@property
def name(self): # obj1.name
return self.__name
@name.setter
def name(self, val): # obj1.name='EGON'
if type(val) is not str:
print('必须传入str类型')
return
self.__name = val
@name.deleter
def name(self): # del obj1.name
print('不让删除')
# del self.__name
obj1=People('egon')
# 人正常的思维逻辑
print(obj1.name) #
# obj1.name=18
# del obj1.name
五、继承
1、什么是继承
I:继承是一种创建新类的方式,新建的类可称为子类或派生类,父类又可称为基类或超类,子类会遗传父类的属性
II:需要注意的是:python支持多继承
在Python中,新建的类可以继承一个或多个父类
class Parent1(object):
x=1111
class Parent2(object):
pass
class Sub1(Parent1): # 单继承
pass
class Sub2(Parent1,Parent2): # 多继承
pass
print(Sub1.__bases__)
print(Sub2.__bases__)
print(Sub1.x)
ps1: 在python2中有经典类与新式类之分
新式类:继承了object类的子类,以及该子类的子类子子类。。。
经典:没有继承object类的子类,以及该子类的子类子子类。。。
ps2:在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都是新式类
print(Parent1.bases)
print(Parent2.bases)
III:python的多继承
优点:子类可以同时遗传多个父类的属性,最大限度地重用代码
缺点:
1、违背人的思维习惯:继承表达的是一种什么”是”什么的关系
2、代码可读性会变差
3、不建议使用多继承,有可能会引发可恶的菱形问题,扩展性变差,
如果真的涉及到一个子类不可避免地要重用多个父类的属性,应该使用Mixins
2、为何要用继承
3、如何实现继承
示范1:类与类之间存在冗余问题
class Student:
school='OLDBOY'
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def choose_course(self):
print('学生%s 正在选课' %self.name)
class Teacher:
school='OLDBOY'
def __init__(self,name,age,sex,salary,level):
self.name=name
self.age=age
self.sex=sex
self.salary=salary
self.level=level
def score(self):
print('老师 %s 正在给学生打分' %self.name)
示范2:基于继承解决类与类之间的冗余问题
class OldboyPeople:
school = 'OLDBOY'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Student(OldboyPeople):
def choose_course(self):
print('学生%s 正在选课' % self.name)
# stu_obj = Student('lili', 18, 'female')
# print(stu_obj.__dict__)
# print(stu_obj.school)
# stu_obj.choose_course()
class Teacher(OldboyPeople):
# 老师的空对象,'egon',18,'male',3000,10
def __init__(self, name, age, sex, salary, level):
# 指名道姓地跟父类OldboyPeople去要__init__
OldboyPeople.__init__(self,name,age, sex)
self.salary = salary
self.level = level
def score(self):
print('老师 %s 正在给学生打分' % self.name)
tea_obj=Teacher('egon',18,'male',3000,10)
# print(tea_obj.__dict__)
# print(tea_obj.school)
tea_obj.score()
4、单继承背景下的属性查找
示范一:
子类函数覆盖父类
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1() # obj.f1()
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj=Bar()
obj.f2()
# Foo.f2
# Bar.f1
示范二:
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
Foo.f1(self) # 调用当前类中的f1
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj=Bar()
obj.f2()
# Foo.f2
# Foo.f1
示范三:
class Foo:
def __f1(self): # _Foo__f1
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.__f1() # self._Foo__f1,# 调用当前类中的f1
class Bar(Foo):
def __f1(self): # _Bar__f1
print('Bar.f1')
obj=Bar()
obj.f2()
# Foo.f2
# Foo.f1
六、菱形问题
1、菱形问题介绍与MRO
.mro列出继承类的查找列表
class A(object):
# def test(self):
# print('from A')
pass
class B(A):
def test(self):
print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(C,B):
# def test(self):
# print('from D')
pass
print(D.mro()) # 类D以及类D的对象访问属性都是参照该类的mro列表
# obj = D()
# obj.test()
# print(D.test)
# print(C.mro()) # 类C以及类C的对象访问属性都是参照该类的mro列表
# c=C()
# c.test()
总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro
2、如果多继承是非菱形继承
经典类与新式的属性查找顺序一样:
都是一个分支一个分支地找下去,然后最后找object
class E:
# def test(self):
# print('from E')
pass
class F:
def test(self):
print('from F')
class B(E):
# def test(self):
# print('from B')
pass
class C(F):
# def test(self):
# print('from C')
pass
class D:
def test(self):
print('from D')
class A(B, C, D):
# def test(self):
# print('from A')
pass
# 新式类
# print(A.mro()) # A->B->E->C->F->D->object
obj = A()
obj.test() # 结果为:from F
3、如果多继承是菱形继承
经典类与新式类的属性查找顺序不一样:
经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索大脑袋(共同的父类)
新式类:广度优先,会在检索最后一条分支的时候检索大脑袋
class G: # 在python2中,未继承object的类及其子类,都是经典类
# def test(self):
# print('from G')
pass
class E(G):
# def test(self):
# print('from E')
pass
class F(G):
def test(self):
print('from F')
class B(E):
# def test(self):
# print('from B')
pass
class C(F):
def test(self):
print('from C')
class D(G):
def test(self):
print('from D')
class A(B,C,D):
# def test(self):
# print('from A')
pass
# 新式类
# print(A.mro()) # A->B->E->C->F->D->G->object
# 经典类:A->B->E->G->C->F->D
obj = A()
obj.test() #
总结:
多继承到底要不用???
要用,但是规避几点问题
1、 继承结构尽量不要过于复杂
2、推荐使用mixins机制:在多继承的背景下满足继承的什么”是”什么的关系
七、Mixins机制
多继承的正确打开方式:mixins机制
mixins机制核心:就是在多继承背景下尽可能地提升多继承的可读性
ps:让多继承满足人的思维习惯=》什么”是”什么
class Vehicle:
pass
class FlyableMixin:
def fly(self):
pass
class CivilAircraft(FlyableMixin,Vehicle): # 民航飞机
pass
class Helicopter(FlyableMixin,Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
pass
import socketserver
补充:通常Mixin结果的类放在左边
八、在子类派生的新方法中如何重用父类的功能
方式一:指名道姓调用某一个类下的函数=》不依赖于继承关系
class OldboyPeople:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def f1(self):
print('%s say hello' %self.name)
class Teacher(OldboyPeople):
def __init__(self,name,age,sex,level,salary):
OldboyPeople.__init__(self,name,age,sex)
self.level = level
self.salary=salary
tea_obj=Teacher('egon',18,'male',10,3000)
print(tea_obj.__dict__)
方式二:super()调用父类提供给自己的方法=》严格依赖继承关系
调用super()会得到一个特殊的对象,该对象会参照发起属性查找的那个类的mro,去当前类的父类中找属性
class OldboyPeople:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def f1(self):
print('%s say hello' %self.name)
class Teacher(OldboyPeople):
def __init__(self,name,age,sex,level,salary):
# super(Teacher,self).__init__(name,age,sex)
super().__init__(name,age,sex) # 调用的是方法,自动传入对象
self.level = level
self.salary=salary
# print(Teacher.mro())
tea_obj=Teacher('egon',18,'male',10,3000)
print(tea_obj.__dict__)
super()案例
class A:
def test(self):
print('from A')
super().test()
class B:
def test(self):
print('from B')
class C(A,B):
pass
obj=C()
obj.test()
print(C.mro())
class A:
def test(self):
print('from A')
super().test1()
class B:
def test(self):
print('from B')
class C(A,B):
def test1(self):
print('from C')
obj=C()
obj.test()
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# 报错,
九、多态与鸭子类
1、什么多态:
同一事物有多种形态
class Animal:
pass
class People(Animal):
pass
class Dog(Animal):
pass
class Pig(Animal):
pass
2、为何要有多态
多态会带来什么样的特性,多态性
多态性指的是可以在不考虑对象具体类型的情况下而直接使用对象
class Animal: # 统一所有子类的方法
def say(self):
print('动物基本的发声频率。。。',end=' ')
class People(Animal):
def say(self):
super().say()
print('嘤嘤嘤嘤嘤嘤嘤')
class Dog(Animal):
def say(self):
super().say()
print('汪汪汪')
class Pig(Animal):
def say(self):
super().say()
print('哼哼哼')
obj1=People()
obj2=Dog()
obj3=Pig()
obj2.say()
obj3.say()
# 定义统一的接口,接收传入的动物对象
def animal_say(animal):
animal.say()
animal_say(obj1)
animal_say(obj2)
animal_say(obj3)
python推崇的是鸭子类型
走路摇摇晃晃就是鸭子
class Cpu:
def read(self):
print('cpu read')
def write(self):
print('cpu write')
class Mem:
def read(self):
print('mem read')
def write(self):
print('mem write')
class Txt:
def read(self):
print('txt read')
def write(self):
print('txt write')
obj1=Cpu()
obj2=Mem()
obj3=Txt()
obj1.read()
obj1.write()
obj2.read()
obj2.write()
obj3.read()
obj3.write()
了解:
import abc
class Animal(metaclass=abc.ABCMeta): # 统一所有子类的标准
@abc.abstractmethod
def say(self):
pass
# obj=Animal() # 不能实例化抽象类自己
class People(Animal):
def say(self):
pass
class Dog(Animal):
def say(self):
pass
class Pig(Animal):
def say(self):
pass
#
# obj1=People()
# obj2=Dog()
# obj3=Pig()
十、绑定方法与非绑定方法
一:绑定方法:特殊之处在于将调用者本身当做第一个参数自动传入
1、绑定给对象的方法:调用者是对象,自动传入的是对象
2、绑定给类的方法:调用者类,自动传入的是类
classmethod
import settings
class Mysql:
def __init__(self,ip,port):
self.ip=ip
self.port=port
def func(self):
print('%s:%s' %(self.ip,self.port))
@classmethod # 将下面的函数装饰成绑定给类的方法
def from_conf(cls):
print(cls)
return cls(settings.IP, settings.PORT)
# obj1=Mysql('1.1.1.1',3306)
obj2=Mysql.from_conf()
print(obj2.__dict__)
二:非绑定方法-》静态方法:
没有绑定给任何人:调用者可以是类、对象,没有自动传参的效果
class Mysql:
def __init__(self,ip,port):
self.nid=self.create_id()
self.ip=ip
self.port=port
@staticmethod # 将下述函数装饰成一个静态方法
def create_id():
import uuid
return uuid.uuid4()
@classmethod
def f1(cls):
pass
def f2(self):
pass
obj1=Mysql('1.1.1.1',3306)
# print(Mysql.create_id)
# print(obj1.create_id)
# Mysql.create_id(1,2,3)
# obj1.create_id(4,5,6)
print(Mysql.create_id)
print(Mysql.f1)
print(obj1.f2)