zoukankan      html  css  js  c++  java
  • Day 23:python 面向对象 【装饰器,property应用,元类】

    类的装饰器

    的基本原理和 函数的装饰器原理基本一致

    例:

    def test(obj):
        print("====>>",obj)#obj就是Foo.那我们可以对这个类进行操作
        obj.x= 3
        obj.y =4
        return obj
    @test # Foo = test(Foo)
    class Foo:
        pass
    print(Foo.__dict__)#属性字典里面就有我们设置的值
    类的装饰器原理

    上面说的是直接赋值,装装饰器写死了。但是如果这个装饰器用运用于多个类呢?参数不确定呢?

    def test(**kwargs):
      #kwargs 就是test传进来的字典
        def deco(obj): #obj就是Foo.那我们可以对这个类进行操作
            for key,val in kwargs.items():
            #循环这个字典,得到key,val
                setattr(obj,key,val)
                #设置值到foo
            return obj 
        return deco
    @test(name = "sjc",age = "28")#加括号就是运行了
    #@test --->把字典传进去,并执行,变成@deco ,Foo = deco(Foo)
    class Foo:
        pass
    print(Foo.__dict__)
    进阶

    类的装饰器的应用

    class Typed:
        def __init__(self,key,e_type):
            self.key = key
            self.e_type = e_type
        def __get__(self, instance, owner):
            return instance.__dict__[self.key]
        def __set__(self, instance,value,):
            if not isinstance(value,self.e_type):
                raise TypeError("你传入的%s不是%s" %(value,self.e_type))
            instance.__dict__[self.key] = value
    def test(**kwargs):
        def deco(obj):
            for key,val in kwargs.items():
                setattr(obj,key,Typed(key,val))
                # setattr(Salary,name,Teped(name,str))
                #Type(key,val) 就是在调用描述符了。和下面对应
            return obj
        return deco
    @test(name = str,age = int,salarty = float)
    #如果Salary的参数过多,为了减少重复代码。
    #取代name = Typed("name",str)
    class Salary:
        # name = Typed("name",str)
        # age = Typed("age",int)
        # salarty = Typed("salarty",float)
        def __init__(self,name,age,salary):
            self.name = name
            self.age = age
            self.salarty = salary
    s1 = Salary("sunjinchao",12,2.3,)
    print(s1.__dict__)
    装饰器应用与描述符结合,检测输入类型

    装饰器,也可以是个类! 

    class lproperty:
        def __init__(self,func):
            self.func=func#func就是[gongzi]
        def __get__(self, instance, owner):
            return self.func(instance)
            #instance实例本身 S1
        def __set__(self, instance, value):
            pass
    class Salary:
        # gongzi = lproperty(gongzi)
        def __init__(self,name,salary,kpi):
            self.name = name
            self.salarty = salary
            self.kpi = kpi
        @property#隐藏方法,然后调用的时候好像在调用数据属性。
        #gongzi = property(gongzi) // 就是增加描述符的操作
        #
        #property(gongzi) 实例化的过程 --》实例化就会触发init方法
        def gongzi(self):
            return self.salarty +self.kpi
    s1 = Salary("sunjinchao",500,800)
    print(s1.gongzi)#1300
    #r1.gongzi.func(r1)
    利用描述符模拟property

    用自定制的property 实现 延迟计算功能(计算一次,存在缓存中下次直接使用,不用在触发函数运行)

    class lproperty:
        def __init__(self,func):
            self.func=func#func就是[gongzi]
        def __get__(self, instance, owner):
            ret = self.func(instance)
            setattr(instance,self.func.__name__,ret)
            #直接把值设置在 r1实例的属性字典。
            #下次调用直接从字典里面找
            return ret
            #instance实例本身 S1
    class Salary:
        # gongzi = lproperty(gongzi)
        def __init__(self,name,salary,kpi):
            self.name = name
            self.salarty = salary
            self.kpi = kpi
        @property#隐藏方法,然后调用的时候好像在调用数据属性。
        #gongzi = property(gongzi) // 就是增加描述符的操作
        #
        #property(gongzi) 实例化的过程 --》实例化就会触发init方法
        def gongzi(self):
            return self.salarty +self.kpi
    s1 = Salary("sunjinchao",500,800)
    print(s1.gongzi)#1300
    #r1.gongzi.func(r1)
    延迟计算

    那如果给gongzi 这个函数属性设置值呢?

    class Goods:
        def __init__(self):
            # 原价
            self.original_price = 100
            # 折扣
            self.discount = 0.8
        @property
        def price(self):
            # 实际价格 = 原价 * 折扣
            new_price = self.original_price * self.discount
            return new_price
        @price.setter
        def price(self, value):
            self.original_price = value
        @price.deleter
        def price(self):
            del self.original_price
    obj = Goods()
    obj.price         # 获取商品价格
    obj.price = 200   # 修改商品原价
    print(obj.price)
    del obj.price     # 删除商品原价
    property 的函数属性设置值

    元类 :metaclass

    元类:元类就是类的类,是类的末班

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

    元类的实例 就是类,正如类的实例是一个对象,(f1,是foo的对象,那foo类是type的一个实例)

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

    class foo:
        def __init__(self):
            pass
    f1 = foo()
    # print(type(f1))#<class '__main__.foo'>
    # print(type(foo))#<class 'type'>
    print(foo.__dict__)
    
    def __init__(self,name):
        self.name = name
    FFo = type('FFo',(object,),{'x':1,__init__:__init__})
    #object新式类,有逗号,可以继承多个类
    #设置数据属性,与 init方法
    print(FFo.__dict__)
    初识元类

     

    人生苦短,我用Python
  • 相关阅读:
    阿里云服务器ECS centos_7 安装jdk环境
    Spring Data Jpa 投影(Projection)的用法
    win10 docker 部署微服务
    centos 安装docker
    VMware 启动 虚拟机后一直黑屏
    VMware 新建虚拟机选择操作系统的时候提示,此主机不支持64位客户机操作系统,此系统无法运行
    mysql 表名全变小写的解决(windows)
    docker: Error response from daemon: driver failed programming external connectivity on endpoint jovial_morse (71d0315110605c3812f7255c7072f5d38512118a4635feaf84cdc170d3bee8d1): Error starting userland
    win10 docker部署springboot项目
    nginx failed (1113: No mapping for the Unicode character exists in the target multi-byte code page)
  • 原文地址:https://www.cnblogs.com/sunjinchao/p/11135234.html
Copyright © 2011-2022 走看看