zoukankan      html  css  js  c++  java
  • python的魔术方法(反射)

    一、魔术方法---反射

    •  概述:运行时,区别于编译时,指的是程序被加载到内存中执行的时候
    •  反射,reflection,指的是运行时获取类型信息,一个对象能够在运行时,像照镜子一样,反射出器类型信息
    •  简单说,在python中,能够通过一个对象,找出其type,class,attribute或者method的能力,称为反射或者自省
    •  具有反射能力的函数有:type(),isinstance(),callable(),dir(),getattr()

    1、反射相关的函数和方法

    需求:有一个Point类,查看它实例的属性,并修改它,动态为实例增加属性
        
    class Point:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        def __str__(self):
            return "Point({},{})".format(self.x,self.y)
        def show(self):
            print(self.x,self.y)
    p = Point(4,5)
    
    print(p)
    print(p.__dict__)
    p.__dict__['y'] = 16
    print(p.__dict__)
    p.z = 10
    print(p.__dict__)
    print(dir(p))
    print(p.__dir__())


    2、内建函数

    •   getattr(object,name[,default]): 通过name返回object的属性值,当属性不存在,将使用default返回;如果没有default,则抛出AttributeError,name必须为字符串
    •   setattr(object,name,value): object的属性存在则覆盖,不存在则新增
    •   hasattr(object,name) : 判断对象是否有这个名字的属性,name必须为字符串
    用上面的方法来修改上例的代码
    
    class Point:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        
        def __str__(self):
            return "Point({},{})".format(self.x,self.y)
        
        def show(self):
            print(self)
    
    p1 = Point(4,5)
    p2 = Point(10,10)
    print(repr(p1),repr(p2),sep='
    ')
    print(p1.__dict__)
    setattr(p1,'y',16)
    print(p1.__dict__)
    setattr(p1,'z',10)
    print(p1.__dict__)
    print(1111111111111,getattr(p1,'__dict__'))
    
    
    class Point:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        
        def __str__(self):
            return "Point({},{})".format(self.x,self.y)
        
        def show(self):
            print(self)
    
    p1 = Point(4,5)
    p2 = Point(10,10)
    # print(repr(p1),repr(p2),sep='
    ')
    # print(p1.__dict__)
    # setattr(p1,'y',16)
    # print(p1.__dict__)
    # setattr(p1,'z',10)
    # print(p1.__dict__)
    # print(1111111111111,getattr(p1,'__dict__'))
    
    #动态调用方法
    if hasattr(p1,'show'):
        getattr(p1,'show')()
    
    #为类动态增加方法
    if not hasattr(Point,'add'):
        setattr(Point,'add',lambda self,other: Point(self.x + other.x, self.y + other.y))
    
    print(Point.add)
    print(p1.add)
    print(p1.add(p2))  # 绑定向量相加
    
    #为实例增加方法,未绑定
    if not hasattr(p1,'sub'):
        setattr(p1,'sub',lambda self, other: Point(self.x - other.x, self.y - other.y))
    
    print(p1.sub(p1,p1))
    print('================',p1.sub)
    
    #add在谁里面,sub在谁里面(add是类的方法,sub是实例的方法)
    print(p1.__dict__)  #  
    print(Point.__dict__)
    
    思考:这种动态增加属性的方式是运行时改变类或者实例的方式,但是装饰器或Mixin都是定义时就决定了
          因此反射能力具有更大的灵活性


    二、反射相关的魔术方法

    • __getattr__(), __setattr__(), __delattr__()这三个魔术方法,分别测试

    1、__getattr__()方法举例

    class Base:
        n = 0
    
    class Point(Base):
        z = 6
        def __init__(self,x,y):
            self.x = x
            self.y = y
        def show(self):
            print(self.x,self.y)
        
        def __getattr__(self,item):
            return "missing {}".format(item)
    
    p1 = Point(4,5)
    print(p1.x)
    print(p1.z)
    print(p1.n)
    print(p1.t)
    
    #一个类的属性会按照继承关系找,如果找不到,就会执行__getattr__()方法
    #如果没有这个方法,就会抛出AttributeError异常表示找不到属性
    #instance.dict-->instance.class.dict-->继承的祖先类(直到object)的dict——》调用getattr()
        


    2、__setattr__()方法举例

    class Base:
        n = 0
    
    class Point(Base):
        z = 6
        def __init__(self,x,y):
            print(1111111111111111111)
            self.x = x
            self.y = y
        def show(self):
            print(self.x,self.y)
        
        def __getattr__(self,item):
            print(2222222222222222222)
            return "missing {}".format(item)
        
        def __setattr__(self,key,value):
            print(3333333333333333333)
            print("setattr {}={}".format(key,value))
            self.__dict__[key] = value  #__setattr__()方法,可以拦截对实例属性的增加,修改操作,如果要设置生效,需要自己操作实例的__dict__
    
    p1 = Point(4,5)
    print(p1.x)
    print(p1.z)
    print(p1.n)
    #print(p1.t)
    p1.x = 50
    print(p1.__dict__)
    print(Point.__dict__)
    
    实例通过点设置属性,如果self.x = x,就会调用__setattr__()方法,属性要加到实例的__dict__中,需要自己完成
    __setattr__()方法,可以拦截对实例属性的增加,修改操作,如果要设置生效,需要自己操作实例的__dict__

    3、__delattr__()

    • 可以阻止通过实例删除属性的操作,但是通过类依然可以删除属性
    class Base:
        n = 0
    
    
    class Point(Base):
        z = 6
        def __init__(self,x,y):
            self.x =x
            self.y = y
        
        def __delattr__(self,item):
            print('Can not del {}'.format(item))
    
    p = Point(14,5)
    del p.x
    p.z = 15
    del p.z   # 实例不能删除属性
    del p.z
    
    print(111111111111111,Point.__dict__)
    print(p.__dict__)
    del Point.z           #类可以删除属性
    print(Point.__dict__)
    
    
    __getattribute__ : 实例所有的属性调用都从这个方法开始
    方法中为了避免在该方法中无限的递归,它的实现应该永远调用基类的同名方法


    4、属性查找顺序

    • 实例调用__getattribute__()——> instance.__dict__--> instance.__class__.__dict__-->继承的祖先类的dict-->都没找到最后调用__getattr__()
  • 相关阅读:
    数据库分库分表之后,你是如何解决事务问题?
    数据库周刊31丨openGauss 正式开源;7月数据库排行榜发布;浙江移动国产数据库AntDB迁移;oracle ADG跨版本搭建;PG解决社保问题;mysqlbinlog解析……
    2020年7月国产数据库排行:华为、腾讯发新品,中兴、阿里结硕果
    47%的MongoDB数据库遭黑客比特币勒索,你中招了吗?中招怎么办?
    数据库周刊30丨数据安全法草案将亮相;2020数据库产业报告;云南电网上线达梦;达梦7误删Redo Log;Oracle存储过程性能瓶颈;易鲸捷实践案例……
    数据库周刊29│2020数据库研究报告;Oracle取消今年技术大会;腾讯云DBbridge发布支持一键迁库;饿了么迁至阿里云;PG数组查询;Oracle被比特币勒索;DM8 安全管理…
    数据库周刊28│开发者最喜爱的数据库是什么?阿里云脱口秀聊程序员转型;MySQL update误操作;PG流复制踩坑;PG异机归档;MySQL架构选型;Oracle技能表;Oracle文件损坏处理……
    怎么查看HBase表的创建时间
    Hadoop/HBase Kerberos认证失败:Clock skew too great
    java线程莫名异常退出时,如何捕获异常信息
  • 原文地址:https://www.cnblogs.com/jiangzuofenghua/p/11448790.html
Copyright © 2011-2022 走看看