python学习笔记-面向对象进阶

一、反射

定义:反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

四个可以实现自省的函数
下面方法适用类和对象(一切皆对象,类本身也是对象)
hasattr(object,name)
getattr(object,name,default="xxx")
setattr(object,"name","ssss")
delattr(object,"name")

用法:

#四个方法的用法
class BlackMedium:
    feature='Ugly'
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_house(self):
        print('%s 黑中介卖房子啦' %self.name)
    def rent_house(self):
        print('%s 黑中介租房子啦' %self.name)

b1=BlackMedium('新华置地','天宫大道')

#检测是否含有某属性
print(hasattr(b1,'name'))   #Trur
print(hasattr(b1,'sell_house')) #True

#获取属性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func()

# getattr(b1,'aaaaaaaa') #报错
print(getattr(b1,'aaaaaaaa','不存在啊'))

#设置属性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')
print(b1.__dict__)#{'name': '新华置地', 'addr': '天宫大道', 'sb': True, 'show_name': <function <lambda> at 0x00000210EB131E18>}
print(b1.show_name(b1))

#删除属性
delattr(b1,'addr')
delattr(b1,'show_name')
#delattr(b1,"shou_name111")#不存在,则报错

print(b1.__dict__) #{'name': '新华置地', 'sb': True}

补充:动态导入模块

#例子:调用m1目录下的文件
module_t=__import__("m1.t")
print(module_t) #获得的是最顶级的模块m1,但是会执行到t
module_t.t.test1()

#1
#test2是加_的私有方法时,不能通过import *导入
from m1.t import *
test1()
#_test2()#报错

#2
from m1.t import test1,_test2
test1()
_test2() #能导入

#3 正确的做法
import importlib
m=importlib.import_module("m1.t")#取到的就是m1.t模块
print(m)
m.test1()

例子1:模块也是对象

#1
import test as obj
print(hasattr(obj,"say_hi"))

if hasattr(obj,"say_hi"):
    func=getattr(obj,"say_hai")
    func()
else:
    print("执行其他操作")

#2,导入当前模块
xxx=111
import sys
obj1=sys.modules[__name__]
print(hasattr(obj1,"xxx")) #True
好处:一、实现可插拔机制,二,动态导入模块(基于反射原理)

二、类的内置attr属性(__setattr__,__delattr__,__getattr__)

例子1,__getattr__

class Foo:
    x=1
    def __init__(self,y):
        self.y=y
    def __getattr__(self, item):
        print("执行__getattr__")

f1=Foo(10)
print(f1.y)
print(getattr(f1,"y")) #10
f1.sss #执行__getattr__

例子2,__setattr__,__delattr__

class Foo:
    x=1
    def __init__(self,y):
        self.y=y
    def __delattr__(self,item):
        # self.__dict__.pop(item)
        print("删除")

    def __setattr__(self,key,value):
        print("__setattr__执行")
        # self.key=value 报错,无限递归
        self.__dict__[key]=value

# f1=Foo(10)  #__setattr__执行
# del f1.y   #删除
# del f1.x   #删除

f1=Foo(10)
print(f1.__dict__)#{'y': 10}
f1.z=2
print(f1.__dict__)
print(Foo.__dict__)#查看属性字典
print(dir(Foo)) #更全面,可以查看内置属性__getattr__,__delattr__,__setattr__

f1=Foo(8)
print(f1.x) #只有在属性不存在时,会自动触发__getattr__,  用得较多
del f1.x    #删除属性时会触发__delattr__
f1.y=10     #设置属性的时候会触发__setattr__

例子3,继承的方式完成包装

class Foo:
    x=1
    def __init__(self,name):
        self.name=name
    def __setattr__(self,k,v):
        print("执行setarrt",k,v)
        if type(v)==str:
            print("开始设置")
            self.__dict__[k]=v
        else:
            print("必须是字符串类型")

    def __delattr__(self,item):
        print("执行delattr",item)
        self.__dict__.pop(item)


f1=Foo("steven")
f1.age=18
f1.grade="ssss"
print(f1.__dict__)

del f1.name
print(f1.__dict__)

结果为:

执行setarrt name steven
开始设置
执行setarrt age 18
必须是字符串类型
执行setarrt grade ssss
开始设置
{'name': 'steven', 'grade': 'ssss'}
执行delattr name
{'grade': 'ssss'}
View Code

例子4,包装标准类型

class List(list):
    def append(self,p_object):
        if type(p_object) is str:
            # self.append(p_object) #报错,调用自己的append方法,又会进入循环
            # list.append(self,p_object)#调用父类的append方法   写法1
            super().append(p_object)#写法2,推荐
    def show_midlle(self):
        mid_index=int(len(self)/2)
        return self[mid_index]

l1=List("helloword")
print(l1,type(l1))
print(l1.show_midlle())
#对append方法进行包装,只允许增加字符串到列表
l1.append("zzz")
print(l1)

例子5,组合的方式完成授权

import time
class Open:
    def __init__(self,filename,mode="r",encoding="utf-8"):
        # self.filename=filename
        self.file=open(filename,mode,encoding=encoding)
        self.mode=mode
        self.encoding=encoding


    def __getattr__(self,item):
        # print(item)
        return getattr(self.file,item)

    def write(self,line):
        print("---->",line)
        t=time.strftime("%Y-%m-%d %X")
        self.file.write("%s %s"%(t,line))


f1=Open("a.txt","w")
print(f1.file)
f1.read #触发的是__getattr__
print(f1.__dict__)
print(f1.read)
print(f1.write)

f1.write("11111111
")
f1.write("22222222
")

结果为:

<_io.TextIOWrapper name='a.txt' mode='w' encoding='utf-8'>
{'file': <_io.TextIOWrapper name='a.txt' mode='w' encoding='utf-8'>, 'mode': 'w', 'encoding': 'utf-8'}
<built-in method read of _io.TextIOWrapper object at 0x0000029877208B40>
<bound method Open.write of <__main__.Open object at 0x0000029877418630>>
----> 11111111

----> 22222222
View Code

三、isinstance(obj,cls)和issubclass(sub,super)

#isinstance(obj,cls)检查obj是否是类cls的实例
class Foo(object):
    pass
obj=Foo()
isinstance(obj,Foo)
#issubclass(sub,super)检查sub类是否是类super类的子类
class Foo(object):
    pass
class Bar(Foo):
    pass
print(issubclass(Bar,Foo))#True
b1=Bar()
print(isinstance(b1,Foo))#True 对象也属于它父类的实例

四、__getattribute__

不管属性存在不存在都会触发运行

例子1

class Foo:
    x=1
    def __init__(self,y):
        self.y=y
    def __getattr__(self,item):
        print("执行的是getattr")
    def __getattribute__(self,item):
        print("执行的是getattribute")

f1=Foo(10)
f1.x      #执行的是getattribute
f1.xxxx   #执行的是getattribute

例子2

class Foo:
    x=1
    def __init__(self,y):
        self.y=y
    def __getattr__(self,item):
        print("执行的是getattr")
    def __getattribute__(self,item):
        print("执行的是getattribute")
        raise AttributeError("抛出异常了")

f1=Foo(10)
f1.x
f1.xxxx

结果:

执行的是getattribute
执行的是getattr
执行的是getattribute
执行的是getattr
View Code

当__getattribute__与__getattr__同时存在,只会执行__getattribute__,除非__getattribute__在执行过程中抛出AttributeError

 五、__setitem__,__getitem__,__delitem__

用法:

class Foo:
    def __getitem__(self, item):
        print("getitem")
        return self.__dict__[item]
    def __setitem__(self, key, value):
        print("setitem")
        self.__dict__[key]=value
    def __delitem__(self, key):
        print("delitem")
        self.__dict__.pop(key)

f1=Foo()
print(f1.__dict__)
f1["name"]="steven" #触发__setitem__
f1["name"]          #触发__getitem__
del f1["name"]      #触发__delitem__
# del f1.name    #没有触发__delitem__,触发的是__delattr__

print(f1.__dict__)

总结:通过字典的方式操作属性,跟__getitem__等相关,通过点操作属性,跟__getattr__相关

六、__str__与__repr__

改变对象的字符串显示

用法:

#例子1
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return "名字是%s,年龄是%s"%(self.name,self.age)

f1=Foo("steven",18)
print(f1) #触发str的执行 :str(f1)====>f1.__str__()

#例子2
class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __repr__(self):
        return "名字是%s,年龄是%s"%(self.name,self.age)

f1=Foo("steven",18)
#repr(f1)---->f1.__repr__()
print(f1) #找不到str,所以去找repr。执行结果为:”名字是steven,年龄是18“
#repr是在解释器中触发显示的

总结:
str函数或者print函数--->obj.__str__()
repr或者交互式解释器--->obj.__repr__()
如果__str__没有被定义,那么就会使用__repr__来代替输出
注意:这俩方法的返回值必须是字符串,否则抛出异常

 七、__format__自定制

用法:

format_dic = {"ymd": "{0.year}{0.month}{0.day}",
              "y:m:d": "{0.year}:{0.month}:{0.day}",
              "m-d-y": "{0.month}-{0.day}-{0.year}"}
class Data:

    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
    def __format__(self, format_spec): #用format_spec="ymd"方式设默认值时,format(d1)报错,而d1.__format__()正常
        print("开始执行")
        print("===>",format_spec)
        if not format_spec or format_spec not in format_dic:
            format_spec="ymd"
        fm=format_dic[format_spec]
        return fm.format(self)

d1=Data(2020,3,25)
# x="{0}{0}{0}".format(d1)
# x="{0.year}{0.month}{0.day}".format(d1)
# y="{0.year}:{0.month}:{0.day}".format(d1)
# z="{0.year}-{0.month}-{0.day}".format(d1)
#
# print(x)
# print(y)
# print(z)

# format(d1)#d1.__format__()
print(format(d1))
#print(d1.__format__())
print(format(d1,"y:m:d"))
print(format(d1,"m-d-y"))

结果:

开始执行
===> 
2020325
开始执行
===> y:m:d
2020:3:25
开始执行
===> m-d-y
3-25-2020
View Code

八、__slots__

class Foo:
    #__slots__="name"#让所有实例都没有__dict__属性字典
    #可以省内存
    __slots__=["name","age"]

f1=Foo()
f1.name="steven"
print(f1.name)
#print(f1.__dict__)#报错

print(f1.__slots__)#['name', 'age']
print(Foo.__slots__)#['name', 'age']
f1.age=17
print(f1.age)
#f1.gender=4 #报错

f2=Foo()
print(f2.__slots__)#['name', 'age']
f2.name="steven"
f2.age=20
print(f2.name)
print(f2.age)
为何使用__slots__?字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__,当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典
使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
只在那些经常被使用到的用作数据结构的类上定义__slots__,比如在程序中需要创建某个类的几百万个实例对象。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。

九、__doc__

class Foo:
    "我是描述信息"
    pass
class Bar(Foo):
    pass
print(Bar.__doc__) #None,说明该属性无法继承给子类
print(Foo.__doc__) #我是描述信息

十、__module__和__class__

from lib.aa import C

c1=C()
print(c1.name)

print(c1.__module__) #查看实例来自那个模块     lib.aa
print(c1.__class__)     #查看实例是由哪个类产生的  lib.aa.C

十一、__del__

析构方法,当对象在内存中被释放时,自动触发执行

class Foo:
    def __init__(self,name):
        self.name=name
    def __del__(self): #只有在实例被删除时才会被触发
        print("开始执行")
f1=Foo("steven")
# del f1.name
del f1 #注释了语句也会触发__del__执行,因为程序执行完内存也会释放
print("--------")

注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__

十二、__call__

对象后面加括号,触发执行

class Foo:
    def __call__(self,*args,**kwargs):
        print("实例执行")

f1=Foo() #创建实例,也相当于调用对应类下的__call__
f1()     #结果为:"实例执行"   Foo下的__call__

十三、__next__和__iter__实现迭代器协议

例子1

class Foo:
    def __init__(self,n):
        self.n=n
    def __iter__(self): #该方法把对象变成一个可迭代对象
        return self
    def __next__(self):
        if self.n==13:
            raise StopIteration("终止了")

        self.n+=1
        return self.n

f1=Foo(10)

# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__())

for i in f1:#f1.__iter__() == iter(f1)
    print(i)#f1.__next__()

例子2,用迭代器实现斐波那契数列

class Fib:
    def __init__(self):
        self._a=1
        self._b=1
    def __iter__(self):
        return self
    def __next__(self):
        if self._a > 1000:
            raise StopIteration
        self._a,self._b=self._b,self._a+self._b
        return self._a

f1=Fib()

for i in f1:
    print(i)
View Code

十四、描述符(__get__,__set__,__delete__)

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

例子1

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

f1=Foo()
f1.name='egon'
f1.name
del f1.name

例1包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法

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

例子2

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__)#结果为:{},行为被其他方法代理了,而Str()和Int()并没有对数据进行操作
print(People.__dict__)

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

描述符分2种
1、数据描述符:至少实现了__get__()和__set__()
2、非数据描述符:没有实现__set__()

描述符使用

class Foo:
    def __get__(self,instance,owner):#instance实例,owner拥有者就是所属的类
        print("===>get方法")
    def __set__(self,instance,value):
        print("===>set方法",instance,value)
        instance.__dict__["x"]=value#b1.__dict__
    def __delete__(self,instance):
        print("===>del方法")

class Bar:
    x=Foo() #x被Foo代理,对x的任何操作都由Foo处理
    def __init__(self,n):
        self.x=n #b1.x=10
b1=Bar(10) #对x的操作由Foo处理,赋值调用__set__()方法
print(b1.__dict__)
b1.x=11111
# b1.y=222 #没被代理,自己处理
print(b1.__dict__)

描述符优先级

注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()

例子:

class Foo:
    def __get__(self,instance,owner):
        print("===>get方法")
    def __set__(self,instance,value):
        print("===>set方法",instance,value)
        instance.__dict__["x"]=value#b1.__dict__
    def __delete__(self,instance):
        print("===>del方法")

class Bar:
    x=Foo()


#类属性>数据描述符
Bar.x=1
print(Bar.__dict__)
print(Bar.x)

'''结论:描述符在使用时被定义成另外有一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性
有更高的优先级
Bar.x 调用类属性x,找不到就去找描述符伪装的类属性x,触发了__get__()
Bar.x=1 直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__()
'''

#补充
#在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典
print(Bar.__dict__)
类属性>数据描述符
class Foo:
    def __get__(self,instance,owner):
        print("===>get方法")
    def __set__(self,instance,value):
        print("===>set方法",instance,value)
        instance.__dict__["x"]=value#b1.__dict__
    def __delete__(self,instance):
        print("===>del方法")

class Bar:
    x=Foo()

#数据描述符>实例属性
b1=Bar()
b1.x #get
b1.x=1 #set
del b1.x

'''
结论:
如果描述符是数据描述符(既有__get__又有__set__),那么b1.x的调用与赋值都是触发描述符的操作,与b1本身无关了
相当于覆盖了实例的属性
'''
数据描述符>实例属性
class Foo:
    def __get__(self,instance,owner):
        print("===>get方法")

class Bar:
    x=Foo()

b1=Bar()
b1.x=1
print(b1.__dict__)

#结果为:{'x': 1}
实例属性>非数据描述符
class Foo:
    def __get__(self,instance,owner):
        print("===>get方法")

class Bar:
    x=Foo()
    def __getattr__(self,item):
        print("找不到",item)

b1=Bar()
b1.xxxx

#结果为:找不到 xxxx
非数据描述符>找不到

描述符应用

例子1,增加类型限制

class Type:
    def __init__(self,name,expect_type):
        self.key=name
        self.expect_type=expect_type
    def __get__(self,instance,owner):
        print("===>get方法")
        print("instance:",instance)
        print("owner:",owner)
        return instance.__dict__[self.key]
    def __set__(self,instance,value):
        print("===>set方法")
        print("instance:",instance)
        print("value:",value)
        if not isinstance(value,self.expect_type):
            # print("输入的类型不是字符串,错误")
            # return
            raise TypeError("你输入的%s不是%s"%(self.key,self.expect_type))
        instance.__dict__[self.key]=value
    def __delete__(self,instance):
        print("===>del方法")
        print("instance:",instance)
        del instance.__dict__[self.key]


class People:
    name=Type("name",str)
    age=Type("age",int)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=People("steven",20,5550)
print(p1)
p1.name
p1.name="jobs"
print(p1.name)
del p1.name

结果为:

===>set方法
instance: <__main__.People object at 0x000001E7A1580780>
value: steven
===>set方法
instance: <__main__.People object at 0x000001E7A1580780>
value: 20
<__main__.People object at 0x000001E7A1580780>
===>get方法
instance: <__main__.People object at 0x000001E7A1580780>
owner: <class '__main__.People'>
===>set方法
instance: <__main__.People object at 0x000001E7A1580780>
value: jobs
===>get方法
instance: <__main__.People object at 0x000001E7A1580780>
owner: <class '__main__.People'>
jobs
===>del方法
instance: <__main__.People object at 0x000001E7A1580780>
View Code

例子2,类的装饰器

装饰器既能用户函数,也能用于类

#1
def deco(obj):
    print("=======>")
    obj.x=1
    obj.y=2
    return obj
@deco
class Foo: #Foo=deco(Foo)
    pass

print(Foo.__dict__)

#2,验证一切接对象
def test():
    pass
test.x=1
test.y=4
print(test.__dict__)#{'x': 1, 'y': 4}

#3
def Typed(**kwargs):
    def deco(obj):
        print("==+>",kwargs)
        for key,val in kwargs.items():
            setattr(obj,key,val)
        return obj
    print("===>",kwargs)
    return deco

@Typed(x=1,y=2,z=3) #1.Typed(x-1,y=2,z=3)-->deco   2.@deco-->Foo=deco(Foo)
class Foo:
    pass
print(Foo.__dict__)

@Typed(name="steven")
class Bar:
    pass
print(Bar.name)

结果为:

=======>
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'x': 1, 'y': 2}
{'x': 1, 'y': 4}
===> {'x': 1, 'y': 2, 'z': 3}
==+> {'x': 1, 'y': 2, 'z': 3}
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'x': 1, 'y': 2, 'z': 3}
===> {'name': 'steven'}
==+> {'name': 'steven'}
steven
View Code

例子3,装饰器用在描述符的实现

class Type:
    def __init__(self,name,expect_type):
        self.key=name
        self.expect_type=expect_type
    def __get__(self,instance,owner):
        return instance.__dict__[self.key]
    def __set__(self,instance,value):
        if not isinstance(value,self.expect_type):
            raise TypeError("你输入的%s不是%s"%(self.key,self.expect_type))
        instance.__dict__[self.key]=value
    def __delete__(self,instance):
        del instance.__dict__[self.key]

def deco(**kwargs):  #kwargs={"name":str,"age":int}
    def wrapper(obj): #obj=People
        for key,val in kwargs.items():
            setattr(obj,key,Type(key,val))  #People.name=Type("name",str)
        return obj
    return wrapper

@deco(name=str,age=int) #@wrapper  ===>People=wrapper(People)
class People:

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

p1=People("steven",20,5550)
print(People.__dict__)

例子4,利用描述符自定制property

class Lazyproperty:
    def __init__(self,func):
        # print("====>",func)
        self.func=func
    def __get__(self,instance,owner):
        # print(instance)
        # print(owner)
        #类调用代理的属性时,instance为None。实例调用代理的属性时,instance是实例本身
        #处理类调用时instance为None的问题
        if instance is None:
            return self

        res=self.func(instance)
        return res

class Room:

    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length
    #@property #area=property(area)
    @Lazyproperty #area=Lazyproperty(area) #类也可以作为装饰器,加括号表示执行后再赋给@
    def area(self):
        return self.width * self.length

r1=Room("厕所",1,3)
print(r1.area) #3

例子5,自定制property实现延迟计算功能

class Lazyproperty:
    def __init__(self,func):
        # print("====>",func)
        self.func=func
    def __get__(self,instance,owner):
        print(instance)
        print(owner)
        if instance is None:
            return self
        res=self.func(instance)
        setattr(instance,self.func.__name__,res) #添加到实例的属性字典
        return res

class Room:
    def __init__(self,name,width,length):
        self.name=name
        self.width=width
        self.length=length
    #@property #area=property(area)
    @Lazyproperty #area=Lazyproperty(area) #类也可以作为装饰器,加括号表示执行后再赋给@
    def area(self):
        return self.width * self.length

r1=Room("厕所",1,3)
print(r1.area)
print(r1.area) #直接通过实例的属性字典获取。实例属性>非数据描述符
print(r1.area)

property补充:

#写法1
class Foo():
    @property
    def AAA(self):
        print("get的时候运行")
    @AAA.setter
    def AAA(self,val):
        print("set的时候运行")
    @AAA.deleter
    def AAA(self):
        print("del的时候运行")
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
print(f1.AAA)
f1.AAA="hahaha"
del f1.AAA

#写法2
class Foo():

    def get_AAA(self):
        print("get的时候运行")

    def set_AAA(self,val):
        print("set的时候运行",val)

    def del_AAA(self):
        print("del的时候运行")

    AAA=property(get_AAA,set_AAA,del_AAA)
f1=Foo()
print(f1.AAA)
f1.AAA="hahaha"
del f1.AAA

结果:

get的时候运行
None
set的时候运行
del的时候运行
get的时候运行
None
set的时候运行 hahaha
del的时候运行
View Code

十五、__exit__,__enter__

with open("a.txt") as f:
    f.read()

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

例子:

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

    def __enter__(self):  #出现with语句,对象的__enter__被触发,有返回值就赋给as声明的变量
        print("执行enter")
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("执行exit")
        print(exc_type) #显示异常名称,参数,追踪
        print(exc_val)
        print(exc_tb)
        return True

with Foo("a.txt") as f: #实例化对象,触发obj.__enter__(),拿到返回值给f,开始时会执行__enter__
    print(f)
    print(sssss) #有异常情况,从异常位置引发__exit__执行,(__exit__返回的是False时,exit完成执行后就抛出异常,中止。有return true)
                 #时,代表吞掉了异常,__exit__的运行完毕就代表整个with语句执行完毕
    print(f.name) #没有异常的情况下。with里语句块执行完会触发__exit__执行

print("111111111")

好处用途:

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

2、在管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制

十六、元类

python中一切皆对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class时就会

创建一个对象(这里的对象指的是类而非类的实例)

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

元类是用来控制如何创建类的,正如类是创建对象的模板一样

元类的实例为类,正如类的实例为对象

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

一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类

例子1

class Foo:
    def func(self):
        print("form func")

f1=Foo()
print(type(Foo))#<class 'type'>   #type函数可以查看类型,也可以用来查看对象的类

例子2

FFo=type("FFo",(object,),{"x":1})
print(FFo)#<class '__main__.FFo'>
print(FFo.__dict__)
<class '__main__.FFo'>
{'x': 1, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'FFo' objects>, '__weakref__': <attribute '__weakref__' of 'FFo' objects>, '__doc__': None}

例子3(创建类的两种方式,一是class方式,二是用type的方式)

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

FFo=type("FFo",(object,),{"x":1,"__init__":__init__})
print(FFo)#<class '__main__.FFo'>
print(FFo.__dict__)

f1=FFo("steven","age")
print(f1.name)#steven。同用class创建类的方法一样
<class '__main__.FFo'>
{'x': 1, '__init__': <function __init__ at 0x0000014280DC1E18>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'FFo' objects>, '__weakref__': <attribute '__weakref__' of 'FFo' objects>, '__doc__': None}
steven

自定义元类

#1使用默认的type元类
class Foo(metaclass=type):#type("Foo",(object,),{})
    def __init__(self,name):
        self.name=name

f1=Foo("jobs")
#2.自定义的元类
class MyType(type):
    def __init__(self,a,b,c):
        print("元类的构造函数执行")
        # print(a)
        # print(b)
        # print(c)

    def __call__(self,*args,**kwargs):
        print("=======")
        obj=object.__new__(self) #object.__new__(Foo) -->产生f1
        self.__init__(obj,*args,**kwargs) #Foo.__init__(f1.*args,**kwargs)
        return obj
class Foo(metaclass=MyType):#MyType(Foo,"Foo",(),{})---》__init__  表示用MyType实例化Foo
    def __init__(self,name):
        self.name=name

f1=Foo("steven") #f1为None
print(f1)
print(f1.__dict__)

元类的构造函数执行
=======
<__main__.Foo object at 0x000001A5ACF70780>
{'name': 'steven'}



原文地址:https://www.cnblogs.com/steven223-z/p/12801322.html