1.描述符

#!/usr/bin/python env
# coding=utf-8
# 数据描述符__get__ __set__ __delete__
'''
描述符总结
描述符是可以实现大部分python类特性中的底层魔法,包括@classmethod,@staticmethd,@property甚至是__slots__属性
描述符是很多高级库和框架的重要工具之一,描述符通常是使用到装饰器或者元类的大型框架中的一个组件 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
描述符分2种
1.数据描述符:至少有get set方法
2.非数据描述符:没有set方法 '''
class Str:
def __init__(self, name,val_type):
self.name = name
self.val_type = val_type
# instance 实例对象 owner实例的类
def __get__(self, instance, owner):
print('get方法', instance, owner)
return instance.__dict__[self.name]
# instance 实例对象 value实例的值
def __set__(self, instance, value):
print('set方法', instance, value)
if not isinstance(value, self.val_type):
raise TypeError("%s 的数据类型不是 %s" % (value, self.val_type))
instance.__dict__[self.name] = value def __delete__(self, instance):
print('delete方法', instance)
instance.__dict__.pop(self.name) class People:
# 描述符
name = Str('name', str)
age = Str('age', int)
salary = Str('salary', int) def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary p1 = People('wangwu', 12, 98921) # 调用
print(p1.__dict__)
# print(p1)
# p1.name # #赋值
# print(p1.__dict__)
# p1.name='egonlin'
# print(p1.__dict__)
#
# #删除
# print(p1.__dict__)
# del p1.name
# print(p1.__dict__)

2.上下文管理协议

操作文件对象写法

1 with open('a.txt') as f:
2   '代码块'

上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法

# 上下文管理协议 with
'''
# with open('filename') as f:
# 代码块
1.with.obj ---> obj.__enter__(), return val
2.as f ----> f=val
3.with obj as f === f=obj.__enter()
4.执行
1)没有异常时,all code运行后,__exit__ 三个参数都为None
2)有异常时,从异常的的位置触发__exit__
a。如果exit的返回值为True,吞掉了异常
b.反之,抛出异常
c.exit的代码执行完毕代表了整个with语句执行完毕
'''
class Foo:
def __init__(self, name):
self.name = name def __enter__(self): # 出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
return self # exc_type 异常类:NameError
# exc_val 异常值:name 'abc异常abc' is not defined
# exc_tb 追踪信息: Traceback后面的内容
# Traceback(most recent call last):
# NameError: name 'abc异常abc' is not defined
def __exit__(self, exc_type, exc_val, exc_tb): # with里有异常时 触发改函数
print("%s %s %s" % (exc_type, exc_val, exc_tb))
return True # 如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行 with Foo('a.txt') as f:
print(f)
# print(abc异常abc)
print(f.name)
print("*"*100)
# 上下文管理实例
class Open:
def __init__(self,filepath,mode='r',encoding='utf-8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding def __enter__(self):
# print('enter')
self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
return self.f def __exit__(self, exc_type, exc_val, exc_tb):
# print('exit')
self.f.close()
return True
def __getattr__(self, item):
return getattr(self.f,item) with Open('a.txt','w') as f:
print(f)
f.write('aaaaaa')
f.wasdf #抛出异常,交给__exit__处理

3.类装饰器

# 函数装饰器范式
# def wrap(func):
# def wrapper(*args, **kwargs):
# func(*args, **kwargs)
# return True
# return wrapper # 无参类装饰器范式
# def wrap(cls):
# return cls # 有参类装饰器范式
# def wrap(**kwargs):
# def wrapper(obj):
# # 操作kwargs
# return obj
# return wrapper # 有参类装饰器
class Check_type:
def __init__(self, name, val_type):
self.name = name
self.val_type = val_type # instance 实例对象 owner实例的类
def __get__(self, instance, owner):
# print('get方法', instance, owner)
return instance.__dict__[self.name] # instance 实例对象 value实例的值
def __set__(self, instance, value):
# print('set方法', instance, value)
if not isinstance(value, self.val_type):
raise TypeError("%s的数据类型不是 %s" % (value, self.val_type))
instance.__dict__[self.name] = value def __delete__(self, instance):
# print('delete方法', instance)
instance.__dict__.pop(self.name) def Typed(**kwargs): # kwargs ===> name=str, age= int, salary=int
def wrapper(obj):
for key, val in kwargs.items():
# 描述符 val是key的类型
# val = Check_type('val', str)
setattr(obj, key, Check_type(key, val))
return obj
return wrapper @Typed(y=2, x=1, z=3)
class Foo:
pass @Typed(name='wangwu')
class foo:
pass @Typed(name=str, age=int, salary=int) # @warpper -->People=warper(people)
class People:
# 描述符
# name = Str('name', str)
# age = Str('age', int)
# salary = Str('salary', int)
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary print(People.__dict__)
p1 = People('wangwu', "d", 98921) # 调用
print(p1.__dict__)

4.仿property

# 类装饰器
# class Cls_property:
# def __init__(self,func):
# self.func = func
# 仿property类装饰器 class Cls_property:
def __init__(self, func):
# print("func属性 %s " %(func))
self.func = func # 描述get有两个参数 第一个是实例 第二个是类
def __get__(self, instance, owner):
# val = self.func()
print('get---->')
print('instance: %s' % instance) # 实例对象 r1
print('owner: %s' % owner) # 类 Room
if instance is None:
return self
res = self.func(instance)
# property延时计算
setattr(instance, self.func.__name__, res)
return res
# 加上set 数据描述符
# def __set__(self, instance, value):
# pass class Room:
tag = 168 def __init__(self, owner, width, length):
self.owner = owner
self.width = width
self.length = length # @cls_property
@Cls_property # area=property(area)
def area(self):
return self.width * self.length # @cls_property
@property # area=property(area)
def area1(self):
return self.width * self.length # 类方法 能访问类的属性不能访问实例属性
@classmethod
def test_tag(cls, x):
print(cls)
print("from test_tag %s %s" % (cls.tag, x)) # 静态方法 不能访问类、实例属性
@staticmethod
def action(a, b, c):
print("%s %s %s" % (a, b, c)) # 类可以调用,实例不可调用test
def test(cls, x):
print(cls)
print("from test_tag %s %s" % (cls.tag, x)) @property # <property object at 0x01FE80F0>
def pro_test(self):
return "pro_test" r1 = Room('zq', 1, 100)
print(r1.__dict__) # 没找到area属性值 那就调用代理的Roo的area值
print(r1.area)
print(r1.__dict__) # 没找到area属性值 那就调用代理的Roo的area值
print(r1.area)
print(r1.area)
print(r1.area)
# print(Room.__dict__['area']) # print(Room.area)
# print(Room.pro_test) # 一个静态属性property本质就是实现了get,set,delete三种方法
# 方法一
class Foo:
@property
def AAA(self):
print('get的时候运行我啊') @AAA.setter
def AAA(self,value):
print('set的时候运行我啊', value) @AAA.deleter
def AAA(self):
print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
print("<----------------------->") # 方法二
class Foo:
def get_AAA(self):
print('get的时候运行我啊') def set_AAA(self,value):
print('set的时候运行我啊', value) def delete_AAA(self):
print('delete的时候运行我啊')
AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

5.元类 metaclass

元类是类的类,是类的模板

元类的实例是类,类的实例是 对象

type是python的一个内建元类 ,用来控制生成类,python中任何class定义的类其实都是type类实例化的对象

# 创建类有2种方法
# metaclass
# 类的默认元类是type
# 1.
class Foo:
pass
# tpye(str)
t = type(Foo)
print(t)
# print(t.__dict__) def test(self):
pass
def __init__(self, name, age):
self.name = name
self.age = age # s三个参数 类名 (父类,), {属性字典}
# 2.type(类名,(object,),{})
t = type('t', (object,), {'a': 1, '__init__': __init__, 'test': test})
print(t.__dict__) # {'a': 1, '__weakref__': <attribute '__weakref__' of 't' objects>, '__init__': <function __init__ at 0x002C4738>, '__module__': '__main__', 'test': <function test at 0x00703660>, '__doc__': None, '__dict__': <attribute '__dict__' of 't' objects>}
print(t) # <class '__main__.t'>
print("------------------------->") # 自定义元类
class Mytype(type):
def __init__(self, *args, **kwargs):
print("元类的自定义类")
# for i in args:
# print(i) def __call__(self, *args, **kwargs): # self == Foo
# print("__call__函数:",self)
obj = object.__new__(self) # object.__nee__(Foo) --> 产生 f1 产生实例obj
# print("obj产生: ",obj)
self.__init__(obj, *args, **kwargs) # Foo.__init__()
return obj class Foo(metaclass=Mytype): # Mytype(传了4个参数: self,Foo,(),{})-->触发mytype __init__
def __init__(self, name):
self.name = name # f1.name = name print(Foo)
f1 = Foo('wangwu')
print(f1)
# print(f1.__dict__)

参考:http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label15

python 描述符 上下文管理协议 类装饰器 property metaclass的更多相关文章

  1. Python之面向对象上下文管理协议

    Python之面向对象上下文管理协议 析构函数: import time class Open: def __init__(self,filepath,mode='r',encode='utf-8') ...

  2. python基础----实现上下文管理协议__enter__和__exit__

    我们知道在操作文件对象的时候可以这么写 with open('a.txt') as f: '代码块' 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明_ ...

  3. Python系列之 - 上下文管理协议

    with obj as f: '代码块' 1.with obj ---->触发obj.__enter__(),拿到返回值 2.as f----->f=返回值. 3.with obj as ...

  4. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  5. 11.python描述符---类的装饰器---@property

    描述符1.描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()这三个内置方法中的一个,描述符也被称为描述符协议(1):__ ...

  6. 杂项之python描述符协议

    杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用 ...

  7. Descriptor - Python 描述符协议

    描述符(descriptor) descriptor 是一个实现了 __get__. __set__ 和 __delete__ 特殊方法中的一个或多个的. 与 descriptor 有关的几个名词解释 ...

  8. python实现可以被with上下文管理的类或函数

      # .开始之前先明确一下with机制 # 1.类包函数__enter__()和__exit__()函数,即是可以被上下文管理的类 # __enter__用来执行with时的方法,__exit__返 ...

  9. 用python优雅打开文件及上下文管理协议

    有次面试被问到如何优雅地打开一个文件?   那就是用with语句,调用过后可以自动关闭.   但是为什么使用with语句就可以自动关闭呢,原因就是上下文管理协议.   上下文管理协议:包含方法 __e ...

随机推荐

  1. Codeforces Round #556 (Div. 2)-ABC(这次的题前三题真心水)

    A. Stock Arbitraging 直接上代码: #include<cstdio> #include<cstring> #include<iostream> ...

  2. python实现数据库增删改查

    column_dic = {"id": 0, "name": 1, "age": 2, "phone": 3, &quo ...

  3. springboot自定义jmx对象

    在使用springboot-admin对springboot项目进行监控的时候我们发现其是具有web访问jmx对象的功能的,那它内部是怎么实现的呢. Jolokia是一个JMX-http桥梁,它提供了 ...

  4. windows 下 pyinstaller distutils not included with latest virtualenv (16.4.0)

    起因 因为windows下python3.7.2内置venv虚拟环境下pyinstaller错误问题,切换virtualenv但是发现最新版本又有其他问题 - -! ModuleNotFoundErr ...

  5. WebGIS简单实现一个区域炫酷的3D立体地图效果

    1.别人的效果 作为一个GIS专业的,做一个高大上的GIS系统一直是我的梦想,虽然至今为止还没有做出一个理想中的系统,但是偶尔看看别人做的,学习下别人的技术还是很有必要的.眼睛是最容易误导我们的,有时 ...

  6. Docker实战:更轻松、更愉快、更高效

    编者按:借助Docker,我们可以更容易地进行web应用部署,而同时不必头疼于项目依赖.环境变量以及各种配置问题,Docker可以快捷.高效地处理好这一切.而这也是本教程所要实现的主要目的.以下是作者 ...

  7. FAQ of db2fmp messages in the db2diag.log

    http://www-01.ibm.com/support/docview.wss?uid=swg21470035 Technote (FAQ) Question What do these mess ...

  8. Linux下C++开发常用命令

    本页面记录本人在Linux下进行C++开发时使用的常用命令,注意这里不包括比如ls,mv等linux命令,这里会持续更新.首先假设你只有一个源程序文件,叫vec.cpp,编译后的可执行程序叫vec(本 ...

  9. 【Vim】Vim学习

    1. 三种模式 (1)命令模式:刚启动vim便进入命令模式,此时敲击键盘会被当做命令来处理 以下是常用的几个命令: i 切换到插入模式,以输入字符.x 删除当前光标所在处的字符.: 切换到底线命令模式 ...

  10. mongo 固定集合,大文件存储,简单优化 + 三招解决MongoDB的磁盘IO问题

    1.固定集合 > db.createCollection(, max:});//固定集合 必须 显式创建. 设置capped为true, 集合总大小xxx字节, [集合中json个数max] { ...