python 类装饰器 添加属性_【python 第9日】上下文 类装饰器 元类 属性描述符扩展...

with 上下文管理

包含__enter__/__exit__的模块

classWithTest:def __init__(self, name):print("这里是初始化")

self.name=namedef __enter__(self):print("这里是%s的enter" %self.name)returnselfdef __exit__(self, exc_type, exc_val, exc_tb):print("这里是%s的exit" %self.name)print("exc_type", exc_type)print("exc_val", exc_val)print("exc_tb", exc_tb)returnTrue

with WithTest("zgl") as f:print(f.name)print(sss)print("---------->")

输出如下

这里是初始化

这里是zgl的enter

zgl

这里是zgl的exit

exc_typeexc_val name'sss' is notdefined

exc_tb

首先Withtest("zgl"),如果这里出错,上下文管理器是管理不到的,始终会报错,除非再外层加try/except

然后进入__enter__, 要return self 否则f接受到的是None类型

然后开始执行,上下文里面的内容,对于里面的变量赋值,外层函数也可以用,比如a =1 在最外层也是可以用的

如果报错,立刻进入__exit__, exc_type返回的异常类型, exc_val返回的是异常信息, exc_tb返回的是异常栈

如果__exit__返回True,则不报错,进行控制,编译器不发出异常,如果不返回True,则编译器仍然报错

之后不在执行后面的代码,推出上下文管理

类装饰器

类装饰器定义

在类外加上装饰器,使其增加附加功能,返回类

#给每个类添加一个数据属性和一个函数属性

def Decorator(obj):#print(School.__dict__)

#添加数据属性

obj.addr = "浙江省杭州市"

defprice():pass

#添加函数属性

obj.price =pricereturnobj #一定返回的是类本身

@Decorator#相当于执行 School = Decorator(School)

classSchool():def __init__(self,name,price):

self.name=name

self.price=price#打印类的属性字典

print(School.__dict__)

#

{'__module__': '__main__', '__init__': , '__dict__': , '__weakref__': , '__doc__': None, 'addr': '浙江省杭州市', 'price': .price at 0x035D8588>}

带参数的类装饰器

添加可变参数,易于管理,

#给每个类添加一个可变的数据属性

def Decorator(**kwargs):defadd(obj):"添加数据属性"

#print('调用外部函数的**kwargs',kwargs)

for key,val inkwargs.items():#添加数据属性

setattr(obj,key,val) #不可以用obj.__dict__ 的修改操作,是不可变更字典类型returnobj#print("外部传入的参数为:",kwargs)

returnadd

@Decorator(addr= "浙江省杭州市",name ="浙江大学") #执行顺序:1.运行Decorator函数,先打印外部的传入的参数,返回add函数名;2.再执行School = add(School)

classSchool():def __init__(self,price):

self.price=price

@Decorator(addr= "湖北省",price =12000)classSchool1():pass

print(School.__dict__)print(School1.__dict__)

装饰器类

和上面不同,是把类作为装饰器,相当于类的初始化

做一个Property类,把类中的函数变成静态变量

classProperty:def __init__(self, func):

self.func=funcdef __get__(self, instance, owner):#print(self, instance, owner)

#self 调用对象,也就是score实例, instance是test实例 owner归属的类Test

if notinstance:return self #如果类调用返回对象

return self.func(instance) #实例调用这

def __set__(self, instance, value):#print(self, instance, value)

instance.__dict__[ self.func.__name__ ] = value #修改实例test字典

classTest:def __init__(self, mark, discount):

self.mark=mark

self.discount=discount

@Property#实例f = Property(score) 这里是类,数据描述符

defscore(self):return self.mark *self.discount

@propertydefscore1(self):return self.mark *self.discount

test= Test(10, 0.8)#print(Test.score1) ##print(Test.score) #<__main__.property object at>#print(test.score1) #8.0#print(test.score) #8.0

test.score = 1

print(test.__dict__)print(test.__dict__["score"])print(test.score) #8.0 要想使用__dict__的,必须不加__set__, 在__get__里面修改 set(obj, name, value)

做一个classmethod类,把类中的方法变成类方法

本来想通过__call__实现,但是最后,不会获取函数的外层类,所以失败,如果只写Test,那太固定了,没意思,希望厉害的人回复,怎么获取函数的外层类,不是函数的类

classClassmethond:def __init__(self, func):

self.func=funcdef __get__(self, instance, owner):def wrap(*args, **kwargs):return self.func(owner, *args, **kwargs)returnwrap#def __call__(self, *args, **kwargs):

## print(self.cla , self, *args, **kwargs)

#return self.func(self.cla , *args, **kwargs) #本来想通过__call__实现,但是最后,不会获取函数的外层类,所以失败,如果只写Test,那太固定了,没意思

classTest:

x= 1

def __init__(self, mark, discount):

self.mark=mark

self.discount=discount

@Classmethond#实例f = Property(score) 这里是类,数据描述符

defscore(cls):print(cls, cls.x)

@classmethoddefscore1(cls):print(cls, cls.x)

Test.score1()# 1

Test.score() # 1

test= Test(1, 0.8)

test.score1()# 1

test.score() # 1

做一个staticmethod 类,把类中的方法变成静态方法

classStaticmethod:def __init__(self, func):

self.func=funcdef __get__(self, instance, owner):returnself.func#def __call__(self, *args, **kwargs):

## print(self.cla , self, *args, **kwargs)

#return self.func(self.cla , *args, **kwargs)

classTest:

x= 1

def __init__(self, mark, discount):

self.mark=mark

self.discount=discount

@Staticmethoddefscore():print("静态方法")

@staticmethoddefscore1():print("这是静态方法1")#Test.score1()

Test.score1() #这是静态方法1

Test.score() #静态方法

test= Test(10, 0.8)

test.score1()#这是静态方法1

test.score() #静态方法

元类   type 自定义(类名,父类,属性)

元类定义

元类就是用来创建类的“东西”。你创建类就是为了创建类的实例对象,不是吗?但是我们已经学习到了Python中的类也是对象。好吧,元类就是用来创建这些类(对象)的,元类就是类的类,

因此,元类就是创建类这种对象的东西。如果你喜欢的话,可以把元类称为“类工厂”(不要和工厂类搞混了:D) type就是Python的内建元类,当然了,你也可以创建自己的元类。

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

class Foo(object):

__metaclass__ = something…

[…]

Python做了如下的操作:

Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。

现在的问题就是,你可以在__metaclass__中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。

抽象函数

importabcclass Abs(metaclass=abc.ABCMeta):#class Abs(object):#__metaclass__ = abc.ABCMeta #这个命名方式不行,不知道为什么 是python3 新修改的么

@abc.abstractmethoddefabstar(self):pass

print(Abs.__dict__)

abcd= Abs()

自定义元类

classUpperAttrMetaclass(type):def __new__(cls, name, bases, dct):

attrs= ((name, value) for name, value in dct.items() if not name.startswith('__'))

uppercase_attr= dict((name.upper(), value) for name, value inattrs)return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)class A(metaclass=UpperAttrMetaclass):pass

就是这样,除此之外,关于元类真的没有别的可说的了。使用到元类的代码比较复杂,这背后的原因倒并不是因为元类本身,而是因为你通常会使用元类去做一些晦涩的事情,依赖于自省,控制继承等等。确实,用元类来搞些“黑暗魔法”是特别有用的,因而会搞出些复杂的东西来。但就元类本身而言,它们其实是很简单的:

1)   拦截类的创建

2)   修改类

3)   返回修改之后的类

属性描述符、property(@setter,@deleter)和__setattr__

我这是么理解的,

property用于的是少数属性的控制,1个2个

属性描述符用于的是某些的相同属性的控制   具有相同属性

__setattr__ 全部属性的控制,当然也可以部分,不够代码结构复杂

__get__  __getAttribute__ ___getattr__  __getitem__ 顺序

__get__使用在数据描述符中,暂时不考虑,后面三个的优先级顺序为__getitem__ > __getAttribute__ >___getattr__

对类属性A.x的获取不触发,对a.x的获取才触发

其他set  del的顺序和这个一致,

__del__是析构函数是在实例删除时候触发的

classA:

data= 1

def __init__(self, id):

self.id=iddef __getattribute__(self, item):print("这里是getattribute",item)#raise AttributeError

#print("这是getattribute后期")

#return object.__getattribute__(self, item)

return super(A, self).__getattribute__(item)def __getattr__(self, item):print("这里是getattr")def __getitem__(self, item):print("这里是getitem", item)#raise AttributeError

return self.__dict__[item]#return object.__getattribute__(self, item)

#if item in self.__dict__:

#return self.__dict__[item]

#else:

#raise ValueError

a = A("11")print(a.__dict__)#这里是getattribute __dict__#{'id': '11'}

print(a.data)#这里是getattribute data#1

print(a.x)#这里是getattribute x#这里是getattr#None

print(a["x"])#这里是getitem x#这里是getattribute __dict__###KeyError: 'x'

print(a["data"])#这里是getitem data#这里是getattribute __dict__#KeyError: 'data'

print(a["id"])#这里是getitem id#这里是getattribute __dict__#11

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值