何时使用__getattr__方法

3
我发现内置函数__getattr__,并想知道它何时会被使用。从文档http://docs.python.org/reference/datamodel.html#中,我很难想到一个实际的用途。你能给一个实际的例子来说明它在代码中如何使用和有用吗?
4个回答

9
一个例子是使用字典的对象表示法。例如,考虑一个字典:
myDict = {'value': 1}

通常在Python中,我们可以通过以下方式访问'value'变量:

'value'

myDict['value']

这将在Python解释器中打印1。然而,有些人可能希望使用myDict.value记法。可以通过使用以下类来实现:

class DictAsMember(dict):
    def __getattr__(self, name):
        value = self[name]
        if isinstance(value, dict):
            value = DictAsMember(value)
        return value

my_dict = DictAsMember()
my_dict['property'] = {'sub_property': 1}

print(my_dict.property.sub_property) # 1 will be printed

1
这句话应该是value = self[name]吗? - Casey Kuball
@Darthfett 没错,谢谢你发现了这个问题 - 我已经纠正了示例代码。 - Chris

3

3

__getattr__方法仅在找不到属性时才会被调用,它可以是定义查找属性的备选位置或提供默认值的有用方式,类似于defaultdict

您还可以通过将所有查找委托给另一个对象来模拟对象MRO中高于所有其他对象的基类(尽管这样做可能会导致无限循环,如果另一个对象将属性委托回来)。

还有__getattribute__方法,它与__getattr__相关,因为它在任何时候查找对象上的任何属性时都会被调用。


2

编辑:这是关于内置函数getattr的,而不是__getattr__方法。

我需要为使用令牌的REST客户端做这个操作。我将Requests的Session对象包装成自己的接口,这样我就可以始终发送身份验证标头,并且(更相关的是)只需使用URL的路径即可向同一站点发出HTTP请求。

class RequestsWrapper():
    def __init__(self, base_url):
        self.client = requests.Session(
            headers={'Authorization':'myauthtoken'}
        )
        self.base_url = base_url

    def _make_path_request(self, http_method, path, **kwargs):
        """
        Use the http_method string to find the requests.Session instance's
        method.
        """
        method_to_call = getattr(self.client, http_method.lower())
        return method_to_call(self.base_url + path, **kwargs)

    def path_get(self, path, **kwargs):
        """ 
        Sends a GET request to base_url + path.
        """
        return self._make_path_request('get', path, **kwargs)

    def path_post(self, path, **kwargs):
        """ 
        Sends a POST request to base_url + path.
        """
        return self._make_path_request('post', path, **kwargs)

    def path_put(self, path, **kwargs):
        """ 
        Sends a PUT request to base_url + path.
        """
        return self._make_path_request('put', path, **kwargs)

    def path_delete(self, path, **kwargs):
        """ 
        Sends a DELETE request to base_url + path.
        """
        return self._make_path_request('delete', path, **kwargs)

然后,我只需根据路径发起请求:
# Initialize
myclient = RequestsWrapper("http://www.example.com")
# Make a get request to http://www.example.com/api/spam/eggs
response = myclient.path_get("/api/spam/eggs")
# Print the response JSON data
if response.ok:
    print response.json

我认为这个答案回答了相反的问题:为什么有人会使用 getattr() 内建函数。我理解问题是关于为什么一个类会提供 __getattr__() 魔术方法。 - Brandon Rhodes
@BrandonRhodes 哈哈,你说得太对了。还有,这段代码太糟糕了,是时候进行“尸体编辑”了。 - Colin Dunklau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接