迭代器相对于生成器来说,需要自己手动实现__iter__和__next__方法
类的三个特征:封装 继承 多态
多态主要用于接口的重用
经典类和新式类:
在Python 2.x及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,不由任意内置类型派生出的类,则称之为“经典类”
“新式类”和“经典类”的区分在Python 3.x之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”
区别:继承了python的内置类的时候,才是新式类,其他的都是经典类
1.经典类 通过type查看到的实例类型都叫做instance 类和实例之间能够通过__class__属性进行关联
新式类 通过type查看到的实例类型就是类名
class A:pass
a=A()
type(a):
python2 中是经典类 我们通过type查看到的类名都是instance 只能通过__class__查看自己所属的类名
python3 中是新式类 我们通过type查看到的是类名A 也有__class__方法
2.多重继承顺序的区别
经典类:深度优先
新式类:c3算法
多重继承(那个圆陀陀的截图)
类可以多重继承
? 定义类A
? 定义类B,C继承自A
? 定义类D,继承自D
? 定义类E,继承自E
? 定义类F,继承自F
深度优先(从左至右)(经典类):如果有两三条类,先一条路走到底 截图
C3算法(从左至右)(不算广度优先)(新式类) 截图
#看截图定义
class a:
def test(self):
print("from a")
class b(a):
def test(self):
print("from b")
class c(a):
def test(self):
print("from c")
class d(b):
def test(self):
print("from d")
class e(c):
def test(self):
print("from e")
class f(d,e):#先继承的d 再继承的e
def test(self):
print("from f")
f1=f()
f1.test()
查找顺序:经典类:FDBAEC 新式类:FDBECA
经典类与新式类的继承继承原理
? MRO:方法解析顺序
? 对于你定义的每一个类,Python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表
现在新式类就是c3算法 经典类就是深度优先
c3算法:
首先将自身类加入到本序列,然后对继承序列的元素从左至右依次判断
若某元素不在其他序列或者它是所有继承序列的第一个,那么就把这个元素提取到本序列,不符合条件的就丢掉,然后下一个
静态方法和类方法:
属性:对象的描述信息
? 静态属性(所有的实例共用一份=>引用)--类属性
? 普通属性(每个实例都不同的数据=>引用)--实例属性
方法:对象的行为信息
实例(普通)方法:接受的第一个参数,就代表实例本身
静态方法:使用staticmethod修饰的方法,称为静态方法 可以接收参数也可以不接收参数 参数不代表实例也不代表类
类方法:使用@classmethod修饰的方法 叫做类方法 接收的第一个参数是类
class a():
name="a" #静态属性
def __init__(self):
self.country='china' #普通属性
#普通(实例)方法:接受的第一个参数,就代表实例本身
def method(self,name):
print("normal")
print(self.name,name)
#使用classmethod修饰的方法 叫做类方法 接收的第一个参数是类
@classmethod
def class_method(cls,name):
print("clssnormal")
print(cls.name, name)
#使用staticmethod修饰的方法,称为静态方法 可以接收参数也可以不接收参数 参数不代表实例也不代表类
@staticmethod
def static_method(name):
print("staticnormal")
print(a.name, name)#静态方法只能传值 不能通过cls或者self去调用
#通过实例调用类方法,静态方法,实例方法 都可以
a1=a()
a1.method("normal")
a1.class_method("classmethod")
a1.static_method("staticmethod")
##通过类调用类方法,静态方法,实例方法 都可以
a.method(a1,"normal")#通过类去调用实例方法的时候 一定要传一个实例作为参数
a.class_method("classmethod")
a.static_method("staticmethod")
python中的下划线:
以单下划线开头的(_foo)
? 类:这类成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量
? 模块:如果你写了代码“from <模块/包名> import *”,那么以“_”开头的模块和包都不会被导入,除非模块或包中的“__all__”列表显式地包含了模块和包。
惯例:道以“_”开头的名称只供内部使用
以双下划线开头的(__foo)
? 类:只有类对象自己能访问,连子类对象也不能访问到这个数据。强行访问“对象名._类名__xxx“这样的方式
? 模块:不能用“from xxx import *“导入包/模块。
? 双下划线(“__“)开头对解释器来说它有特定的意义。Python中的这种用法是为了避免与子类定义的名称冲突
以双下划线开头和结尾的( __foo__ )(python内置的变量)(不建议用户使用)
? 代表Python中特殊方法专用的标识。其实,这只是一种惯例,对Python系统来说,这将确保不会与用户自定义的名称冲突
class parent:
tmp="tmp"
_min=1
__max=10
def __init__(self):
self.name='sc'
self._age=4
self.__desc='it'
def __make(self):
print("这是一个私有方法")
print(self.__desc)
def _protectmake(self):
print("这是一个保护方法")
def show(self):
print(self.__max,self.__desc)
print("这是一个普通方法")
class child(parent):
def show(self):
print(self.__max)
#parent
# 类属性 tmp _min __max
# 实例属性 name _age __desc
# 方法 __make _protectmake show
p=parent()
c=child()
# 访问普通成员和保护成员(在类里面开头 但下划线开头和没下划线开头的区别不大)
print(p.tmp,c.tmp)
print(p._min,c._age,c._min)
# 保护私有成员 __max __desc __make 只能在类的内部去访问 (会自动的给你换名字)
# 查看实例空间有那些属性: 实例.__dict__
#python中的私有是一种伪私有,就是将双下划线开头的标识符给改了一个名字 变成 _类名__标识名
特殊含义:
__dir__:查看对象的属性和方法 如:p.__dir__=dir(p)
__doc__:自动识别读取文档注释
查看对象和类空间:__dict__ 如:类(实例).__dict__
查看对象属于哪个类:实例.__class__
查看类名:类.__name__
查看父类:子类.__bases__
查看对象的哈希值:对象.__hash__()
常用的魔术方法:
魔术方法:(面试常考)
在Python中,所有以双下划线__包起来的方法,统称为Magic Method(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。
魔术方法在类或对象的某些事件触发后会自动执行,让类具有神奇的“魔力”。如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。
Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的
? 构造函数(__new__/__init__)
? __new__:创建实例
? __init__:初始化实例
? 析构函数(__del__)
? 在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作, 如关闭一些数据库连接,关闭打开的临时文件
? 调用方法(__call__)
? 把类实例化后的对象当做函数来调用的时候自动被调用
class a:
def __del__(self):
print("执行del")
def __call__(self, *args, **kwargs):
print("11")
a1=a() # 如果只有这一行 会自动执行del 输出结果:执行del 表示关闭自动调用__del__ 若后面还有代码 则不会执行del
del a # 手动删除实例 也会执行__del__ 也可以删除实例a(del是关键字 会自动调用__del__ __del__还是会进行删除,然后再加上那些新的功能)
a1("sc",4) #得到 11 (把对象当作函数来调用的时候会自动执行__call__)
__str__和__repr__:返回对象实例的描述信息 默认调用的是__repr__
__str__ 给用户看的
__repr__ 更加官方的说明,给程序员看的
class a:
def __str__(self):
return "str"
def __repr__(self):
return "repr"
a1=a()
print(a)返回的是__str__
如果没有str 默认返回rper
交互式环境才能看到rper(不要打print)
raise 抛出异常
其他常用的魔术方法:
让对象以字典的形式去设置或者获取参数(常常用在设置或者配置属性的时候)
__gititem__
__setitem__
__delitem__
class a:
def __init__(self):
self.data={}
def __getitem__(self, key):
print("get data:")
return self.data.get(key,0)#没有的话是返回默认值 不会把这个key加进去
def __setitem__(self, key, value):
print("set data:")
self.data[key]=value
def __delitem__(self, key):
print("delete data:")
del(self.data[key])
a1=a()
a1["key"]="value" #去设置值的时候 会调用__setitem__ 输出set data:
print(a1["key"])#获取值的时候 会调用__getitem__ 输出get data: 最后输出value
a1["k1"]="v1"
a1["k2"]='v2'
print(a1.data)#这里面就是我们设置了内容的字典了
del a1["key"]#删除时 会调用__delitem__ 输出delete data:
print(a1.data)#输出{'k1': 'v1', 'k2': 'v2'}
其他魔术方法:(这些要是不自己定义,会继承object的)
? __eq__(self, other) 定义了等号的行为,==
? __ne__(self, other) 定义了不等号的行为, !=
? __lt__(self, other) 定义了小于号的行为, <
? __gt__(self, other) 定义了大于等于号的行为, >=
? __add__(self, other) +运算 (用对象相加直接调用__add__)
? __mul__(self, other) *运算
? __len__(self, other) 获得长度
class a:
def __init__(self,num):
self.num=num
def __add__(self, x):
print("add")
return self.num+x
def __gt__(self, other):
print("gt")
return self.num>other.num
a1=a(5)
b=a1+6 #调用__add__ 输出 add
print(b)#输出 11
a2=a(10)
print(a1>a2)#看到大于号就会自动调用__gt__,输出gt,最后输出False
# print(a1.num.__gt__(a2.num))#若没有自定义__gt__,会继承object的__gt__方法,形式可以是这样的,效果一样
python自省:(增加程序的健壮性)
什么是自省
? 在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力
自省有4个方法(成员==属性)
? getattr(obj,'name'): 获取成员
? 根据字符串去获取obj对象里的对应的方法的内存地址
? hasattr(obj,'name'): 检查是否含有成员
? 判断一个对象obj里是否有对应的name_str字符串的方法
? setattr(obj,'age', 18): 设置成员
? delattr(obj,'name'): 删除成员
import math
#python自省
print(hasattr(math,'xx'))#判断math有没有xx属性 False
print(setattr(math,'xx',1))#设置math的xx属性为1 None
print(getattr(math,'xx'))#获取math的xx属性 1
print(delattr(math,'xx'))#删除math的xx属性 None
class a:
name='sc'
__max='max'
def func1():
print('i am func1')
if hasattr(a,'name'):
print(getattr(a,'name'))
if hasattr(a,'func1'):
result=getattr(a,'func1')#这个时候result得到的就是方法了 可以直接调用方法
result()
#如果要设置的是一个函数的话 先在外部定义一个函数
def func2():
print('func2')
setattr(a,'func2',func2)
a.func2()
|