python __getattr__ 巧妙应用

在之前的文章有提到__getattr__函数的作用: 如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__)失败, 那么会调用到类的__getattr__函数, 如果没有定义这个函数,那么抛出AttributeError异常。由此可见,__getattr__一定是作用于属性查找的最后一步,兜底。
我们来看几个例子:

第一个例子,比如我业务里有好几个request请求,但是你会发现所有的请求无非都是请求参数不一样,仅此而已,那么通常你需要定义好多个方法,但是方法里的逻辑都几乎一样,那怎么去简化呢,我这里给个例子

from functools import partial


IAM = {
    
    
    "path": "/api/iam/",
    "actions": {
    
    
        "get_auth_info": ("GET", "GetAuthInfo"),
        "policy_check": ("GET", "PolicyCheck"),
        "get_user": ("GET", "GetUser"),
        "create_resource_group": ("POST", "CreateResourceGroup"),
        "list_resource_group": ("GET", "ListResourceGroups"),
        "list_policy_attachments": ("GET", "ListPolicyAttachments"),
        "get_policy": ("GET", "GetPolicy"),
        "create_policy": ("GET", "CreatePolicy"),
        "attach_policy": ("POST", "AttachPolicy"),
        "create_policy_version": ("POST", "CreatePolicyVersion"),
        "set_default_policy_version": ("POST", "CreatePolicyVersion"),
        "list_users": ("GET", "ListUsers"),
        "list_policies": ("GET", "ListPolicies")
    }
}

RMS = {
    
    
    "path": "/api/rms/",
    "actions": {
    
    
        "list_regions": ("GET", "ListRegions")
    }
}

SERVICE_MAP = {
    
    
    "IAM": IAM,
    "RMS": RMS
}


class Client():

    def __init__(self, endpoint, service_name):
        self.service_name = service_name
        service = SERVICE_MAP[self.service_name]
        self.path = service['path']
        self.actions = service['actions']

    def common_method(self, method, action, filters):
    	# 这里写的是通用的方法逻辑,比如调用request请求
        print(method)
        print(action)
        print(filters)

    def __getattr__(self, name):
        method, action = self.actions.get(name, (None, None))
        if method:
            return partial(self.common_method, method, action)


dbfilters = {
    
    'tt1': '111', 'tt2': '222'}
myclient = Client('http://127.0.0.1:8888', 'IAM')
# 这里的方法在Client类中没有定义,其实就是走了 __getattr__ 这个方法,name这个字段就是get_auth_info
myclient.get_auth_info(filters=dbfilters)

运行结果如下:
在这里插入图片描述
可以看到通过这个方法名,对应匹配到了actions中的数据


第二个例子,我觉的是最实用的,__getattr__使得实现adapter wrapper模式非常容易,我们都知道“组合优于继承”,__getattr__实现的adapter就是以组合的形式。

class adaptee(object):
    def foo(self):
        print 'foo in adaptee'
    def bar(self):
        print 'bar in adaptee'

class adapter(object):
    def __init__(self):
        self.adaptee = adaptee()

    def foo(self):
        print 'foo in adapter'
        self.adaptee.foo()

    def __getattr__(self, name):
        return getattr(self.adaptee, name)

if __name__ == '__main__':
    a = adapter()
    a.foo()
    a.bar()

如果adapter需要修改adaptee的行为,那么定义一个同名的属性就行了,其他的想直接“继承”的属性,通通交给__getattr__就行了。

猜你喜欢

转载自blog.csdn.net/weixin_44388689/article/details/119924204
今日推荐