十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
属性 | 含义 |
---|---|
_name_ | 类,函数,方法等的名字 |
_module_ | 类定义所现在的模块名 |
_class_ | 对象或类所属的类 |
_bases_ | 类的基类的元素,顺序为他们在基类列表中出现的顺序 |
_doc_ | 类/函数的文档字符传,如果没有定义则为None |
_mro_ | 类的mro,class.mro()返回 |
_dict_ | 类或实例的属性,可写的字典 |
_dir_ | 返回了类或者对象所有成员列表,dir()函数调用的是_dir_(),如果提供了_dir_(),则返回属性列表,否则尽可能从__dict__属性中收集信息 |
获取类和函数的名字
创新互联公司服务项目包括浔阳网站建设、浔阳网站制作、浔阳网页制作以及浔阳网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,浔阳网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到浔阳省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
def C():
pass
print (A.__name__,B.__name__,C.__name__,sep='\n')
类定义所在的模块名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B:
pass
print (A.__module__,B.__module__)
#!/usr/local/bin/python3.6
#coding:utf-8
import disp
print (disp.A.__module__,disp.B.__module__,sep='\n')
对象或类所属的类
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
a=A()
b=B()
print (A.__class__,B.__class__,sep='\n') #类所属的类是class
print (a.__class__,b.__class__,sep='\n') # 对象所属的类是实实在在的类
类的基类的元组,顺序是他们在基类列表中出现的顺序
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
class C(B):
pass
class E:
pass
class D(E,C):
pass
print (A.__bases__,B.__bases__,C.__bases__,D.__bases__,sep='\n')
结果如下
文档字符串,针对类和函数有效,若不存在,则返回为None
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
'''this is class'''
pass
def B():
'''this is function'''
pass
class C:
pass
print (A.__doc__,B.__doc__,C.__doc__,sep='\n')
结果如下
类的mro。返回多继承中的查找顺序
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
pass
class B(A):
pass
class C(B):
pass
class E:
pass
class D(E,C):
pass
print (A.__mro__,B.__mro__,C.__mro__,D.__mro__,sep='\n')
结果如下
类或者实例的属性,可写的字典
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a=10
def __init__(self,x):
self.x=5
a=A(3)
print (A.__dict__)
print (a.__dict__)
结果如下
dir 返回了类或者对象所有成员名称列表,dir()函数调用的是_dir_(),如果提供了_dir_() ,则返回属性的列表,否则会尽量从__dict__属性中收集
dir() 对于不同类型的对象具有不同的行为:
1 如果对象是模块对象,则列表包含模块的属性名
#!/usr/local/bin/python3.6
#coding:utf-8
import re
def foo(x):
y=1
print (dir()) # 输出当前模块信息,此处会打印当前导入的模块和导入的函数
print (dir(re))
print ('+'*20)
print (dir(foo))
结果如下
2 如果对象是类型或者类对象,列表包含类的属性名,以及其他基类的属性名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
pass
class B(A): # 此处调用父类,其dir中会包含父类的属性
pass
print (dir()) # 输出当前模块信息,此处会打印当前导入的模块和导入的函数
print ('*'*40)
print (dir(A),dir(B),sep='\n') # 此中DIR属性父类和子类是完全相同的,但dict中却是不同的
print (A.__dict__,B.__dict__,sep='\n')
3 如果是对象,列表包含对象的属性名,它的类的属性名和基类的属性名
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
self.x=10
class B(A): # 此处调用父类,其dir中会包含父类的属性
pass
a=A()
print (dir()) # 输出当前模块信息,此处会打印当前导入的模块和导入的函数
print ('*'*40)
print (dir(A),dir(B),dir(a),sep='\n') #此处若是打印实例的属性,则会吧类的属性也打印上来
结果如下
4此处对属性名进行了重写操作
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
a='1234'
def __init__(self):
self.x=10
class B(A): # 此处调用父类,其dir中会包含父类的属性
def __dir__(self): # 此处是针对实例设置的,和类本身并无关系
return ['this is class A '] # 此处是dir返回是列表,若使用字符串,则会处理成列表进行返回
a=A()
b=B()
print (dir()) # 输出当前模块信息,此处会打印当前导入的模块和导入的函数,以及实例后的对象
print ('*'*40)
print (dir(A),dir(B),dir(a),dir(b),sep='\n') #此处若是打印实例的属性,则会吧类的属性也打印上来
结果如下
都是字典惹的祸
字典为了提升查询效率,必须用空间换时间
一般来说一个对象,属性多一点,都存储在字典中便于查询,问题不大,但是数百万个对象,那么字典就占得有点大了,这个时候,python便提供了_slots_
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = ('p1',) # 此处只放置了一个槽位,则只能使用p1变量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print (A().__dict__)
结果如下
此处的p2属性不能使用
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = ('p1','p2') # 此处只放置了一个槽位,则只能使用p1变量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print ('slots',A().__slots__) #实例的此属性可以被打印出来,但实例的字典属性却不存在
print (A.__dict__) # 类的字典属性不受影响
print ('dict',A().__dict__)
结果如下
添加实例属性如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = 'p1','p2' # 此处只放置了一个槽位,则只能使用p1变量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
print ('slots',A().__slots__) #实例的此属性可以被打印出来,但实例的字典属性却不存在
print (A.__dict__) # 类的字典属性不受影响
A.p4=300 #类添加属性,只会影响类的__dict__,实例中不会显示,而__slots__ 不会对类造成影响
try:
setattr(A(),'p5',30)
except AttributeError as a:
print (A(),'不能添加属性')
finally:
print (A().__slots__) #查看
try:
A().P3=300
except AttributeError as a:
print (A(),'不能添加属性')
finally:
print (A().__slots__) #查看
结果如下
_slots_ 告诉解释器,实例的属性都叫什么,一般来说,既要节约内存,最好还是使用元祖来存储__slots__梳理,这样就阻止了实例产生__dict__来保存实例的属性
继承
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class A:
x=123
__slots__ = 'p1','p2' # 此处只放置了一个槽位,则只能使用p1变量,不能使用其他
def __init__(self):
self.p1=1
self.p2=2
def show(self):
print ('this is test1,{}'.format(self.p1))
class B(A):
def __init__(self):
super().__init__()
self.b1=200
b=B()
b.b2=300
print (b.__dict__) # 继承则失效
结果如下
使用需要构建在数百万以上对象,且内存容量较为紧张的场景
描述 | 方法 |
---|---|
初始化和销毁 | _init__和_del\ |
在字典和set中使用 | _hash_ |
布尔类型,常用于判断语句 | _bool_ |
可视化,用于输出对应的类型 | _str__和_repr\ |
运算符重载 | _eq_,_ne_,_gt_,__lt__等 |
容器和大小相关和操作相关属性 | _getitem_,__setitem__等 |
可调用对象,将实例化的对象当成一个函数去调用,一旦可以当函数调用 | _call_ |
上下文管理(with open(x) as f 等形式 | _enter_,_exit_ |
反射 | _getattr_, _setattr_,_delattr_ |
描述器 | Object._get_(self,instance,owner)Object._set_(self,instance,value)Object._delete_(self,instance) |
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self,name):
self.name=name
self.x=10
print ("init instance")
def __del__(self):
print ('delete {}'.format(self.name))
a=X('a')
del a # 因为python自身的垃圾回收机制,而del删除实例的操作不确定何时执行,因此需要使用del进行清除处理
结果如下
hash 中最基础的hash就是取模运算。
list 不能hash的原因
list 源码: 其中hash=None,在调用None的时候自然是不能hash的
判断是否可hash
#!/usr/local/bin/python3.6
#coding:utf-8
from collections import Hashable
class X:
def __init__(self,x):
self.x=x
def __hash__(self):
return 1
print (isinstance(X(1),Hashable))
print (isinstance([],Hashable))
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
from collections import Hashable
class X:
def __init__(self):
self.x=10
__hash__=None
print (isinstance(X(),Hashable)) #判断是否可hash,返回为bool类型
print (hash(X()))
结果如下
实例如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self): # 此处是定义的是实例的hash,和类没关系
return None # 此处设置hash的返回为None,模拟列表
# 另一种方式定义不可哈希类型 __hash__=None
class Y: #此类未设置相关的hash属性
def __init__(self):
pass
class Z: # 此类定义了hash的返回值为1 ,则实例化后调用hash返回为1
def __hash__(self):
return 1
print (hash(Y())) # 此处返回整数
print (hash(Z())) # 此处返回为固定数
print (hash(X())) #进行判断是否能够进行hash操作,未进行hash,直接抛出异常
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
lst=[X(),X()] # 此处进行实例化并装载到列表中
print (lst) # 此处打印列表的值,指定的是内存地址
s=set(lst) # 此处定义一个集合,集合本身具有去重功能,上述的hash的返回值是相同的,则说明其hash相同,则表明其key相同,常理推论可得
# 其会走set的去重属性进行处理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
结果如下
此处s集合中的元素hash后的结果是相同的,但是其却没有进行去重操作,则此处表明hash相等的函数不一定就是相同的,此处没有直接的相等关系
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此处是判断是否相等的原因,及就是其值必须相等的情况下才能说是同一个,而不是hash相同就认为是同一个,此处返回bool值,当然可以是0或非0的数
return True
lst=[X(),X()] # 此处进行实例化并装载到列表中
print (lst) # 此处打印列表的值,指定的是内存地址
s=set(lst) # 此处定义一个集合,集合本身具有去重功能,
# 其会走set的去重属性进行处理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此处是判断是否相等的原因,及就是其值必须相等的情况下才能说是同一个,而不是hash相同就认为是同一个
return False
lst=[X(),X()] # 此处进行实例化并装载到列表中
print (lst) # 此处打印列表的值,指定的是内存地址
s=set(lst) # 此处定义一个集合,集合本身具有去重功能,上述的hash的返回值是相同的,则说明其hash相同,则表明其key相同,常理推论可得
# 其会走set的去重属性进行处理
print (len(s))
for i in s: # 打印其中的值,如下
print (hash(i))
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self):
self.x=10
def __hash__(self):
return 1
def __eq__(self, other): # 此处是判断是否相等的原因,及就是其值必须相等的情况下才能说是同一个,而不是hash相同就认为是同一个
return False
a=X()
lst=[a,a]
print (lst)
s=set(lst)
print (len(s))
for x in s:
print (hash(x))
结果如下
set判断是否是同一个的步骤:
1 先进行内存地址的判断,及is判断,若内存地址相同,则肯定是同一个
2 若内存地址不同,再进行eq 判断,及就是==进行判断,若相同,则是同一个,若不同,则不是同一个,此处和hash没有任何关系
及就是: 同假为假,一真一假为真,同真为真
默认的能够使用hash的原因是由于在基类object中实现了hash方法,一般的,不同的内存地址的hash是不相同的,两个对象的hash相同,叫hash冲突
hash 相同不代表一样
#!/usr/local/bin/python3.6
#coding:utf-8
class X:
def __init__(self,x):
self.x=x
def __hash__(self):
return 1
def __eq__(self, other): # 此处是判断是否相等的原因,及就是其值必须相等的情况下才能说是同一个,而不是hash相同就认为是同一个
return self.x==other.x# 此处表示二元操作,前面调用方法self.x,后面的作为参数传递进去进行处理,other表示第二个对象对应的方法
print (hash(X(4)))
lst=[X(4),X(6)]
t=tuple(lst)
s=set(lst)
print (s)
for x in s:
print (hash(x))
结果如下
__hash__方法只是返回一个hash值作为set的key,但是去重,还需要__eq__来判断2个对象是否相等,
设计二维坐标类Point,比较2个坐标是否相等
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self,x,y):
self.x=x
self.y=y
def __hash__(self):
return hash((self.x,self.y)) # 此处返回是一个元组,是不可变数据类型,此处可直接进行hash
def __eq__(self, other):
return self.x==other.x and self.y == other.y
a1=Point(3,4)
a2=Point(3,4)
print ( a1 is a2 )
print (a1==a2)
结果如下
_bool_ 内建函数bool(), 或者对象放在逻辑表达式的位置,调用这个函数返回布尔值,没有定义_bool_,就找_len_ 返回长度,非0为真,如果__len__也没有定义,则所有的实例都返回是真。
#!/usr/local/bin/python3.6
#coding:utf-8
class Point: # 此类未定义len和bool,因此其返回值为恒真
def __init__(self):
self.x=3
self.y=4
# def __bool__(self):
# return False
print (bool(Point()))
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __bool__(self): # 此处定义了bool的返回值为False,则调用bool()返回结果应该为False
return False
print (bool(Point()))
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
# def __bool__(self): # 此处定义了bool的返回值为False,则调用bool()返回结果应该为False
# return False
def __len__(self): # 此处用于当bool不存在时的找寻位置,为0则表示为空,则为False
return 0
print (bool(Point()))
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __bool__(self): # 同时存在,则以bool为准
return False
def __len__(self):
return 1
print (bool(Point()))
结果如下
这也就是为啥空的字典和空集合以及空列表为False的原因了,因为其没有定义bool,因此其只能通过访问len来实现了 。
方法 | 意义 |
---|---|
_repr_ | 内建函数repr()对一个对象获取字符串表达式,如果一个类定义了_repr__但没有定义_str\,那么在请求该类的实例的"非正式"的字符串也将调用_repr_() |
_str_ | str() 函数,内建函数format,print()函数调用,需要返回对象的字符串表达式 |
_bytes_ | bytes 的时候,返回一个独享的bytes表达,及返回bytes对象 |
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此处的返回必须使用字符串进行包裹,否则会报错
print (Point())
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此处的返回必须使用字符串进行包裹,否则会报错
def __str__(self): # 若存在此属性,则上述的表达式将不会被调用
return 'abcdefg'
print (Point())
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此处的返回必须使用字符串进行包裹,否则会报错
def __str__(self): # 若存在此属性,则上述的表达式将不会被调用
return 'abcdefg'
print (Point())
p1=Point()
p2=Point()
lst=[p1,p2]
for x in lst:
print (x)
print (lst)
#!/usr/local/bin/python3.6
#coding:utf-8
class Point:
def __init__(self):
self.x=3
self.y=4
def __repr__(self):
return str([self.x,self.y]) #此处的返回必须使用字符串进行包裹,否则会报错
def __str__(self): # 若存在此属性,则上述的表达式将不会被调用
return 'abcdefg'
print (Point())
p1=Point()
p2=Point()
lst=(p1,p2)
for x in lst:
print (x)
print (lst)
print (*lst) #进行解包处理,此时是针对于对象上的,此时应该调用的是str
上述实例证明,当str和repr同时存在时,如果输出结果直接作用于对象上,则调用str方法,否则将调用repr方法
operator 模块提供以下的特殊方法,可以将类的实例使用下面操作符来进行操作
运算符 | 特殊方法 | 含义 |
---|---|---|
<,<=,==,>,>=,!= | _lt_,_le_,_eq_,_gt_,_ge_,_ne_ | 比较运算符 |
+,-,*,/,%,//,**,divmod | _add_,_sub_,_mul_,_truediv_,_mod_,_floordiv_,_pow_,_divmod_ | 算数运算符,移位,位运算也有对应的方法 |
+=,-=,*=,/=,%=,//=,**= | _iadd_,_isub_,_imul_,_itruediv_,_imod_,_ifloordiv_,_ipow_ |
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other):
return self.x < other.x
def __eq__(self, other):
return self.x == other.x
def __ne__(self, other):
return self.x != other.x
def __sub__(self, other):
return self.x - other.x
print (A(10)
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此处定义的是+= 返回的是self=self+other
self.x += other.x
print ('__iadd__')
return self # 此处返回的是一个实例,可通过调用其方法来实现此方法是否执行
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此处定义的是+= 返回的是self=self+other
# self.x += other.x
print ('__iadd__')
return A(self.x+other.x ) #此处方法相同
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __iadd__(self, other): # 此处定义的是+= 返回的是self=self+other
# self.x += other.x
print ('__iadd__')
return A(self.x+other.x ) #此处方法相同
def __isub__(self, other):
print ('__isub__')
self.x -= other.x
return self
a1=A(10)
a2=A(20)
print ('*'*30)
a1+=a2
print (a1.x,a2.x)
a1-=a2
print (a1.x,a2.x)
functools.total_ordering 的应用
默认的
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other): # 此处定义的是小于,现需要使用大于等于,则默认会报错
return self.x < other.x
print (A(1) >= A(2))
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
from functools import total_ordering
@total_ordering
class A:
def __init__(self,x):
self.x=x
def __lt__(self, other): # 此处定义的是小于,现需要使用大于等于,则默认会报错
return self.x < other.x
print (A(1) >= A(2))
print (A(1)==A(2))
print (A(1) != A(2))
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x:int):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other.x
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self.x+other.x
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (a+b)
print (b+a)
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x:int):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other.x
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self+other # 此处self调用了add,其相当于实例self.__add__(other)进行处理的
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (a+b)
print (b+a)
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
# this is test
class Add:
def __init__(self,x):
self.x=x
def __add__(self, other):
print ('add',self)
return self.x+other
def __iadd__(self, other):
print ('iadd',self)
return self.x+other.x
def __radd__(self, other):
print ('radd',self)
return self+other # 此处self调用了add,其相当于实例self.__add__(other)进行处理的
class B:
def __init__(self,x):
self.x=x
a=Add(3)
b=B(4)
print (1+a)
print (1+b)
结果如下
结论如下:
b+a 等价于 b.add(a),但是B类没有实现add方法,就去找a的__radd__方法
1+a 等价于1.add(a),而int 类型实现了__add__放方法,不过这个方法对于这种加法的返回值是NotImplemented,解释器发现了这个值,就会对第二个操作对象执行__radd__进行调用。
运算符重载的应用场景
往往是面向对象实现的类,需要做大量的运算,而运算符是这种运算在数学上最常见的表达方式,int 类中,几乎实现了所有操作符,可以作为参考
内建方法 | 含义 |
---|---|
_len_ | 内建函数len(),返回对象的长度(>=0的整数),其实即使吧对象当作容器类型来看,就如同list或dict,bool()函数调用的时候,如果没有_bool_()方法,则会看_len_()方法是否存在,存在返回非0为真,第三方库中可能存在size,其和len的含义相同 |
_iter_ | 迭代器时,调用,返回一个新的迭代器对象 |
_contains_ | in成员运算符,没有实现,就调用__iter__方法遍历 |
_getitem_ | 实现self[key]访问,序列对象,key接受整数为索引,或者切片,对于set和dict,key为hashable,key不存在时引KeyError异常 |
_setitem_ | 和__getitem__的访问相似,是设置值的方法 |
_missing_ | 字典使用_getitem_()调用时,key不存在执行该方法 |
#!/usr/local/bin/python3.6
#coding:utf-8
class Item:
def __init__(self,name,*args):
self.name=name
self.lst=list(args)
def __len__(self):
return len(self.lst)
def __iter__(self):
return iter(self.lst) # 此处返回是一个迭代器,必须是一个迭代器
def __add__(self, other): # 此处使用+ 号返回一个列表
self.lst.append(other)
return self
def __getitem__(self, index): # 此处应用于列表时,表示为索引,此处应用于字典时,表示key
if index > len(self.lst):
print ('Key Error')
else:
return self.lst[index]
def __setitem__(self, index, value): # 此处表示修改属性列表中的值
if index > len(self.lst):
print ('Key Error')
else:
self.lst[index]=value
return self
# def __missing__(self, key): # 此方法只能适用于字典的处理
# pass
def __repr__(self):
return str(self.lst) # 此处对其进行可视化处理
a=Item('MySQL',12,3,45,678,8909)
print (len(a))
# 此处调用了__iter__方法
for i in a:
print (i)
print ('++++++++++++++++')
print (a[2]) # 此处调用了__getitem__方法,用于获取值
a+10 # 此处使用__add__方法进行加入,此处追加到列表的末尾
print (a[-1]) # 获取列表的最后一个元素,则得到此值
a[1]=20 # 使用__setitem__方法修改属性
print (a[1]) #返回对应位置的值
a+10+20+30+40 # 此处进行连加操作,因为其add方法返回是self,因此每次赋值后都会增加
print (a)
结果如下
在python中一切皆对象,函数也不例外
可调用对象
方法
__call__类中出现该方法,实例就可以像函数一样调用,
可调用对象: 定义一个类,并实例化得到其实例,将实例像函数一样调用。调用是实例的,不是类的。
#!/usr/local/bin/python3.6
#coding:utf-8
def foo():
print (foo.__module__,foo.__name__)
foo.__call__()# 此处的方法和下面的相同,皆是调用该函数
foo()
print (dir(foo))
结果如下
函数的可调用原因是函数实现了\call()方法
#!/usr/local/bin/python3.6
#coding:utf-8
def foo():
print (foo.__module__,foo.__name__)
print (foo.__call__) # 此处返回一个函数对象是一个wrapper
foo.__call__()# 此处的方法和下面的相同,皆是调用该函数
foo()
结果如下
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self):
self.x=1
def __call__(self, *args): # 此处的第一个是self,表明其是给实例使用的,并不是给类使用的
return args # 此处返回一个元组
print (A()(12344)) # 此处第一个括号是实例化,第二个是传递参数并调用实例
利用封装完成斐波那契额数列
方法1
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __call__(self,num):
a,b=0,1
for i in range(num):
print (b)
a,b=b,a+b
A()(10)
结果如下
方法2
#!/usr/local/bin/python3.6
#coding:utf-8
class A:
def __init__(self):
self.lst=[1,1,2]
def __call__(self,num):
if num < 3:
return self.lst[:num]
else:
for i in range(num-3):
self.lst.append(self.lst[-1]+self.lst[-2])
return self.lst
print (A()(10))
结果如下
添加功能如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
self.lst=[1,1,2]
def __len__(self):
return len(self.lst)
def __call__(self,x):
if len(self.lst) > x:
return self.lst[:x]
for i in range(2,x):
self.lst.append(self.lst[i]+self.lst[i-1])
return self.lst
def __getitem__(self, item):
if item < 0:
return None
if len(self) > item:
return self.lst[item]
def __iter__(self):
return iter(self.lst)
a=A()
print (a(10))
print (a[4])
for x in a:
print (x)
结果如下
文件IO操作可以对文件对象进行上下文管理,使用with...as语法
推导过程
#!/usr/bin/poython3.6
#conding:utf-8
# 此处为默认的上下文管理
# with open('test') as f:
# pass
class A:
pass
with A() as f:
pass
结果如下
提示需要添加 __enter__属性
添加如下
#!/usr/bin/poython3.6
#conding:utf-8
# 此处为默认的上下文管理
# with open('test') as f:
# pass
class A:
def __enter__(self):
pass
with A() as f:
pass
结果如下
提示需要添加 __exit__属性
#!/usr/bin/poython3.6
#conding:utf-8
# 此处为默认的上下文管理
# with open('test') as f:
# pass
class A:
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with A() as f:
pass
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __enter__(self):
print ('__enter__')
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
with A() as f:
pass
由此图可知,其调用顺序是先调用_enter_,后调用_exit_
方法 | 意义 |
---|---|
_enter_ | 进入于此对象相关的上下文,如果存在该方法,with语法会把该方法的返回值作为绑定到as字句中指定的变量上 |
_exit_ | 退出与此对象的上下文 |
exit 中变量的含义:
1 exc_type: 异常类型,如果没有异常,则返回是None
2 exc_tb:异常追踪信息,如果没有异常,则是None
3 exc_va :异常对应的值,如果没异常,则是None
此处的return 用于压制异常,若此处是False,则会抛出异常,等效True 或 False缺少了enter 进不去,缺少了exitc出不来
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此处的p是__enter__的返回值,是f的参数,若此处__enter__无return,则默认返回为None,无意义
print (p==f) # 此处用于比较p和f的关系
print (p is f)
print (p)
print (f)
上述结论如下:
实例化对象的时候,并不会调用enter,进入with语句块会调用__enter__方法,然后执行语句体,最后离开with语句块的时候,调用__exit__方法with 可以开启一个上下文运行环境,在执行前做一些准备工作,执行后做一些收尾工作。
#!/usr/bin/poython3.6
#conding:utf-8
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此处的p是__enter__的返回值,是f的参数,若此处__enter__无return,则默认返回为None,无意义
raise Exception('Error') # 此处抛出异常,一般的,抛出异常后,语句将不会再次执行
print (p==f) # 此处用于比较p和f的关系
print (p is f)
print (p)
print (f)
结果如下
由此证明,当异常抛出时,exit对应的语句仍然会被执行。
#!/usr/bin/poython3.6
#conding:utf-8
import sys
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return 1
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
p=A()
with p as f: # 此处的p是__enter__的返回值,是f的参数,若此处__enter__无return,则默认返回为None,无意义
sys.exit() # 此处的是直接退出
print (p==f) # 此处用于比较p和f的关系
print (p is f)
print (p)
print (f)
结果如下
上述证明,此处满足上述清理工作,上下文管理非常安全,能够保证变量的顺利清除工作。
#!/usr/bin/poython3.6
#conding:utf-8
import sys
class A:
def __init__(self):
print ('init instance')
def __enter__(self):
print ('__enter__')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print ('__exit__')
print (exc_tb) #追踪信息
print (exc_type) # 类型
print (exc_val) # 值
return 1 # 此处设置为1 是压制异常,不让其出现
p=A()
with p as f: # 此处的p是__enter__的返回值,是f的参数,若此处__enter__无return,则默认返回为None,无意义
raise Exception('Error1234454')
print (p==f) # 此处用于比较p和f的关系
print (p is f)
print (p)
print (f)
结果如下
之前的计算时长方式
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
import sys
def wapper(fn):
def _wapper(*args,**kwargs):
start_time=datetime.datetime.now()
ret = fn(*args,**kwargs)
delta=(datetime.datetime.now()-start_time).total_seconds()
print ("{} 函数的执行时间为: {}".format(fn.__name__,delta))
return ret
return _wapper
@wapper
def add(x,y):
time.sleep(2)
return x+y
add(4,5)
结果如下
使用上下文管理的方式统计函数执行时间
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
class Timer:
def __init__(self,fn):
self.fn=fn
def __enter__(self):
self.start_time=datetime.datetime.now()
return self.fn # 此处对应的是as前面的值
def __exit__(self, exc_type, exc_val, exc_tb):
delat=(datetime.datetime.now()-self.start_time).total_seconds()
print ("函数{} 的执行时间为: {}".format(self.fn.__name__,delat))
return 1
def add(x,y):
return x+y
p=Timer(add)
with p as f: # 此处调用的是__enter__的返回值,重命名为f
time.sleep(2)
print (f(4,5))
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.fn=fn
def __call__(self,*args,**kwargs): #实例调用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函数的执行时间为: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
time.sleep(2)
return x+y
print (add(10,20))
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.fn=fn
def __call__(self,*args,**kwargs): #实例调用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函数的执行时间为: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此处打印出文档
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
self.__doc__=fn.__doc__ # 此处只能进行部分的属性覆盖操作
self.__name__=fn.__name__
self.fn=fn
def __call__(self,*args,**kwargs): #实例调用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函数的执行时间为: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此处打印出文档
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
import datetime
import time
from functools import wraps
class A:
def __init__(self,fn):
wraps(fn)(self) # 调用此方法完成属性的覆盖操作,此处第一个是原函数,后面是现在的函数
self.fn=fn
def __call__(self,*args,**kwargs): #实例调用支持的方法
self.start_time=datetime.datetime.now()
ret = self.fn(*args,**kwargs)
delta=(datetime.datetime.now()-self.start_time).total_seconds()
print ("{} 函数的执行时间为: {}".format(self.fn.__name__,delta))
return ret
@A #add=A(add)
def add(x,y):
'''this is function'''
time.sleep(2)
return x+y
print (add(10,20))
print (add.__doc__) # 此处打印出文档
结果如下
是一个装饰器实现上下文管理,装饰一个函数,而不像类一样可以实现__enter__和__exit__方法
对下面的函数有要求,必须有yield,也就是这个函数必须返回一个和生成器,且只有一个yield的值。
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield
print ('exit')
with foo() as f:
pass
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield [1,2,34,56,5867,856,867,] # 此处相当分界线,用于分割上面和下面的执行
print ('exit')
with foo() as f:
print (f)
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
yield [1,2,34,56,5867,856,867,] # 此处相当分界线,用于分割上面和下面的执行
print ('12344exit')
with foo() as f:
try:
raise Exception
finally:
print ('exit')
print (f)
结果如下
修改异常捕获如下
#!/usr/bin/poython3.6
#conding:utf-8
import contextlib
@contextlib.contextmanager
def foo():
print ('enter')
try:
yield [1,2,34,56,5867,856,867,] # 此处相当分界线,用于分割上面和下面的执行
finally: # 放置在此处能够执行后面的相关操作
print ('12344exit')
with foo() as f:
raise Exception
print (f)
结果如下
总结: 如果业务逻辑简单可以使用函数加装饰器的方式,如果业务复杂,用类的方式加__enter__和__exit__更方便
1 增强功能
在代码执行的前后增加代码,以增强其功能,类似装饰器的功能2 资源管理
打开了资源需要关闭,例如文件对象,网络链接,数据库链接等3 权限验证
在执行代码之前,做权限的验证,在enter中处理
在代码进入的时候进行处理,在权限出去则不管
运行时:区别于编译时,指的是程序被加载到内存中执行的时候。
反射:python中,能够通过一个对象,找出其type,class,attribute或method的能力,成为反射或自醒。
具有反射能力的函数type(),isinstance(),callable()(查看对象能否被调用),dir(),getattr()
object 可以是类或实例
语法格式:
getattr(object,name[,default]) : 通过name 返回object的属性值,当属性不存在时,将使用default返回,如果没有default,则抛出attributeError,name 必须位字符串
setattr(object,name,value) object 的属性存在,则覆盖,若不存在,则新增。
hasattr(object,name) 判断对象是否有这个名字属性,name必须时字符串
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=10
def __init__(self):
self.x=5
setattr(A,'y',20) # 动态添加类属性位y=20
print (A.__dict__) # 打印属性信息列表
a=A()
setattr(a,'z',100) # 实例动态增加属性
print (getattr(A,'y')) # 查看增加的属性是否存在
print (getattr(A,'x')) # 定义属性是否存在
print (getattr(a,'y')) # 查看实例中是否存在该属性
print (a.__dict__) # 查看实例属性信息中是否具有'z'属性
print (A.__dict__) # 打印属性信息列表,此处查看当实例属性信息增加后,类属性信息是否增加
if hasattr(a,'z'):
print ("{} 函数存在此属性 {}".format('a','y'))
结果如下
进阶
#!/usr/bin/poython3.6
#conding:utf-8
class A:
x=10
def __init__(self,y):
self.x=5
self.y=y
a=A(20)
setattr(A,'printf',lambda self: 1 ) #此处增加一个类的属性,并通过参数调用
setattr(a,'myclass',lambda : 10 ) # 此处增加一个实例属性
print (a.printf()) # 打印此类的属性结果如下
print (getattr(a,'printf')()) # 因为此处是函数,因此需要通过()来进行调用
print (getattr(a,'myclass')())
if not hasattr(A,'sub'): # 此处添加一个类的函数属性,实现函数之前的差运算
setattr(A,'sub',lambda self,other : A(self.y- other.y) )
if not hasattr(A,'add'): # 此处添加一个类的属性,实现函数之间的和的计算
setattr(A,'add',lambda self,other: (self.y + other.y))
print (a.__dict__)
print (A.__dict__)
b1=A(10)
b2=A(20)
print (b2.sub(b1))
print (b1.add(b2))
结果如下
注意:
这种动态增加属性的方式是运行时改变类或者实例的方式,比装饰器和Mixin更加灵活,其具有更大的使用用途
实现分发器
简单雏形
#!/usr/bin/poython3.6
#conding:utf-8
class Dispatcher:
def cmd1(self): # 此处在内部定义一个方法
print ('cmd10')
def run(self): # 此处用于执行
while True:
cmd=input("plase input str:") #退出程序命令
if cmd.strip() == 'q' or cmd.strip() == 'quit':
return
getattr(self,cmd.strip(),self.__defaltfun)() # 此处用于获取该方法,若不存在,则执行默认程序
def __defaltfun(self):
print ('default')
a=Dispatcher()
a.run()
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
class Dispatcher:
def cmd1(self): # 此处在内部定义一个方法
print ('cmd10')
def reg(self,cmd,fn):
if isinstance(cmd,str):
setattr(self.__class__,cmd.strip(),fn) # 此处使用的是类,若是实例化,则需要进行下面将self传入进去的方式进行调用
else:
print ('TypeError')
def run(self):
while True:
cmd = input("plase input str:")
if cmd.strip() == 'q' or cmd.strip() == 'quit':
return
getattr(self,cmd.strip(),self.defaultfun)()
def defaultfun(self):
print ('default')
a=Dispatcher()
a.reg('cmd2',lambda self :print (2))
a.reg('cmd3',lambda self :print (3))
a.run()
结果如下
魔术方法 | 意义 |
---|---|
_getattr_() | 当通过搜索实例,实例的类以及祖先类查不到的属性,就会调用此方法 |
_setattr_() | 通过访问实例属性,进行增加,修改都要调用它 |
_delattr_() | 当通过实例删除属性的时候调用此方法 |
_getattribute_ | 实例所有的属性调用都是从政方法开始 |
实例如下:
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此处定义了属性,所以下面的__setattr__被执行了一次,初始化先执行,之后__setattr__这个属性再执行一次
def __getattr__(self, item):#针对上述无法查找到的属性,则执行此属性,可配置其值为None来弥补此属性值
print ('__getattr__',item)
self.__dict__[item]=None
def __setattr__(self, key, value): #设置一个属性时,一定要执行,至于是否生效,则另当别论
print ('__setattr__',key,value)
def __delattr__(self, item): #此处在删除一个实例的属性进行的操作,只要实例能找到,都能够删除
print ('__delattr__',item)
A.n=50 # 此处是正常的添加类属性,不会产生其他的报错
a=A(20)
print (a.__dict__)
a.b # 针对不存在的属性进行调用
a.x=30 # 设置实例的属性变化
a.c=200 #添加一个不存在的属性
del a.a # 删除一个实例的属性
print (a.__dict__)
结果如下
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此处定义了属性,所以下面的__setattr__被执行了一次,初始化先执行,之后__setattr__这个属性再执行一次
def __getattr__(self, item):#针对上述无法查找到的属性,则执行此属性,可配置其值为None来弥补此属性值
print ('__getattr__',item)
self.__dict__[item]=None
def __setattr__(self, key, value): #设置一个属性时,一定要执行,至于是否生效,则另当别论
print ('__setattr__',key,value)
def __delattr__(self, item): #此处在删除一个实例的属性进行的操作,只要实例能找到,都能够删除
print ('__delattr__',item)
def __getattribute__(self, item): #此处是在字典属性之前进行拦截执行
print ('__getattribute__',item)
a=A(20)
print (a.x)
结果如下
实例的所有属性的访问,第一个都会调用__getattribute__方法,其阻止了属性查找,该方法应该返回(计算后)值或者抛出一个attributeError 异常
他的return 值将作为属性查找的结果,如果抛出attributeError 异常,则会直接调用__getattr__方法,因为表示属性没有找到
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此处定义了属性,所以下面的__setattr__被执行了一次,初始化先执行,之后__setattr__这个属性再执行一次
def __getattr__(self, item):#针对上述无法查找到的属性,则执行此属性,可配置其值为None来弥补此属性值
print ('__getattr__',item)
# self.__dict__[item]=None
def __setattr__(self, key, value): #设置一个属性时,一定要执行,至于是否生效,则另当别论
print ('__setattr__',key,value)
def __delattr__(self, item): #此处在删除一个实例的属性进行的操作,只要实例能找到,都能够删除
print ('__delattr__',item)
def __getattribute__(self, item): #此处是在字典属性之前进行拦截执行
print ('__getattribute__',item)
raise AttributeError(item) # 此处若属性不存在,抛出异常,则直接进入getattr中机型处理
a=A(20)
print (a.x)
#!/usr/bin/poython3.6
#conding:utf-8
class Base:
a=5
class A(Base):
m=6
def __init__(self,x):
print ('init')
self.x=x #此处定义了属性,所以下面的__setattr__被执行了一次,初始化先执行,之后__setattr__这个属性再执行一次
def __getattr__(self, item):#针对上述无法查找到的属性,则执行此属性,可配置其值为None来弥补此属性值
print ('__getattr__',item)
# self.__dict__[item]=None
def __setattr__(self, key, value): #设置一个属性时,一定要执行,至于是否生效,则另当别论
print ('__setattr__',key,value)
def __delattr__(self, item): #此处在删除一个实例的属性进行的操作,只要实例能找到,都能够删除
print ('__delattr__',item)
def __getattribute__(self, item): #此处是在字典属性之前进行拦截执行
print ('__getattribute__',item)
# raise AttributeError(item) # 此处若属性不存在,抛出异常,则直接进入getattr中机型处理
return object.__getattribute__(self,item) #此处表示若不存在,则直接去object中进行查找,并得到其访问的值
a=A(20)
print (a.b)
结果如下
注意:\getattribute\ 方法中为了避免在该方法中无限递归,实现了应该永久调用基类的同名方法以访问需要的任何属性,除非你明确知道\getattribute\方法用来做什么,否则不要使用它。
文章名称:python类之特殊属性和魔术方法
本文链接:http://6mz.cn/article/pojcih.html