面向对象进阶

面向对象进阶

一 、上下文协同管理(__enter__和 __exit__)

# class Foo:
#     def __init__(self,name):
#         self.name = name
#     def __enter__(self):
#         print('执行enter',self)
#         return self
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('执行exit')
#         print(exc_type)
#         print(exc_val)
#         print(exc_tb)
#
# with Foo('a.txt') as f:   # 相当于f = obj.__enter__() ##  with时触发enter
#     print('------')
#     print('=====')
# print('000000')    ### 上面的代码块执行完毕时触发exit
## 没有异常时,with 下的代码块运行完毕,自动触发exit,exc_type, exc_val, exc_tb三个参数均为None

# class Foo:
#     def __init__(self,name):
#         self.name = name
#     def __enter__(self):
#         print('执行enter',self)
#         return self
#     def __exit__(self, exc_type, exc_val, exc_tb):
#         print('执行exit')
#         print(exc_type)
#         print(exc_val)
#         print(exc_tb)
#
# with Foo('a.txt') as f:   # 相当于f = obj.__enter__() ##  with时触发enter
#     print('------')
#     print(sdhf)   ## 异常
#     print('=====')
# print('000000')
## 有异常时,到异常那句代码,直接触发、__exit__,此时三个参数为
# exc_type  <class 'NameError'>;
# exc_val name 'sdhf' is not defined
###  exc_tb <traceback object at 0x0000000002203148>

class Foo:
    def __init__(self,name):
        self.name = name
    def __enter__(self):
        print('执行enter',self)
        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:   # 相当于f = obj.__enter__() ##  with时触发enter
    print('------')
    print(sdhf)   ## 异常
    print('=====')
print('000000')
## 有异常,但是exit返回值为True时,会吞掉异常,遇到异常那句代码,执行exit,然后开始执行with外面的代码

# 好处
#1.使用with语句的目的就是把代码放在with中执行,with结束后,自动完成清理工作,无需手动干预
#2.在需要管理一些资源,比如文件,网络连接,和锁的编程环境中,可以在__exit__中定制自动释放资源的机制。

二 、描述符的应用

场景:为下面People类传入的属性加上限制类型

#只为name限定输入类型
# class Typed:
#     def __init__(self,key):
#         self.key =key
#     def __get__(self, instance, owner):
#         print('执行get')
#         # print('instance参数%s'%instance)
#         # print('owner参数%s'%owner)
#         return instance.__dict__[self.key]
#     def __set__(self, instance, value):
#         print('执行set')
#         print('instance参数%s' %instance)
#         print('value参数%s' %value)
#         if not isinstance(value,str):
#             raise TypeError('输入的不是字符串')
#         instance.__dict__[self.key] = value
#     def __delete__(self, instance):
#         print('执行delete')
#         instance.__dict__.pop(self.key)
#
# class People:
#     name = Typed('name')
#     def __init__(self,name,age,salay):
#         self.name = name
#         self.age = age
#         self.salay = salay
# p1 =People('goulonghui',18,1500000.56)
# print(p1.name)
# print(p1.__dict__)    ## {'name': 'goulonghui', 'age': 18, 'salay': 1500000.56}
#
# p1.name = '苟陇辉'
# print(p1.__dict__)  ## {'name': '苟陇辉', 'age': 18, 'salay': 1500000.56}
#
# del p1.name
# print(p1.__dict__)   ## {'age': 18, 'salay': 1500000.56}
#
# p1 = People(1855,18,1555555.56)   ## TypeError: 输入的不是字符串

## 为name,和age 同时限定输入类型
# class Typed:
#     def __init__(self,key):
#         self.key =key
#     def __get__(self, instance, owner):
#         print('执行get')
#         print('instance参数%s'%instance)
#         print('owner参数%s'%owner)
#         return instance.__dict__[self.key]
#     def __set__(self, instance, value):
#         print('执行set')
#         print('instance参数%s' %instance)
#         print('value参数%s' %value)
#         if self.key == 'name':
#             if not isinstance(value,str):
#                 raise TypeError('输入的不是字符串')
#             instance.__dict__[self.key] = value
#         if self.key == 'age':
#             if not isinstance(value,int):
#                 raise TypeError('输入的不是数字')
#             instance.__dict__[self.key] = value
#
#     def __delete__(self, instance):
#         print('执行delete')
#         instance.__dict__.pop(self.key)
#
# class People:
#     name = Typed('name')
#     age = Typed('age')
#     def __init__(self,name,age,salay):
#         self.name = name
#         self.age = age
#         self.salay = salay
# p1 =People('goulonghui',18,1500000.56)
# print(p1.name)
# print(p1.__dict__)    ## {'name': 'goulonghui', 'age': 18, 'salay': 1500000.56}

## 为name,和age 同时限定输入类型
class Typed:
    def __init__(self,key,except_type):
        self.key =key
        self.except_type = except_type
    def __get__(self, instance, owner):
        # print('执行get')
        # print('instance参数%s'%instance)
        # print('owner参数%s'%owner)
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        # print('执行set')
        # print('instance参数%s' %instance)
        # print('value参数%s' %value)
        if not isinstance(value,self.except_type):
            raise TypeError('%s传入的类型不是%s'%(self.key,self.except_type))
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('执行delete')
        instance.__dict__.pop(self.key)

class People:
    name = Typed('name',str)
    age = Typed('age',int)
    def __init__(self,name,age,salay):
        self.name = name
        self.age = age
        self.salay = salay
p1 = People('goulonghui',18,154965896.5)
print(p1.__dict__)   ##{'name': 'goulonghui', 'age': 18, 'salay': 154965896.5}
# p1 = People(56,18,154965896.5)  ### TypeError: name传入的类型不是<class 'str'>
p1 = People('goulonghui','18',154965896.5)  ## TypeError: age传入的类型不是<class 'int'>

三、类的装饰器 

def deco(obj):
#     print('======')
#     obj.x = 1
#     obj.y = 2
#     obj.z = 3
#     return obj
#
# @deco  ##  相当于 Foo = deco(Foo)
# class Foo:
#     pass
#
# print(Foo.__dict__)    ###  'x': 1, 'y': 2, 'z': 3}
类的装饰器初步理解
def typed(**kwargs):
    print(kwargs)
    def deco(obj):
        print(kwargs)
        for key,val in kwargs.items():
            setattr(obj,key,val)
        return obj
    return deco
@typed(x=1,y=2)  ###  拆成@ 和 typed(x=1,y=2)两部分----->deco----->@deco------>Foo = deco(Foo)
class Foo:
    pass
print(Foo.__dict__)    ## 'x': 1, 'y': 2}

@typed(name = 'goulonghui')
class Bar:
    pass
print(Bar.name)   ### goulonghui
带参的类的装饰器
class Typed:
    def __init__(self,key,except_type):
        self.key = key
        self.except_type = except_type
    def __get__(self, instance, owner):
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        # print(instance)
        # print(value)
        if not isinstance(value,self.except_type):
            raise TypeError('%s传入的类型不是%s'%(self.key,self.except_type))
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        instance.__dict__.pop(self.key)
def deco(**kwargs):
    def wapper(obj):
        for key,val in kwargs.items():
            setattr(obj,key,Typed(key,val))
        return obj
    return wapper
@deco(name = str,age = int) ## deco(name = str,age = int)----->@wapper----->obj = wapper(obj)
class People:
    def __init__(self, name, age, salay):
        self.name = name
        self.age = age
        self.salay = salay

print(People.__dict__)

p1 = People('goulognhui',20,566666666)
print(p1.__dict__)
类的装饰器的应用(与描述符搭用)

四、利用描述符自定制property

# class Lazyproperty:
#     def __init__(self,func):
#         self.func = func
#     def __get__(self, instance, owner):
#         print('get')
#         print(instance)
#         print(owner)
#         if instance == None:   ## 此情况为类调用时,直接返回一个对象(area就是Lazyproperty实例化产生的一个对象)
#             return self
#         return self.func(instance)
#
# class Room:
#     #   @Lazyproperty  ##  area = Lazyproperty(area) 相当于area = Lazyproperty()Room的类属性area被Lazyproperty代理了
#     def __init__(self,name,length,width,height):
#         self.name = name
#         self.length = length
#         self.width = width
#         self.height = height
#     @Lazyproperty  ##  area = Lazyproperty(area),实例化Lazyproperty, area是Lazyproperty的一个对象
#     def area(self):
#         return self.length * self.width
#
# r1 = Room('WC',1,1,1)
# # 实例调用
# print(r1.area)
# print(r1.__dict__)
# print(Room.__dict__)   ## 'area': <__main__.Lazyproperty object at 0x00000000027B9B38>,
#
# # 模拟系统property,用类调用area时,返回一个property对象
# # 类调用
# print(Room.area)    ### <__main__.Lazyproperty object at 0x0000000001E89B70>
View Code
class Lazyproperty:
    def __init__(self,func):
        self.func = func
    def __get__(self, instance, owner):
        print('get')
        print(instance)
        print(owner)
        if instance == None:   ## 此情况为类调用时,直接返回一个对象(area就是Lazyproperty实例化产生的一个对象)
            return self
        res = self.func(instance)
        setattr(instance,self.func.__name__,res)    #将计算的结果加在属性字典中,(self.func.__name__是拿到func(即area)函数名)
        return res

class Room:
    #   @Lazyproperty  ##  area = Lazyproperty(area) 相当于area = Lazyproperty()Room的类属性area被Lazyproperty代理了
    def __init__(self,name,length,width,height):
        self.name = name
        self.length = length
        self.width = width
        self.height = height
    @Lazyproperty  ##  area = Lazyproperty(area),实例化Lazyproperty, area是Lazyproperty的一个对象
    def area(self):
        return self.length * self.width

r1 = Room('WC',1,1,1)
print(r1.area) ## 第一次为res的值
print(r1.area)
print(r1.area) ### 后面2次都是在实例属性字典中拿‘area',
加上实现延迟计算的功能

五、property的其他写法

# class Foo:
#     def __init__(self,age):
#         self.age = age
#     @property
#     def name(self):
#         print('get')
#
#     @name.setter
#     def name(self,val):
#         print(self,val)
#     @name.deleter
#     def name(self):
#         print('del')
#
# f1 = Foo(18)
# f1.name           触发get_name
# f1.name = 'goulognhui'        #  触发set_name
# del f1.name    ##触发del_name
class Foo:
    def __init__(self,age):
        self.age = age
    def get_name(self):
        print('get')

    def set_name(self,val):
        print(self,val)

    def del_name(self):
        print('del')
    name = property(get_name,set_name,del_name)   #利用property内置方法做
f1 = Foo(18)
f1.name#   触发get_name
f1.name = 'goulognhui' #  触发set_name
del f1.name  ##触发del_name
View Code

六、元类

# 元类:产生类的类是元类,type
# class Foo:
#     pass
# print(Foo)    ## <class '__main__.Foo'>
#
#
# def __init__():
#     pass
# FFo = type('FFo',(object,),{'x':1,'init':__init__})
# print(FFo)   ## <class '__main__.Foo'>

## ------自定制元类---------
class Mytype(type):
    def __init__(self,a,b,c):
        print('元类在执行')
    def __call__(self, *args, **kwargs):
        obj = object.__new__(self)  ##  产生一个Foo的实例f1
        self.__init__(obj,*args,**kwargs)  ### 给obj(即f1)设值,即调用Foo里的init初始化函数
        return obj
class Foo(metaclass=Mytype): ## 相当于Mytype(self,'Foo',(object,),{})实例化产生Foo类,执行元类的init函数
    def __init__(self,name):  ### 这里的self 为Foo的实例f1
        self.name = name

f1 = Foo('苟陇辉')
print(f1.__dict__)

元类知识详见

posted @ 2018-03-17 00:06  Mr.GLH  阅读(252)  评论(0)    收藏  举报
Top↑