面向对象概念
面向过程
也就是过程,解决过程的流程,相当于流水线一样的
把问题流程化
优点:
将复杂的流程简单化
缺点:
可扩展性差
面向对象
对象:特征与技能的结合体
有点:
可扩展性强
缺点:
编程复杂高
应用场景:
用户需求经常变化,游戏,企业内的应用
类就是一系列对象相似特征与技能的结合体
强调:站在不同的角度中,得到的分离是不同的
在现实世界:现有对象后总结出来类
在编程世界:先定义类,后调用类来产生对象
# 抽象: 抽取相同的地方
一切接对象
站在不同的角度上 定义的类是不同的
现实中的类不等于程序中的类 现实中的公司类,在程序中要拆分到部门,业务
有是为了编程需求 程序中定义的类在现实中是不存在的,比如策略类 显示中是不存在的,但是在程序中非常常见
python 一切皆对象 在python3中的统一类类型的概念
比如:
class list 类 只是继承了 列表相似的功能进去
# 这两对象实例化是一个不同过的对象
# 那么对象中的方法也是不同
l1 = [1,2,3] # l = list([1,2,3])
l2 = [1,2,4] # l = list([1,2,4])
那么 l 变量就是list class类的实例化对象 name l 就可以使用list中的那个方法
比如: l.append()
Class基础语法关键字
class 类名:
def 方法名(self,参数1,参数2.....):
pass
执行类:
对象 实例化类
实例对象=类名()
实例对象.方法名(参数1,参数2...)
案例:
class Name(object): # 创建对象
def get_name(self): # 创建对象中的方法
return 'name'
# name 对象 Name() 实例化类
name = Name()
# 利用对象调用内部方法
name.get_name()
1.初始化方法init
在实例化对象时,会自动触发__init__方法
class 中的 name = Name() 被称为实例化对象
1.init方法的定义
class 类名:
def __init(self):
pass
2.对实例变量进行定义(当前类下的全部方法都可以使用)
class C:
def __init(self,val):
# 参数的传递:1.通过实例对象传递 2.通过自定义传递
self.val = val # val是在实例化对象时传入参数123 实例变量
self.a = '777' # 自行定义的实例变量
C('123')
3.__init__的过程
1.执行class()实例化
2.在执行对class进行实例化时 会限制性__new__(cls)方法 创建一个内存区域 cls参数就是当前类本身
3.才会执行__init__(self,)方法self 是内部提供的参数,内部存储的是基于实例化的一个内存区域(默认为空),使用__init__方法可以将数据存储在方法中,通过self进行调用存储的数据
4.self 是个参数接收了class的实例化在new方法执行完毕创建内存区域后,init方法接收并且将方法参数存储到内存区域,使用self进行调用
4.当实例化两个对象时 内存地址时不同的
class Name(object): # 创建对象
def __init__(self):
print('我是init方法') # 后执行
def __new__(cls, *more):
print('我是new方法') # 先执行
return super().__new__(cls, *more)
# name 对象 Name() 实例化类
name = Name()
print(id(name)) # 2140846747360
name2 = Name()
print(id(name2)) # 2140846747120
实例化时 将对象当成参数传入到self中,self内是一个内存区域,存放着类中的方法和数据。
2.class的成员修饰符
1.成员 类变量 实例变量
实例变量:封装到实例化对象中,只有实例化对象才能调用,在类中属于局部变量
类变量: 封装到类中,类可以调用同时实例化对象也可以调用,在类中属于全局变量
class N(object):
age = 18 # 类变量
def __init__(self, name):
self.name = name # 实例变量
n = N('zss') # 实例化对象
print(n.age) # 实例化对象调用age 打印18
print(n.name) # 实例化对象调用name 打印zss
print(N.age) # 类只能调用类变量无法调用实例变量
# 备注:
优先去实例变量中找,找不到,去类变量找
2.对类内部的变量进行添加与修改
class N(object):
age = 18
def __init__(self, name):
self.name = name
n = N('zss')
n.name = '修改实例变量' # 修改
n.type = '添加一个实例变量' # 添加
N.age = 999 # 修改类变量
N.pee = '添加类变量' # 添加类变量
通过 n.__dict__ 查看实例对象中全部的内容(只有__init__的变量)
通过 N.__dict__ 查看类中的全部内容(不包过__init__的变量)
读:如果实例变量中没有,就去类变量中找
写:类添加和实例变量添加,不受影响,使用类名就是类添加变量,使用对象就是实例变量添加
2.成员修饰符
# 区别
公有:任何地方都可以调用
私有:只能在自己类中使用
定义:__双下划线定义
class N(object):
def __init__(self, name, age):
self.name = name # 公有的实例变量,任何地方都可以调用
self.__age = age # 私有的实例变量,只能在内部使用
def __func(self): # 私有方法
pass
def func2(self): # 共有方法
pass
n = N('zss', 18)
# 怎么实现调用类中的私有方法
class N(object):
def __init__(self, name, age):
self.name = name
self.__age = age
def __func(self):
pass
因为共有方法可以被外部调用,私有只能被内部调用,那么就使用外部调用内部
def func2(self): # 使用共有调用私有
self.__func()
print(self.__age)
n = N('zss', 18)
n.func2()
# 关于共有与私有的使用
1.想要外部调用就是公有
2.想要内部成员只是作为辅助其他成员 就用私有
3.成员是否作为独立功能暴露给外部,让外部调用
3.外部硬执行私有方法变量
案例:
class foo:
def __init__(self,a1,a2):
self.a1 =a1
self.__a2 =a2
def __f1(self):
pass
def f2(self):
self.__f1
obj = foo() # 实例化
#调用内部私有变量
print(obj._foo__a2) #实例化对象._类名 私有成员
#调用内部私有方法
obj._foo__f1() #实例化对象._类名 私有方法
3.使用类封装分页方法
class Pagination:
def __init__(self, current_page, per_pagr_num=10):
self.per_pagr_num = per_pagr_num #实例化默认值
if current_page.isdecimal():
# 判断起始值,如果输入的不是数字,起始值就等于1
self.current_page = 1
return
current_page = int(current_page) # 转换为init类型
if current_page < 1:
#判断起始值,如果起始值小于1,起始值等于1
self.current_page = 1
return
# 实例化起始值
self.current_page = current_page
# 在__init__ 方法中设置值,并且执行一些代码。经过判断后将起始值进行实例化
@property # 定义为属性 不要加括号进行调用执行
def start(self): # 起始位置
#返回 起始值-1*默认值,起始位置
return (self.current_page - 1) * self.per_pagr_num
@property
def end(self):
# 返会 尾部 起始*默认值
return self.current_page * self.per_pagr_num
# 每次浏览10个数据
list = [1w数据]
if __name__ == "__main__":
while True:
page = input(">>>")
pa_object=Pagination(page,10) # 获取实例化对象,将用户输入的值传进去
list_object = list[pa_object.start:pa_object.end] # 进行切片,实例化对象调用 类中的起始方法和尾部方法
for i in list_object:
print(i) # 将切片的内容进行循环打印
4.class的3大特征封装继承多态
1.封装
特征:
封装,继承,多态
1.封装
# 封装方法:隔离复杂度
# 将类内部的复杂类型给隐藏起来
# 将简单的接口暴露给用户,将复杂的流程隐藏起来
分装的扩展性:
使用者不需要知道内部的逻辑,只需要接口的怎么调用就可以
创建者,只需要将内部的逻辑编写完整,将需要暴露的外部接口暴露就可以
体现在两个方面
1.将同一类方法封装到类中 :西瓜和苹果都是水果类的
2.将数据封装到对象中,在实例化对象时,通过__init__初始化方法封装到实例化的对象中
便于以后使用
封装的体现:
class 信息:
def __init__(self,n1)
self.n1 = n1
def 发微信(self):
print(self.n1)
def 发短信(self):
print(self.n1)
def 发微博(self):
print(self.n1)
对象 = 信息(xxxxxxxxx) # 在实例化时将数据封装到类中
对象 = 信息() 将类中的方法 封装到对象中(变量),通过对象进行调用
对象.发短信()... # 公用一个参数实现不同的效果
1.对类进行实例化时
2.执行init方法,init的n1接受传入的值
3.在将数据封装到 init方法中 self.n1 = n1
4.在内存区域开辟一个 存储 n1 = n1的数据
5.对象 会成为参数传入到self的内存中 self内部就存储这信息类的方法和数据
4.总结
总结:
1.封装:将方法,数据封装到对象中,便于以后使用
2.继承:将功能中的公共方法放到父类中,让子类继承使用
3.多态:python参数是多态的,但是内部的方法是有约束的,只有相同的方法,才可以
2.继承
1.继承
继承的作用:增加代码的复用性,类与类之间的关系,解决代码的冗余问题,重用性提高
两个类同时都有一个方法,那么可以将方法重新创建一个类,放另外两个类继承。
子类可以继承父类的方法和类变量(数据)(不属于拷贝,父类的还是父类的,子类可以用)
class Base:
def func(self):
pass
class Son(Base): son类继承了 base类
def show(self):
pass
class Func(Base):
pass
son = Son()
son.show()
func = Func()
func.show() # 优先在自己的类中去找,没有就去父级中去找.
# 继承的类被成为 父类和基类
# 被继承的类被成为 派生类的子类
类.__bases__ # 查看当前的继承关系
类名.mro() # 查看继承关系
2.类的查询方法
查找的方式:
深度优先 和 广度优先
只有在python2中 分为 新式类 和 经典类之分
在python2中 子类和父类没有继承object类
class A: # 经典类
pass
class B(A):
pass
在python2中继承了object类 被称为新式类
class A(object): # 新式类
pass
class B(A):
pass
在python3 默认基础object 都是新式类
class A:
pass
print(A.__bases__) # (<class 'object'>,)
新式类与经典类查找顺序不同
经典类: 是深度优先
例如:
class A(B,C,D)
pass
先从继承的B类开始一直找到B类的父类的尽头
在去继承的C类开始找找到C类父类的尽头
在去找继承D类父类的尽头
新式类: 是广度优先
最深的继承的类不会先找,而是平行到相邻类中找,到最后在找最深的继承类
3.多态
3.多态
传入的数据类型多种形态的(参数时多种形态,传入的参数都必须要有同样的方法)
方法是有约束的,参数时多态的任意类型,函数内部调用的方法规则
多态性是面向对象编程的又一个重要特征,它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义
值的是可以不在考虑对象的类型下而直接使用对象本身
增加程序的灵活性
增加程序的扩展性
鸭子类型:
根本不用在乎多种类型的使用
例如:
开车,只要学会开车,那么全部的类型车就可以开(奥迪....)
鸭子类型:
比如:
不让子类继承父类(强制的abc.ABCMeta抽象类)
而是让子类模拟父类
代码比喻:
文件类型类 有读 和写文件
class File:
def read(slfe):
pass
def write(self):
pass
# 磁盘类
class Disk:
def read(slfe):
pass
def write(self):
pass
# text 类
class Text:
def read(slfe):
pass
def write(self):
pass
def func(obj):
obj.read()
他们有都是由两个方式 read 和 write 两种方式
text = Text()
disk = Disk()
# 这中就是鸭子类型 有相同的方法或者方式 但是没有什么直接的关系
# Python崇尚的就是 只要像鸭子,走路像,叫声像 就可以
# 不用考虑类像的具体类型
text.read()
disk.read()
5.super的用法
也就是,当自己类中派生的存在,那么就是用自己的,不在使用父类的属性
现在对象中的找对象的命名空间中,在从对象当前类中的找,在去父类中找
class A:
def __init__(self):
pass
def show(self):
print(123)
class Func(A):
name = 123 # 这就是派生属性
def show(self):
print(456)
f = Func()
f.show() 那么他就是还是用自己的类中的show方法
******* 在子类中重用父类的属性 *****
# 指明道姓的方法式进行使用初始化方法 不依赖继承
class A:
def __init__(self, name):
self.name = name
def show(self, age):
print(123)
class B(A):
#def __init__(self,name,age):
#self.name = name
#self.age = age # 子类在初始值中需要多添加一个,那么就是重写init方法
def __init__(self,name,age)
A.__init__(self,name) # 那么就是用指明道姓的方式进行调用父类原有的init方法
self.age = age
def show(self, age):
# 在子类中使用父类的方法和属性
A.show(self, age) # 1.指明道姓的使用,没有使用到继承的概念,而是使用了类名调用内部方法函数
print(4456)
b = B('123')
b.show(666)
******** super() **********
2. 第二种情况子类需要有自己的初始化方法,进行对象的独特的值
使用super可以 对象的方式进行调用父类的中的方法
使用 super() 依赖继承 具体依赖是那个类的实例化对象,他存在的mro继承关系,而不是取决于super() 存在那个类
class A:
def __init__(self, name):
self.name = name
def func(self):
print(123)
# super 是在mro列表中 进行继承 按照mro继承顺序去找方法
# super 是按照当前 实例化对象的mro 列表进行找继承关系,不是super在那个类中,他就是那个类的
class B(A):
def __init__(self, name, age):
# python2需要将自己的类名,与self实例化对象与参数传入
# super(B, self).__init__(name)
# python3 可以省略掉super内的参数
super().__init__(name)
self.age = age
def show(self):
# 子类使用super(自己的类名,当前的实例化对象self)
super(B, self).func()
b = B('HAHA',18)
b.show()
抽象类的使用与概念
python 提供了抽象类的概念,提供了一个接口的方式
模仿java 模仿 interface接口
抽象类:将全部的类抽取比较像的部分,形成一个父类,让子类继承父类必须使用当前的父类的方法,必须让继承父类的子类必须按照父类的规定进行使用
import abc # 1.导入abc模块
# 继承metaclass=abc.ABCMeta ,那么这个子类继承当前的父类必须强制的使用内部的方法名
# 这个类只做规范,不完成具体的效果
# 通过抽象类,实现子类的规范
# 抽象类,只能被继承不能被实例化
# 抽象类,本质上还是一个类,还是可以遵从类属性的查找原则
class Animal(metaclass=abc.ABCMeta): # 2.定义抽象类,继承metaclass=abc.ABCMeta
@abc.abstractmethod # 3.强制规范继承子类的中的方法
def run(self):
pass
@abc.abstractmethod
def eat(self):
pass
# 只要子类继承了当前的父类方法 就必须实现当前内部的方法
class People(Animal):
def run(self):
print('people')
def eat(self):
pass
凡是继承当前抽象类,那么必须定义父类中的定义的方法,那怕不实现也可以
进阶使用
1.类中的3种方法
1.绑定方法 __init__(self)方法 :对象调用
默认参数时self,self代指实例对象,内部存放着类的方法和实例变量/类变量
2.类方法 @classnethod :类名调用
默认参数 cls ,cls就是代指这整个类。作用:在方法内部使用 类 就用类方法
3.静态方法 @staticmethod :类名调用
无默认参数,作用:如果方法内部只是一些简单的逻辑,不适用参数,就可以使用静态方法
使用方式案例:
class foo:
def __init__(self):
pass
#绑定方法,用的最多
def show1(self): self 指向 实例对像 a
pass
@classmethod # 类方法
def show2(cls): # cls 指向 类名 foo
pass
@staticmethod #静态方法
def show3():
pass
a = foo() # 实例化对象
a.show1() #绑定方法调用
foo.show2() #类方法调用 当执行时,将类当成参数 传入show2 第一个参数cls
foo.show3() #静态方法
绑定方法的特殊
1.使用类名进行调用内部的方法函数时,需要对应的传入指定的位置参数self
而且类名调用的方法函数,就是一个普通的函数
2.绑定方法是给实例化对象使用,绑定不同的对象效果也是不同的
而对象调用内部的方法函数时,默认自动将对象本身传入到方法函数中的self中
也就是 a1.learn(a1) 将对应本身默认传入参数
总结:对象来调用自己内部的绑定方法时,会将对象本身当为第一个参数(self)传入到方法中
剩余的参数,该怎么传入就怎么传入
类中的方法函数,是给对象使用,那个对象来调用,就将他当为第一个参数传入
如果对象的名称空间中这个参数存在,那么就是用对象的名称空间中的
如果名称空间中的参数不存在,就会使用类中的参数
和函数中的局部和全局的概念是相同的意思
如果对象名称空间(局部)不存在的,那么就使用类空间中的(全局的)
当找不到也不会去类外部找
绑定方法 如果用类名调用内部的方法是不同函数 用对象调用方法是绑定函数 同时他们的内存地址是不同的
# 注意当使用类去调用内部的函数时,需要对应的传入self位置参数 类本身传递进去
# 使用对象调用,那么会自动将对象本身传递到self中
2.类中的三个特殊属性property
属性是由绑定方法和装饰器组成的。
class Func:
@property # 使用最多
def func1(self):
print('执行property')
@func1.setter # 很少 不能使用func2作为装饰对象 因为不存在
def func2(self, val): # val接收赋值
print(val)
@func1.deleter # 很少 不能使用func3作为装饰对象,因为不存在
def func3(self):
print('deleter')
a = Func()
a.func1
a.func2 = 123 # 将123赋值给val 同时执行当前函数
del a.func3 # 不是删除只是执行
方法1:
定义规则:@方法名.setter,方法中需要多加一个value参数
使用方式:a.func2 = 123 参数value可以接受 添加的值
方法2:
定义规则:在方法上加入:@property
使用方法:a.func 在调用方法时可以不用加括号
方法3:
定义规则:@方法名.deleter
使用方式:del a.func3 执行方法
3.类中的其他方法内置1
class Func:
# 初始化方法
# 实例化对象时自动触发,实例化类是时传入的参数会存放在self,self代指对象
def __init__(self, name):
self.name = name
# 构造方法
def __new__(cls, *args, **kwargs):
# 在实例化对象 先执行 __new__,创建一个空的对象,返回给 init 的 self中
return object.__new__(cls)
# 字符串方法 当进行打印类时,就会直行str方法 可以对类进行说明
def __str__(self):
return "这是一个不同的方法类" # 执行str 必须返回一个字符串,或者返回类中的变量,变量必须是字符串类型
# 字典方法 在类中定义后调用返回当前定义的内容
@property
def __dict__(self):
return '7788'
# 如果不在类中使用 那么会将init 初始化的变量以字典形式返回
'''
例如:
class A:
def __init__(self,a1,a2):
self.a1 =a1
self.a2 =a2
A = A(11,12)
print(A.__dict__) # {'a1': 11, 'a2': 12}
'''
a = Func('zzz')
4.类方法其他方法内置2
class Func:
def __call__(self, *args, **kwargs):
print(args, kwargs) # ('666', '777') {}
return '110'
a = Func()
print(a('666', '777')) # 打印返回值 110
call 作用使实例化对象需要加括号进行调用执行的方法
当实例对象('可以传入参数') 就会直行call方法,不会影响类中的其他方法调用
5.类方法其他方法3
字典支持 对象["xx"]取值 对象["xx"] =123 赋值 del 对象["xx"] 删除键值对
__setitem__ __getitem__ __delitem__
class Func:
def __setitem__(self, key, value):
'''字典赋值操作'''
print(key, value)
def __getitem__(self, item):
'''字典get操作'''
print(item)
def __delitem__(self, key):
'''字典的删除操作'''
print(key)
a = Func()
a['666'] = 777 # 执行setitem
a['666'] # 执行getitem
del a['666'] # 执行delitem
当时实例对象按照字典形式执行方式时 会触发当前三个方法
6.类方法其他方法4
让对象支持with 上下文语法 执行
class Func:
def __enter__(self): # 在操作之前执行操作
return '测试执行中'
def __exit__(self,*args,**kwargs): # 在操作之后在执行别的代码
print('执行结束')
a = Func()
with a as e:
print(e)
'''
1.先执行__enter__方法 返回值赋值给e
2.执行完毕__enter__方法才会执行 __exit__方法
'''
让两个实例对象进行加减
#让两个实例对象进行相加
class A():
def__add__(self,other):
return # 想让他返回什么就返回是什么,v3获得返回值
a = A() # 实例化
a1= A() # 实例化
v3 = a+a1 # 当两个对象相加时执行add方法 +号后面的对象当成参数传入 other中
# v3 等于 add 返回的结果
7.类方法其他方法5
迭代器的定义:
1.在定义类 中 必须有__iter__ 和__next__两个方法
2.__iter__ 返回对象本身 就是 self,将self返回
3.__next__ 返回下一个数据,没有数据就执行 stopiteration异常
迭代器的定义:
1.在定义类 中 必须有__iter__ 和__next__两个方法
2.__iter__ 返回对象本身 就是 self,将self返回
3.__next__ 返回下一个数据,没有数据就执行 stopiteration异常
迭代器类
class A(object):
def __init__(self):
self.count = 0
def __iter__(self): # 条件1
return self # 条件3
def __next__(self): # 条件2
self.count +=1
if self.count == 3:
raise stopiteration()
return self.count
# 符合三个条件
a = A() # 迭代器对象
# 方法1:
v1 = next(a) 1
v2 = next(a) 2
v3 = next(a) 抛出异常
# 方法2:
for i in a : # for循环内部自动执行next
print(i)
#先执行 __iter__ 方法 获取返回值 self
#for循环内部自动执行next
#当结束后,抛出异常
#for循环依赖于迭代器一个个取值
#内部先执行 __iter__ 并获取迭代器对象,不断的执行迭代器对象next方法
生成器
生成器属于迭代器的一种
def func():
yield 1
# 创建生成器对象(根据生成器类generator创建对象)
# 内部声明两个方法: __iter__ 和__next__两个方法
# 可以通过 next() 取值 也可以通过for循环取值
#for 循环取值
#内部先执行 __iter__ 并获取迭代器对象,不断的执行迭代器对象next方法
可迭代对象
# 定义:如果类中有 __iter__ 且返回一个迭代对象,就成为这个类是可迭代对象
class A(object):
def __iter__(self):
return #迭代器对象 也可以返回生成器对象
a = A()
#a 被成为可迭代对象
# 可以被for 循环
for i in a :
pass
可迭代对象和迭代器组合
class A(object):
def __init__(self):
self.count = 0
def __iter__(self):
return self
def __next__(self):
self.count +=1
if self.count == 3:
raise stopiteration()
return self.count
class A1(object):
def __iter__(self):
return A()可迭代对象
for i in A1():
print(i)
8.类中的内置方法总结
1.@classmethod 类方法 参数cls
2.@staticmethod 静态方法 无参数
3.@property 在执行类中的方法时不用加括号
4.callable(函数名) 判断执行对象是否后面可以加括号
5.super() 按照mro的方法向上找到父类成员关系(优先取找父级的方法) 如果父类没有,就会报错
6.type ,获取对象的类型
7.isinstance(实例化对象,父类) 判断对象是不是某个类的继承或者子类 返回True/False
8.issubclass() 判断是否是类的子孙类 返回True/False
9.类使用嵌套
class student(object):
#学生
def __init__(self,name,age):
self.name = name
self.aeg = age
def messaage(self):
data = "{},{}".format(self.name ,self.aeg)
print(data)
class classes(object):
#班级
def __init__(self,title):
self.title = title
self.student_list = []
def add_student(self,stu_object): # 传入单个值
self.student_list.append(stu_object)
def add_students(self,stu_object_list): #传入一个列表
for i in stu_object_list:
self.add_student(i)
def show_members(self):
for i in self.student_list:
print(i)
s1 = student("123",12) #s1 是一个学生对象 student类的全部的方法和变量
s2 = student("4565",13) #s1 是一个学生对象 student类的全部的方法和变量
c1 = classes("年级")
c1.add_student(s1) # 获取的结果列表中包含着对象s1,需要进行 点操作出来
c1.add_students([s1,s2])
#A类的对象,传入B类中,在B类中,可以使用A类的方法
class A(object):
# 学生
def __init__(self,name,aeg,class_object):
self.name = name
self.age = aeg
self.class_object = class_object
def message(self):
data = "{},{},{}".format(self.name,self.age,self.class_object)
print(data)
class B(object):
#班级
def __init__(self,title):
self.title = title
b =B("python全站")
b2 = B("linux云计算")
a = A("wkx","18",b.title)
a2 = A("wyx","16",b2.title)
a.message()
a2.message()
# user_list = [
# A("wkx","18",b),
# A("wyx","16",b2)
# ]
# for i in user_list:
# print(i.name,i.age,i.class_object.title)
# 类B内存中存了一个实例化变量,可以取出来 b.title b2.title
# 取出 B 类封装的值
class A(object):
# 学生
def __init__(self,name,aeg,class_object):
self.name = name
self.age = aeg
self.class_object = class_object
def message(self):
data = "{},{},{}".format(self.name,self.age,self.class_object)
print(data)
class B(object):
#班级
def __init__(self,title,C_object):
self.title = title
self.C_object = C_object
class C(object):
#校区
def __init__(self,name):
self.name = name
s1 = C("上海")
s2 = C("北京")
c1 = B("全站",s1)
c2 = B('云计算',s2)
user_list = [
A("123","18",c1),
A("123","18",c2)
]
for i in user_list:
print(i.name,i.age,i.class_object.title,i.class_object.C_object.name)
# 类的嵌套:就是将实例化的对象传入其他类中,其他类的参数接受这个对象,这个参数也具有对象的方法和值(一层一层的找)
#主要将每一个对象传出另一个类中当参数,这个对象内部有自己的变量和方法,需要时将他取出来
# 当嵌套过多时,一层一层的将赋值的变量名找到,并取出,因为每一个对象中都封装的一些数据和方法。
# i.class_object.C_object.name 在A类中取变量,在B类中取到对应的变量,在从C中取到对应的值
10.mro与c3算法确定类的基础关系
子类没有去找父类
利用方法知道父类关系
mro():作用于找到父类关系
类.mro() 返回一个列表 类关系
类.__mro__ 返回一个元组 类关系
底层原理 : c3 算法
规则:
mro(A) = [A]+(b,c)
mro(A) = [A,B,C]
使用方式:
mro(A) = [A]+merge(mro(B,object),mro(C,object,D,object,E,object),[B,C,D,E])
重点
1.从merge(第一个mro(元素1))对比merge(第二个mro(元素2)) 是否存
2.不存在剔除掉
3.在从merge(第一个mro(元素1))对比merge(第二个mro(元素2)) 是否存在
4.存在,保留,从merge(第二个mro(元素1)) 取其他的作为比较,不存在剔除。再从第一个mro第一个元素进行匹配
继承关系:
继承关系:从左到右,深度优先。大小钻石,留住顶端。
钻石继承:
-------D------
B--------------C
-------A-------
A-B-C-D
11.元类
# 知识点:exec
# 参数1 字符串形式的命令
# 参数2 全局作用域(字典形式) ,如果不指定就是global
# 参数3 局部作用域(字典形式),如果不使用就是locars
g = { # 定义的全局作用域的字典
'x': 10,
'y': 20
}
l = {} # 定义的局部作用域字典
# global 相当于声明了全局的变量
# x存在于g这个字典中
# m 不存在,那么就是新声明的
# z 没有声明全局,那么就是局部
exec('''
global x,mxxxx
x=100
mxxxx = 1000
z=30
''', g, l)
# print(globals()) # 输出就是 当前的全局的变量 x被修改为100,mxxx存在于全局中定义
# print(locals()) # 'l': {'z': 30}}
****** python 中一切皆对象 *****
1.都可以被引用 x = obj
2.都可以当成函数的参数传入
3.都可以作为函数返回值
4.都可以当做容器的元素 [obj.....]
# 类的类被成为元类
默认用class定义的类,他们的原类都是type
class A:
pass
a = A()
print(type(a)) # <class '__main__.A'>
print(type(A)) # <class 'type'>
# 创建的类的方式
1.class定义
2.type定义
定义类的三要素
1.类名
2.类继承的父类
3.类的名称空间
class_name = 'A' # 类的名称
class_bases = (object,) # 类的父类
calss_boby = ''' # 声明使用type声明类的中的方法
def __init__(self,name):
self.name = name
def func(self):
pass
'''
class_dic = {}
exec(calss_boby, globals(), class_dic) # 将class_boby 声明为字典形式的局部变量
# {'__init__': <function __init__ at 0x000001E7F4B3C550>, 'func': <function func at 0x000001E7F4DAE430>}
A = type(class_name, class_bases, class_dic)
# 参数1 类名, 参数2 类的父类 参数3 类内部的方法和属性
print(class_dic) # <class '__main__.A'>
print(A.__dict__)
****** 自定义元类 控制类的创建 *******
class Mymeta(type): # 默认还是要继承type元类,因为内部需要我们自己用的方法
# 为什么要传入3个参数 因为在type() 创建类时
# 需要传入 类名, 类的父类 类的属性和方法
def __init__(self, class_name, class_bases, class_dic):
print(class_dic)
print(class_name)
print(class_bases)
if not class_name.istitle(): # 首字母大写,不大写抛异常
raise TypeError('类名首字母大写') # raise TypeError('类名首字母大写') 主动抛出异常
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,并且不能为空') # TypeError('必须有注释,并且不能为空')
# 因为继承了原类type,当创建init是会覆盖所有要是用父列的
# 继承原类的 __init__
super().__init__(class_name, class_bases, class_dic)
# 自定义元类方法,控制类的行为
# 默认继承的原类就是metaclass = type
class Chinese(object,metaclass=Mymeta): # 将类的原类设置为自定义的原类
'''000''' # 设置类的注释 会赋值给__doc__
country = 'China'
def __init__(self):
pass
def func(self):
pass
'''
print(class_dic)
print(class_name)
print(class_bases)
打印的内容
{'__module__': '__main__',
'__qualname__': 'A', '__init__': <function A.__init__ at 0x000001B480CFE3A0>,
'func': <function A.func at 0x000001B480D17040>} # 类的方法
A 类名
(object) # 继承的父类类
'''
****** 定于元类 控制类的实例化 ******
补充
# __call__ 方法
# 当对实例化对象加()是就会调用__call__
class F: # f的元类默认是type
# 类中的方法如果存在call,那么对象就变为可别调用的 可以加()的
def __call__(self, *args, **kwargs):
print(self) # <__main__.F object at 0x0000020586886580>
print(args) # (1,)
print(kwargs) # {'a': 12}
f = F() # F() 可调用 说明type内部存在 __call__ 方法 会在调用类是触发执行
# 相当于 F.__call__(F,1,a=12)
f(1,a=12) #当对象加括号就会触发 obj.__call(对象本身,1,a=12) 可调用
自定义原类,并且初始化过程模拟
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
print(class_name)
if not class_name.istitle():
raise TypeError('类名首字母大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,并且不能为空')
super().__init__(class_name, class_bases, class_dic)
def __call__(self, *args, **kwargs): # obj =Chinese('wkx', 18)
# print(self) # self = Chinese
# print(args) # ('wkx', 18)
# print(kwargs) # {}
初始化过程
# 1.造空对象
# 创建类时默认会继承object类 内部存在一个new方法 new(obj) 传入的参数就是 一个对象本身自己
obj = object.__new__(self) # 初始化一个空的类对象
# print(obj) # <__main__.Chinese object at 0x0000026693B1AFA0>
# 2.初始化obj对象
self.__init__(obj, *args, **kwargs) # 初始化当前类的本身的__init__方法,将对象本身传入和参数
# 3.返回obj
return obj # 创建的对象返回
class Chinese(object, metaclass=Mymeta):
'''000'''
country = 'China'
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
pass
# chines.__call__(chines,wkx,18)
# 因为 chines 继承了定制的元类,在进行调用类()是就会执行内部的call方法
# 因为自定义的元类中重写了 call方法,那么就会优先使用自定义元类的call方法,而不是默认元类的type中的call方法
obj = Chinese('wkx', 18)
'''
实例化过程
1.创建空对象
2.初始化obj
3.返回obj
而元类的过程也是一模一样的
'''
print(obj.__dict__) # {'name': 'wkx', 'age': 18}
******* 使用创建的元类进行实例化应用 *******
# 定义单利模式 实例化n次还是一个对象
class M:
__instance = None
def __init__(self):
pass
@classmethod
def singleton(cls):
if not cls.__instance:
obj = cls()
cls.__instance = obj
return cls.__instance
a = M.singleton()
b = M.singleton()
print(a is b) # True 说明使用的是同一个对象
# 元类
# 使用元类 进行单利模式
class Mymeta(type):
def __init__(self, class_name, class_bases, class_dic):
print(class_name)
if not class_name.istitle():
raise TypeError('类名首字母大写')
if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
raise TypeError('必须有注释,并且不能为空')
super().__init__(class_name, class_bases, class_dic)
self.__instance = None # 创建一个变量
def __call__(self, *args, **kwargs): # obj =Chinese('wkx', 18)
if not self.__instance: # 判断是否存在这个对象
obj = object.__new__(self) # 没有创建这个对象
self.__init__(obj, *args, **kwargs) # 进行初始化
self.__instance = obj # 赋值
return self.__instance # 返回对象,每一次进行实例化,就会使用同一个对象
class M(object, metaclass=Mymeta):
'''1'''
def __init__(self):
pass
m = M()
m1 = M()
print(m is m1) # True
print(type(M)) # 他的元类就是 <class '__main__.Mymeta'> 自定义元类
Python异常处理与反射
1.异常处理
1.处理原理:
1.基本格式
try:
正常逻辑代码
except Exception as e: #捕获全部的异常
e 是一个对象 内部存放的错误信息 可以通过str进行转换
# 先执行 try内的代码,当出现异常是不会报错,会被excepr捕获,赋值给对象e
2.高级格式
try:
正常逻辑代码
except Exception as e: #捕获全部的异常
try内的代码异常触发,此处代码。
finally:
try中的代码是否报错,finally的代码都会执行。被成为释放资源
# 先执行 try内的代码,当出现异常是不会报错,会被excepr捕获,赋值给对象e 执行finally的代码
2.异常处理的细分
try:
正常逻辑代码
except 其他异常 as e:
代码
except 其他异常 as e:
代码
except 其他异常 as e:
代码
except Exception as e: 捕获全部的异常
try内的代码异常触发,此处代码。
3.自定义异常类
class 自定义异常类名(继承Exception类):
pass 代码
try:
正确的逻辑代码
# 主动触发异常
raise 自定义议程类名() # 触发异常类 固定格式,只有raise 才能触发自己常见的异常类
except 类名 as e:
当出现异常就会创建一个异常类的对象 赋值给 e ,e自定义异常类的对象
可以将e获取错误
finally
在函数内定义finally无论遇到return 都会返回finally内的代码
案例:
# 自定义异常
class MyException(BaseException): # 继承父类异常类
def __init__(self,msg):
super().__init__() # 继承父类的初始化方法
self.msg = msg
def __str__(self): # 类被调用时执行
return self.msg
raise MyException('抛出自己的错误') # 当抛出错误,就会执行
补充
raise参数的作用:显示与引发异常的作用
当程序出现错误时,python自动触发异常,也可以使用raise进行触发异常
一旦raise触发异常后,python后面的代码就不在执行
如果加入了try,except,那么except里面的语句会被执行
try是捕获异常,当raise触发异常时,就会触发except的异常报错
例如:
try:
s = None
if s is None:
print('s是空对象')
raise NameError # 报错
print(len(s))
except Exception: # 捕获异常
print('空对象没有长度') # 触发异常
2.反射
反射:支持以字符串的行式取操作成员 执行getattr
反射的使用方式:
class A :
def __init__(self,a):
self.a = a
def show(self):
pass
a1 = A()
#获取成员内的值
v1 = getattr(a1,“a”) 等价与 a1.a
#如果a变量存在 v1就是a的值,如果不存在就是none
v1 = getattr(a1,“show”,none)() 等价与 a1.show()
# 当利用反射进行判断执行类中的方法,需要添加第三个参数 none ,当方法不存在返回none
# 反射的其他操作
1.添加成员变量
setattr(a1,“b”,“值”) # 等价与 a1.b=“值”
2.判断成员是否存在
v1 = hasattr(a1,“a”)
print(v1) #返回结果 True/False
3.删除成员
delattr(a1,“a”) # 等价与 del a1.a
# 反射的组合操作
# import_module +反射 配合是用可以增加项目代码的扩展性
1.导入模块
from importlib import import_module
2.使用模块名
对象 = import_module("模块名称") #只能导入模块这个级别
# 正常使用方式 m.名称的方法 通过这种方式调用
3.使用方法
getattr(对象,模块的方法)