python 面向对象2

面向对象的迭代器协议

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:        #obj=iter(f1) ------> f1.__iter__()   for循环会自动捕捉到终止条件
    print(i)        #obj.__next__()
1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发

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

3 描述符分两种
一 数据描述符:至少实现了__get__()和__set__()
二 非数据描述符:没有实现__set__()

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

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

    def __delete__(self, instance):
        print("__delete__")

class Bar:
    x = Foo()  #描述了x属性
    def __init__(self,n):
        self.x = n

#触发描述符
b1 = Bar(10)      #触发描述符的set方法
print(b1.__dict__)  #空字典

print(Bar.__dict__)

b1.x   #触发描述符的get方法

del b1.x #触发描述符的delete方法

描述符的应用

#描述符
class Type:
    def __get__(self, instance, owner):      #instance是被描述的类的实例,就是p1
        print("__get__方法")
        print("instance参数[ %s ]"%instance)
        print("owner参数[ %s ]" % owner)

    def __set__(self, instance, value):
        print("__set__方法")
        print("instance参数[ %s ]" % instance)
        print("value参数[ %s ]" % value)

    def __delete__(self, instance):
        print("__delete__方法")
        print("instance参数[ %s ]" % instance)


class People:
    name = Type()   #描述了name 属性
    def __init__(self,name,age):
        self.name = name
        self.age = age

p1 = People("tom",18)  #执行描述符的set方法

print("---->>>>>",p1)

p1.name   #执行描述符的get方法

p1.name = "liaoboshi"   #执行描述符的set方法

print(p1.__dict__)    #没有name这个属性,因为描述符的方法没有返回值

 描述符的应用

#描述符
class Type:
    def __init__(self,key,expected_type):
        self.key = key
        self.expected_type = expected_type

    def __get__(self, instance, owner):      #instance是被描述的类的实例,就是p1
        print("__get__方法")
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print("__set__方法")
        if not isinstance(value,self.expected_type):   #检测传进来的类型
            raise TypeError(" %s 你传入的类型不是 %s"%(self.key,self.expected_type))
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print("__delete__方法")
        instance.__dict__.pop(self.key)


class People:
    name = Type("name",str)   #描述了name 属性(描述符要传2个参数)
    age = Type("age",int)     #描述了age 属性(描述符要传2个参数)
    def __init__(self,name,age):
        self.name = name
        self.age = age

p1 = People("tom",18)
# p2 = People(213,18) #报错,name传入的类型必须是字符串型

类的装饰器

def deco(obj):
    print("========>",obj)    #obj就是Foo类本身

    obj.x = 1111111
    obj.y = 2222222
    return obj

@deco    # Foo=deco(Foo)
class Foo:
    pass

print(Foo.__dict__)   #属性字典里有x 和 y 属性

 类的装饰器

def Typed(**kwargs):
    def deco(obj):
        for key,val in kwargs.items():
            setattr(obj,key,val)

        return obj

    return deco

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

print(Foo.__dict__)


@Typed(name="tom")  #@Typed(name="tom") --->@deco  ---> Foo=deco(Foo)
class Bar:
    print()

print(Bar.name)

类的装饰器的应用

#描述符
class Type:
    def __init__(self,key,expected_type):
        self.key = key
        self.expected_type = expected_type

    def __get__(self, instance, owner):      #instance是被描述的类的实例,就是p1
        print("__get__方法")
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print("__set__方法")
        if not isinstance(value,self.expected_type):   #检测传进来的类型
            raise TypeError(" %s 你传入的类型不是 %s"%(self.key,self.expected_type))
        instance.__dict__[self.key] = value

    def __delete__(self, instance):
        print("__delete__方法")
        instance.__dict__.pop(self.key)


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

        return obj

    return wrapper

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

p1 = People("tom",18)
利用描述符自定制property
class Lazyproperty:
    def __init__(self,funy):  #funy ==>area
        print("=====>",funy)
        self.funy = funy

    def __get__(self, instance, owner):
        if instance is None:
            return self
        res = self.funy(instance)
        return res

class Room:
    def __init__(self,name,width,length):
        self.name = name
        self.width = width
        self.length = length

    # @property
    @Lazyproperty     # area= Lazyproperty(area)
    def area(self):
        return self.width * self.length

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





class Lazyproperty:
    def __init__(self,funy):  #funy ==>area
        print("=====>",funy)
        self.funy = funy

    def __get__(self, instance, owner):
        if instance is None:
            return self
        res = self.funy(instance)

        setattr(instance,self.funy.__name__,res)   #把返回值加到属性字典里

        return res

class Room:
    def __init__(self,name,width,length):
        self.name = name
        self.width = width
        self.length = length

    # @property
    @Lazyproperty     # area= Lazyproperty(area)
    def area(self):
        return self.width * self.length

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

 上下文管理协议

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

    def __enter__(self):
        print("执行了__enter__")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("执行了__exit__")


with Open("a.txt") as f:      #执行这一行的时候,会自动调用__enter__方法
    print(f)         # f 就是Open类产生的对象
    print(f.name)     #with as 里面的代码执行完的时候,会自动调用__exit__方法

print("------------------>>>>>>>>")




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

    def __enter__(self):
        print("执行了__enter__")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("执行了__exit__")
        print(exc_type)     #没有异常输出None,有就输出异常的类型
        print(exc_val)    #没有异常输出None,有就输出异常的值
        print(exc_tb)     #没有异常输出None,有就输出traceback
        return True      #返回True,吞掉异常

with Open("a.txt") as f:      #执行这一行的时候,会自动调用__enter__方法
    print(f)          # f 就是Open类产生的对象
    print(dsafsfsf)  #异常的情况下,会执行__exit__,如果返回True,会吞掉异常,执行with as 外面的代码,
                     # 如果返回不是Ture,吐出异常,不会执行with as 外面的代码,报错
    print(f.name)     #with as 里面的代码执行完的时候,会自动调用__exit__方法

print("------------------>>>>>>>>")

metaclass

1 class Foo:
2     pass
3 
4 f1=Foo() #f1是通过Foo类实例化的对象

python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例)

上例可以看出f1是由Foo这个类产生的对象,而Foo本身也是对象,那它又是由哪个类产生的呢?

1 #type函数可以查看类型,也可以用来查看对象的类,二者是一样的
2 print(type(f1)) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
3 print(type(Foo)) # 输出:<type 'type'> 

2 什么是元类?

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

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

元类的实例为类,正如类的实例为对象(f1对象是Foo类的一个实例Foo类是 type 类的一个实例)

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

3 创建类的两种方式

方式一:

1 class Foo:
2     def func(self):
3         print('from func')

 方式二:

1 def func(self):
2         print('from func')
3 x=1
4 Foo=type('Foo',(object,),{'func':func,'x':1})

 4 一个类没有声明自己的元类,默认他的元类就是type,除了使用元类type,用户也可以通过继承type来自定义元类(顺便我们也可以瞅一瞅元类如何控制类的创建,工作流程是什么)

class Mytype(type):
    def __init__(self,what,bases=None,dict=None):
        print(what,bases,dict)

    def __call__(self, *args, **kwargs):
        print('--->')
        obj=object.__new__(self)
        self.__init__(obj,*args,**kwargs)
        return obj
class Room(metaclass=Mytype):
    def __init__(self,name):
        self.name=name

r1=Room('alex')
print(r1.__dict__)

自定制元类精简版
 
 
原文地址:https://www.cnblogs.com/liaoboshi/p/6223357.html