zoukankan      html  css  js  c++  java
  • Python的__getattribute__ vs __getattr__的妙用

      这里的属性即包括属性变量,也包括属性方法。即类的变量和方法。
      当访问某个实例属性时, getattribute会被无条件调用,如未实现自己的getattr方法,会抛出AttributeError提示找不到这个属性,如果自定义了自己getattr方法的话,方法会在这种找不到属性的情况下被调用,比如上面的例子中的情况。所以在找不到属性的情况下通过实现自定义的getattr方法来实现一些功能是一个不错的方式,因为它不会像getattribute方法每次都会调用可能会影响一些正常情况下的属性访问
     
      使用这几个方法可以实现拦截器啥、动态代理、统一log等功能。
     
      举例:
      1、使用__getattribute__实现统一的打印日志功能。使用__getattribute__方法拦截了属性和方法的访问。__getattribute__只有在新式类中才能使用。
      
    # -*- coding: utf-8 -*-
    class Fjs(object):
        def __init__(self, name):
            self.name = name
     
        def hello(self):
            print "said by : ", self.name
     
        def __getattribute__(self, item):
            print "访问了特性:" + item
            return object.__getattribute__(self, item)
     
     
    fjs = Fjs("fjs")
    print fjs.name
    fjs.hello()

    输出:

    访问了特性:name
    fjs
    访问了特性:hello
    said by :  访问了特性:name
    fjs

      2、这里通过__getattr__方法,将所有的特性的访问都路由给了内部的fjs对象

    # -*- coding: utf-8 -*-
    class Fjs(object):
        def __init__(self, name):
            self.name = name
     
        def hello(self):
            print "said by : ", self.name
     
        def fjs(self, name):
            if name == self.name:
                print "yes"
            else:
                print "no"
     
    class Wrap_Fjs(object):
        def __init__(self, fjs):
            self._fjs = fjs
     
        def __getattr__(self, item):
            if item == "hello":
                print "调用hello方法了"
            elif item == "fjs":
                print "调用fjs方法了"
            return getattr(self._fjs, item)
     
    fjs = Wrap_Fjs(Fjs("fjs"))
    fjs.hello()
    fjs.fjs("fjs")

    输出:

    调用hello方法了
    said by :  fjs
    调用fjs方法了
    yes

      3、使用类的继承实现。则不会路由,子类直接继承了父类的属性和方法

    # -*- coding: utf-8 -*-
    class Fjs(object):
        def __init__(self, name):
            self.name = name
     
        def hello(self):
            print "said by : ", self.name
     
        def fjs(self, name):
            if name == self.name:
                print "yes"
            else:
                print "no"
     
    class Wrap_Fjs(Fjs):
        def __init__(self, fjs):
            self._fjs = fjs
     
        def __getattr__(self, item):
            if item == "hello":
                print "调用hello方法了"
            elif item == "fjs":
                print "调用fjs方法了"
            return getattr(self._fjs, item)
     
    fjs = Wrap_Fjs(Fjs("fjs"))
    fjs.hello()
    fjs.fjs("fjs")

    输出:

    said by :  fjs
    yes

      4、猜一下结果,理解其妙用

    # 例子在原来的基础上简化了一下,排除依赖和干扰,详细参见原项目
    class UrlGenerator(object):
        def __init__(self, root_url):
            self.url = root_url
    
        def __getattr__(self, item):
            if item == 'get' or item == 'post':
                print self.url
            return UrlGenerator('{}/{}'.format(self.url, item))
    
    
    url_gen = UrlGenerator('http://xxxx')
    url_gen.users.show.get

      5、通过转换,可以像访问属性一样访问dict中的键值对

    class ObjectDict(dict):
        def __init__(self, *args, **kwargs):
            super(ObjectDict, self).__init__(*args, **kwargs)
    
        def __getattr__(self, name):
            value =  self[name]
            if isinstance(value, dict):
                value = ObjectDict(value)
            return value
    
    if __name__ == '__main__':
        od = ObjectDict(asf={'a': 1}, d=True)
        print od.asf, od.asf.a     # {'a': 1} 1
        print od.d                 # True
     
    参考:
    1、https://www.jianshu.com/p/885d59db57fc
    2、https://www.cnblogs.com/xybaby/p/6280313.html
  • 相关阅读:
    Java Json 数据下划线与驼峰格式进行相互转换
    Java反射常用示例
    ApplicationContextAware 快速获取bean
    Spring AOP自动代理创建者
    Spring依赖检查
    Bean作用域实例
    注入值到Spring bean属性
    用javaConfig 代替 xml 配置
    spring使用@Autowired装载
    Spring 概述
  • 原文地址:https://www.cnblogs.com/shengulong/p/10054885.html
Copyright © 2011-2022 走看看