python 描述符 上下文管理协议 类装饰器 property metaclass

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

# 2.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三个参数 类名 (父类,), {属性字典}
# 3.type(str,(object,),{})
t = type(‘str‘, (object,), {‘a‘: 1, ‘__init__‘: __init__, ‘test‘: test})
print(t.__dict__)
print(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

原文地址:https://www.cnblogs.com/icemonkey/p/10459477.html

时间: 2024-10-25 22:13:00

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

Python之路(十二):描述符,类装饰器,元类

python基础之面向对象(描述符.类装饰器及元类) 描述符 描述符(__get__,__set__,__delete__)   # 这里着重描述了python的底层实现原理 1. 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议. __get__():调用一个属性时,触发 __set__():为一个属性赋值时,触发 __delete__():采用del删除属性时,触发 1 class

Python基础- 类和对象(使用、继承、派生、组合、接口、多态、封装、property、staticmethod、classmethod、反射、slots、上下文管理协议、元类)

标签: python对象 2017-07-01 16:28 79人阅读 评论(0) 收藏 举报  分类: python(11)  版权声明:本文为广大朋友交流学习,如有纰漏望不吝赐教,若存在版权侵犯请及时与我联系 目录(?)[+] 一.初识类和对象 在python3中类型就是类 先定义类在产生相对应的对象,也就是现有了概念再有了实体 class Garen: camp = 'Demacia' def attack(self): print('attack') 1.如何使用类 在python3:

python描述符、property、函数(类)装饰器实例解析

1 import sys 2 3 ''' 4 当使用实例对象访问属性时,都会调用__getattribute__内建函数 5 __getattribute__查找属性的优先级 6 1.类属性 7 2.数据描述符 8 3.实例属性 9 4.非数据描述符 10 5.__getattr__() 11 12 #实例.属性 13 c.x ==>type(x).__dict__['x'].__get__(x,type(x)) 14 #类.属性 15 C.x ==>X.__dict__['x'].__get

杂项之python描述符协议

杂项之python描述符协议 本节内容 由来 描述符协议概念 类的静态方法及类方法实现原理 类作为装饰器使用 1. 由来 闲来无事去看了看django中的内置分页方法,发现里面用到了类作为装饰器来使用,由于之前就看到过这一类的用法,但是一直没有明白具体是如何实现的,今天本着打破砂锅问到底的精神去网上搜资料,在这里不得不吐槽下百度搜索的垃圾了.....竞价排名做的那么6,搜一些技术文档.....各种坑爹...就是找不到想要的资源...于是FQ上google搜了搜,找到了python官网的文档...

关于__setitem__,__getitem__,delitem__以及__slots__,迭代器原理,上下文管理协议还有元类

关于__setitem__,__getitem__,delitem__ 类似于以前的学过的__setattr__,__getattr__... 不同之处在于item结尾的是用于对象以字典添加的形势添加,查看和删除属性的时候才会触发,如下例子: class Foo(object): # __slots__=['x','y'] def __setitem__(self, key, value): print('我在写入') self.__dict__[key]=value def __getitem

Python概念-上下文管理协议中的__enter__和__exit__

所谓上下文管理协议,就是咱们打开文件时常用的一种方法:with __enter__(self):当with开始运行的时候触发此方法的运行 __exit__(self, exc_type, exc_val, exc_tb):当with运行结束之后触发此方法的运行 exc_type如果抛出异常,这里获取异常的类型 exc_val如果抛出异常,这里显示异常内容 exc_tb如果抛出异常,这里显示所在位置 代码示例:(以自己定义的Open类型做示例) 1 # 编辑者:闫龙 2 class Open: 3

Iterator Protocol - Python 描述符协议

1 Iterator Protocol - Python 描述符协议 2 3 先看几个有关概念, 4 iterator 迭代器, 5 一个实现了无参数的 __next__ 方法, 并返回 '序列'中下一个元素,在没有更多的元素可返回的时候 raises StopIteration 的对象, 6 被称为 iterator(迭代器). 7 在 python 中, 迭代器 'iterator' 同时也实现了 __iter__ 方法, 故 iterators are iterable. 8 经典迭代器

python 面向对象编程 之 上下文管理协议

with open('path', 'r' ,encoding='utf-8') as f: 代码块 上述就叫做上线文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法. 上下文管理协议: class Open: def __init__(self,name): self.name=name def __enter__(self): print('出现with语句 ,对象的__enter__被触发,有返回值则赋值给as声明的

Python进阶-----上下文管理协议(__enter__,__exit)

一.上下文管理协议 即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法 1.__enter__()会在with语句出现(实例化对象)时执行 2.__exit__()会在with语句的代码块实行完毕才会执行 1 class Open: 2 def __init__(self,name): 3 self.name = name 4 5 def __enter__(self): #在实例化打开文件时即触发,在with时触发 6 print(