Python的__getattribute__ vs __getattr__的妙用

枫铃3年前 (2021-09-30)Python198

这里的属性即包括属性变量,也包括属性方法。即类的变量和方法。

当访问某个实例属性时, 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对象

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# -*- 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、使用类的继承实现。则不会路由,子类直接继承了父类的属性和方法

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# -*- 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、猜一下结果,理解其妙用

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:778463939
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
# 例子在原来的基础上简化了一下,排除依赖和干扰,详细参见原项目
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

相关文章

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,...

爬虫基本原理

爬虫基本原理 一、爬虫是什么? 百度百科和维基百科对网络爬虫的定义:简单来说爬虫就是抓取目标网站内容的工具,一般是根据定义的行...

Django 函数和方法的区别

函数和方法的区别 1、函数要手动传self,方法不用传 2、如果是一个函数,用类名去调用,如果是一个方法...

Django 知识补漏单例模式

单例模式:(说白了就是)创建一个类的实例。在 Python 中,我们可以用多种方法来实现单例模式&#x...

Django基础知识MTV

Django简介 Django是使用Python编写的一个开源Web框架。可以用它来快速搭建一个高性能的网站。 Django也是一个MVC框架。但是在Dj...

Python mysql 索引原理与慢查询优化

一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。