【问题标题】:Wrapping individual function calls in Python在 Python 中包装单个函数调用
【发布时间】:2017-02-05 05:49:05
【问题描述】:

我正在编写一个脚本,它使用 imaplib 库从 IMAP 服务器请求一些数据。发起连接 (c) 后,我进行了以下调用:

rv, data = c.login(EMAIL_ACCOUNT, EMAIL_PASS)
if rv != 'OK':
    print('login error')
else:
    print(rv, data)

rv, mailboxes = c.list()
if rv != 'OK':
    print('mailbox error')
else:
    print(rv, data)

rv, data = c.select(EMAIL_FOLDER)
if rv != 'OK':
    print('folder error')
else:
    print(rv, data)

我如何重写它以使用某种包装函数来重用检查错误代码和打印数据的逻辑?我假设该函数会将错误消息作为参数以及要执行的命令(selectlogin 等)。如何通过在参数中传递名称来调用选择连接函数?

【问题讨论】:

  • 不清楚你在问什么。是的,您可以编写一个包装函数 (rv, data = handle_error(c.login(...))) 和/或将方法的名称传递给另一个函数。您尝试过什么,有什么问题?
  • def check(rv, data, msg): ... 并用作check(rv, data, 'folder error')?
  • @jonrsharpe 基本上,我想将其简化为一个函数,它将操作(选择、列表、登录)作为参数以及错误消息。我可以将函数调用(例如c.list())作为参数传递给“句柄”函数吗?
  • 可以,只要传递方法本身即可(c.list,注意没有括号);它们是 Python 中的第一类。但是你需要正确处理参数。
  • 你可能想看看 python 装饰器。

标签: python imaplib


【解决方案1】:

要重用任何代码,请查看保持不变的内容(例如,rvdata 按此顺序出现在您的 imaplib 调用中,而 rv=='OK' 意味着事情是好的)并编写一次涉及它们的逻辑。然后查看更改的内容(例如,需要打印的确切错误消息)。参数化更改的内容,如本例中description 参数更改错误消息:

def check(description, rvdata):
    rv, data = rvdata
    if rv == 'OK':
        print(data)
        return data
    else:
        print(description + ' error')
        return None

data = check('login', c.login(EMAIL_ACCOUNT, EMAIL_PASS))
mailboxes = check('mailbox', c.list())
selection = check('folder', c.select(EMAIL_FOLDER))

【讨论】:

    【解决方案2】:

    按照我的理解,您希望为您的任务检查装饰器。

    class Wrapper:
        def __init__(self, error_message):
            self.error_message = error_message
    
        def __call__(self, wrapped):
            def func(*args, **kwargs):
                rv, data = wrapped(*args, **kwargs)
                if rv=="OK":
                    return(rv, data)
                else:
                    print(self.error_message)
                    return(rv, data)
            return func
    
    @Wrapper("Folder Error")
    def select(email_folder):
        return "OK", "OLOLO"
    
    @Wrapper("Folder Error")
    def select_err(email_folder):
        return "FAIL", "OLOLO"
    
    print select("")
    print select_err("")
    

    产量

    ('OK', 'OLOLO')
    Folder Error
    ('FAIL', 'OLOLO')
    

    您可以在 Wrapper 的 __call__ 函数中查看回复,并按照您想要的方式处理它。例如,如果rv 不等于“OK”,您可以返回“False”或引发错误

    但对于您的情况,这可能过于复杂。

    【讨论】:

    • 是的,有点太复杂了。但是感谢您提供替代方法!
    • 我以前从未想过使用对象实例作为装饰器。这是一个很酷的技巧。
    • @jez,一开始我很难理解装饰器,直到最近才意识到如何使用它。我在某处看过这个技巧)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-02
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 2012-09-03
    • 2021-09-14
    • 1970-01-01
    相关资源
    最近更新 更多