问几个关于 __getattr__() 的问题,求解答

2017-08-17 09:30:51 +08:00
 xinhangliu

初学 Python,最近在看这个项目 zhihu-py3

基本情况

目标

实现这样子调用:

client = ZhihuClient()
client.author  # 这是一个 Author 对象

实现方法(我的第一反应)

我只能想到的是,在 ZhihuClient 里定义一个 author 方法,用来创建并返回 Author 对象

def author(url, session=self.session):
    author = Author(url, session)
    return author

试了一下是能实现的。但是除了 Author 之外还有好多的类,如果一个一个定义过去那得多麻烦。所以看作者的实现方法

实现方法(作者的)

ZhihuClient 里定义 __getattr__(),实现动态调用。下面是作者的源码

def __getattr__(self, item: str):
    """本函数用于获取各种类,如 `Answer` `Question` 等.

    :支持的形式有:
        1. client.answer()
        2. client.author()
        3. client.collection()
        4. client.column()
        5. client.post()
        6. client.question()
        7. client.topic()

        参数均为对应页面的 url,返回对应的类的实例。
    """
    def getter(url):
        return getattr(module, item.capitalize())(url, session=self._session)
    attr_list = ['answer', 'author', 'collection',
                 'column', 'post', 'question', 'topic']
    if item.lower() in attr_list:
        module = importlib.import_module('.'+item.lower(), 'zhihu')
        return getter

我的疑问

  1. 我的方法有没有啥问题?(除了麻烦以外)
  2. 作者的方法是不是比较常见的方法?如果不是,希望知道解决这类问题最常见的方法
  3. 作者方法里定义的 getter(url) 方法是用来传递参数的。我尝试将它去掉,直接 return getattr(module, item.capitalize())(url, session=self._session),但是这样子就会报错:参数 url 未定义。我总感觉定义一个 getter 有点多余(没有任何讽刺作者的意思),有没有更好的解决办法?(如何在 __getattr__() 里传递参数)
1458 次点击
所在节点    Python
4 条回复
Morriaty
2017-08-17 09:52:29 +08:00
1、没问题,稍微有个小瑕疵
def author(self, url):
author = Author(url, self.session)
return author

2、如果是我自己写的话,我也会写类似的方法
3、该函数返回的是类,而不是实例。
nullcc
2017-08-17 09:56:09 +08:00
当用户试图访问一个根本不存在(或者暂时不存在)的属性时,你可以通过__getattr__魔法方法来定义类的行为
xinhangliu
2017-08-17 09:59:39 +08:00
@Morriaty 感谢纠正
keakon
2017-08-17 10:55:37 +08:00
1. 代码不可复用。
2. 常见,但由于效率较低,所以不到万不得已一般也不用。Ruby 的话倒是经常这么干。除此以外还可以用 descriptor 机制(__get__),代码量会多一些,但是 IDE 可以识别这些属性,避免出现警告。
3. url 是传给 Answer(self, url) 的,这是你要暴露出去的参数,干掉就没法初始化了。你实在不想给 getter 起名,可以 return lambda url: getattr(module, item.capitalize())(url, session=self._session)。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/383567

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX