一、__call__

对象后面加括号,触发执行类下面的__call__方法。

创建对象时,对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

  class Foo:

def __call__(self, *args, **kwargs):
print("我执行啦")

f = Foo()
f() #对象加括号调用执行类下的__call__方法
#输出结果 我执行啦

  

二、__next____iter__实现迭代器协议

迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)

可迭代对象执行obj.__iter__()得到的结果就是迭代器对象。

在类中,如果有__iter____next__内置方法,那么就构成了迭代器。

例子

  
  class Foo:

def __init__(self,n):
self.n = n

def __iter__(self):
return self #实例本身就是迭代对象,故返回自己

def __next__(self):
if self.n >10:
raise StopIteration #如果超过10就报StopIteration 错误
self.n = self.n + 1
return self.n

f = Foo(7)
for i in f: #for循环自动调用__next__方法,实现了迭代取值
print(i)

  

例子2

输出100内的斐契那波数列

  
  class F:

def __init__(self):
self.a = 0
self.b = 1

def __iter__(self):
return self

def __next__(self):
self.a ,self.b = self.b , self.a + self.b
if self.a > 100:
raise StopIteration
return self.a

f = F()
for i in f:
print(i)

  

三、描述符(__get__,__set__,__delete__)

描述符(descriptor):

1、描述符本质

就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议。__get__():调用一个属性时,触发__set__():为一个属性赋值时,触发__delete__():采用del删除属性时,触发

2、描述符的作用

是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

描述符是在另外一个类的类属性进行定义的,描述符在一个类的类属性__dict__字典里

例子1

  class Foo:

def __get__(self, instance, owner):
print("执行了__get__")

def __set__(self, instance, value):
print("执行了__set__")

def __delete__(self, instance):
print("执行了__delete__")


class Bar:
x = Foo()

def __init__(self,name):
self.name = name


b = Bar("nick")
b.x #调用执行描述符里的__get__方法
print(b.x) #
b.x = 1 # 调用执行描述符里的__set__方法
print(b.__dict__)
del b.x #调用执行描述符里的__delete__方法
print(b.__dict__)

  

输出结果

  执行了__get__
执行了__get__
None
执行了__set__
{'name': 'nick'}
执行了__delete__
{'name': 'nick'}

  

例子2

  #描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...')

#描述符Int
class Int:
def __get__(self, instance, owner):
print('Int调用')
def __set__(self, instance, value):
print('Int设置...')
def __delete__(self, instance):
print('Int删除...')

class People:
name=Str()
age=Int()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age

#何地?:定义成另外一个类的类属性

#何时?:且看下列演示

p1=People('alex',18)

#描述符Str的使用
p1.name
p1.name='egon'
del p1.name

#描述符Int的使用
p1.age
p1.age=18
del p1.age

#我们来瞅瞅到底发生了什么
print("__p1.__dict__",p1.__dict__)
print(People.__dict__)

#补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__)

  

输出结果

  Str设置...
Int设置...
Str调用
Str设置...
Str删除...
Int调用
Int设置...
Int删除...
__p1.__dict__ {}
{'__module__': '__main__', 'name': <__main__.Str object at 0x021C6850>, 'age': <__main__.Int object at 0x021C6870>, '__init__': <function People.__init__ at 0x021C5DB0>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
True
True

  

3、描述符分两种

(1) 数据描述符:至少实现了__get__()__set__()


class Foo:
def __set__(self, instance, value):
print('set')
def __get__(self, instance, owner):
print('get')

  

(2) 非数据描述符:没有实现__set__()

  class Foo:
def __get__(self, instance, owner):
print('get')

  

注意:非数据描述符一般是只有__get__,如果保留__delete__执行会报错。

4、 注意事项:

(1)描述符本身应该定义成新式类,被代理的类也应该是新式类(python3中全部是新式类)

(2)必须把描述符定义成另外一个类的类属性,不能为定义到构造函数中,

(3)要严格遵循该优先级,优先级由高到底分别是

a.类属性b.数据描述符c.实例属性d.非数据描述符e.找不到的属性触发__getattr__()

例子1

  
  class Foo:

def __get__(self, instance, owner):
print("执行了__get__")

def __set__(self, instance, value):
print("执行了__set__")

def __delete__(self, instance):
print("执行了__delete__")

class People:

name = Foo()

def __init__(self,name):
self.name = name


p = People("nick")
People.name = "nick" #调用执行了描述符的__set__方法,这一步类属性由之前的描述符被定义成另外一个字符串,
# 所以下面再次调用就无法再次使用描述符了
People.name

#可以得出结论,类属性的优先级大于数据描述符

  

例子2

  
  class Foo:

def __get__(self, instance, owner):
print("执行了__get__")

def __set__(self, instance, value):
print("执行了__set__")

def __delete__(self, instance):
print("执行了__delete__")

class People:

name = Foo()

def __init__(self,name):
self.name = name


p = People("nick") #实例化对象,调用数据描述符的__set__,
# 但是由于描述符的__set__只是执行了打印操作,什么都没做,所以p对象的__dict__什么都没有
p.name = "nicholas"
print(p.__dict__) #输出的结果为空

#因此可以得出结论,数据描述符的优先级大于实例属性(字典操作)

  

例子3

  class Foo(object):
def __init__(self):
pass

def __get__(self, instance, owner):
print("执行了__get__")

class People(object):

name = Foo("x")

def __init__(self,name,age):
self.name = name
self.age = age



p = People("nick",18) #实例化对象,这里由于是非数据描述符,优先级低于实例属性,
# 所以这里直接设置了实例属性,而不再调用描述符
print(p.name) #打印直接输出实例属性
print(p.__dict__)
#输出的结果:{'name': 'nick', 'age': 18}

#因此可以得出结论,实例属性的优先级大于非数据描述符

  

例子4

  class Foo(object):
def __init__(self,name2):
self.name2 = name2

def __get__(self, instance, owner):
print("执行了__get__")


class People(object):

name = Foo("x")

def __init__(self,name,age):
self.name = name
self.age = age

def __getattr__(self, item):
print("__getattr__")


p = People("nick",18) #实例化对象,这里由于是非数据描述符,优先级低于实例属性,
# 所以这里直接设置了实例属性,而不再调用描述符
print(p.name)
print(p.sex) #调用不存在的属性执行了__getattr__
print(p.__dict__)
#输出的结果:{'name': 'nick', 'age': 18}

  

5、描述符的应用

例子1

  
  class Type:

def __init__(self,key,expect_type):
self.key = key
self.expect_type = expect_type

def __get__(self, instance, owner):
print("执行__get__方法")
print(self) #这里的self就是type类的对象
print(instance) #这里的instance就是传入的People类的对象
print("执行__get__方法")
return instance.__dict__[self.key] #通过instance的字典获取对象的属性值

def __set__(self, instance, value):
print("执行__set__方法")
instance.__dict__[self.key] = value #instance是另一个类的对象,这里要设置对象的属性字典

def __delete__(self, instance):
print("执行__delete__方法")
instance.__dict__.pop(self.key) #删除对象的属性

class People:
name = Type("name",str)
age = Type("age",int)

def __init__(self,name,age):
self.name = name
self.age = age

p1 = People("nick",18) #调用2次描述符,对对象的字典进行设置
print(p1.name) #通过数据描述符获取对象的属性值
print(p1.__dict__)
p1.age = 20 #调用描述符对对象进行设置
print(p1.__dict__)

  

输出结果

  
  执行__set__方法
执行__set__方法
执行__get__方法
<__main__.Type object at 0x004CB4F0>
<__main__.People object at 0x02106DF0>
执行__get__方法
nick
{'name': 'nick', 'age': 18}
执行__set__方法
{'name': 'nick', 'age': 20}

  

例子2

  
  class Type:

def __init__(self,key,expect_type):
self.key = key
self.expect_type = expect_type

def __get__(self, instance, owner):
print("执行__get__方法")
print(self) #这里的self就是type类的对象
print(instance) #这里的instance就是传入的People类的对象
print("执行__get__方法")
return instance.__dict__[self.key] #通过instance的字典获取对象的属性值

def __set__(self, instance, value):
print("执行__set__方法")
if not isinstance(value,self.expect_type):
print("您输入的%s不是%s"%(self.key,self.expect_type))
raise TypeError
instance.__dict__[self.key] = value #instance是另一个类的对象,这里要设置对象的属性字典

def __delete__(self, instance):
print("执行__delete__方法")
instance.__dict__.pop(self.key) #删除对象的属性

class People:
name = Type("name",str)
age = Type("age",int)

def __init__(self,name,age):
self.name = name
self.age = age

p1 = People("nick",18) #调用2次描述符,对对象的字典进行设置
print(p1.name) #通过数据描述符获取对象的属性值
print(p1.__dict__)
p1.age = 20 #调用描述符对对象进行设置
print(p1.__dict__)
# p1.name = 11 #通过描述符的if not isinstance(value,self.expect_type)判断属性的类型

# p2 = People(88,18) #通过描述符的if not isinstance(value,self.expect_type)判断属性的类型

  

四、__enter____exit__

打开文件操作用 with open() as f操作,这叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter____exit__方法。

__enter__(self):当with开始运行的时候触发此方法的运行

__exit__(self, exc_type, exc_val, exc_tb):当with运行结束之后触发此方法的运行

exc_type如果抛出异常,这里获取异常的类型

exc_val如果抛出异常,这里显示异常内容

exc_tb如果抛出异常,这里显示所在位置

用途或者说好处:

1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预

2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处

例子

class OPEN:

    def __init__(self,name):
self.name = name def __enter__(self):
print("执行__enter__")
return self def __exit__(self, exc_type, exc_val, exc_tb):
print("执行__exit__")
print(exc_type)
print(exc_val)
print(exc_tb)
print("执行__exit__2222") with OPEN("a.txt") as f:
print(f) #执行打印__enter__内置方法,同时打印内置方法返回的结果 #with 语句结束时执行__exit__方法,没有错误则打印None,有错误则打印错误的信息
print("上下文管理协议")

  

最新文章

  1. sip协议音视频性能测试
  2. C语言简易文法(无左递归)
  3. hdu 4411 2012杭州赛区网络赛 最小费用最大流 ***
  4. atitit.提升开发效率---mda 软件开发方式的革命
  5. 根据BIOS信息修改主机名
  6. batch批的概念
  7. html之a标签
  8. linux中/etc/init.d [转]
  9. AngularJs学习笔记4——四大特性之双向数据绑定
  10. 漫画研发之十二:该听谁的? 部门经理 or 项目经理
  11. C++ STL 双端队列deque详解
  12. PHP初入--表单元素
  13. 《团队-Android手机便签-项目进度》
  14. 在Codeblocks下配置GoogleTest单元测试工具
  15. join算法分析
  16. Java设计模式学习记录-解释器模式
  17. Windows7安装两个jdk配置
  18. ms11_050漏洞攻击
  19. sql一些语句性能及开销优化
  20. 深入浅出 JIT 编译器

热门文章

  1. java.security.MessageDigest (1)
  2. spring boot 2 内嵌Tomcat Stopping service [Tomcat]
  3. Eclipse git 冲突合并
  4. 径向模糊(Radial Blur)
  5. javascript学习笔记(三):运算符、循环语句
  6. Python基础之字典操作
  7. 解决镜像无法删除的问题multiple repositories
  8. Lua面试题目
  9. Python: 调用youtube_dl实现视频下载
  10. 【Linux 线程】常用线程函数复习《三》