2011-02-24 65 views
1

httplib.HTTPMessageemail.message.Message类[1]实现了RFC822标头解析的方法。不幸的是,他们有不同的实现[2],他们不提供相同级别的功能。被窃听我如何用另一个类的方法来装饰(monkeypatch ...)一个Python类?

一个例子是:

  • httplib.HTTPMessage缺少get_filename方法存在于email.Message,即让您轻松检索来自Content-disposition: attachment; filename="fghi.xyz"头的文件名;

  • httplib.HTTPMessage具有getparamgetplistparseplist方法,但AFAIK,它们不和不能在content-type报头解析外部使用;

  • email.Message有一个通用的get_param方法来解析与参数,如content-dispositioncontent-type任何RFC822报头。

因此,我想的email.message.Messageget_filenameget_param方法httplib.HTTPMessage但是,当然,我不能修补httplib.HTTPMessage,因为它是在标准库...:-q

最后,来这里的装饰主题... :-)

我成功地创建了一个monkeypatch_http_message功能来装饰我缺少分析方法的httplib.HTTPMessage

def monkeypatch_http_message(obj): 
    from email import utils 
    from email.message import (
     _parseparam, 
     _unquotevalue, 
    ) 
    cls = obj.__class__ 

    # methods **copied** from email.message.Message source code 
    def _get_params_preserve(self, failobj, header): ... 
    def get_params(self, failobj=None, header='content-type', 
        unquote=True): ... 
    def get_param(self, param, failobj=None, header='content-type', 
        unquote=True): ... 
    def get_filename(self, failobj=None): ... 

    # monkeypatching httplib.Message 
    cls._get_params_preserve = _get_params_preserve 
    cls.get_params = get_params 
    cls.get_param = get_param 
    cls.get_filename = get_filename 

现在我可以这样做:

import mechanize 
from some.module import monkeypatch_http_message 
browser = mechanize.Browser() 

# in that form, browser.retrieve returns a temporary filename 
# and an httplib.HTTPMessage instance 
(tmp_filename, headers) = browser.retrieve(someurl) 

# monkeypatch the httplib.HTTPMessage instance 
monkeypatch_http_message(headers) 

# yeah... my original filename, finally 
filename = headers.get_filename() 

这里的问题是,我从字面上源类,我想避免复制装饰方法的代码。

所以,我想通过引用源装饰方法:

def monkeypatch_http_message(obj): 
    from email import utils 
    from email.message import (
     _parseparam, 
     _unquotevalue, 
     Message # XXX added 
    ) 
    cls = obj.__class__ 

    # monkeypatching httplib.Message 
    cls._get_params_preserve = Message._get_params_preserve 
    cls.get_params = Message.get_params 
    cls.get_param = Message.get_param 
    cls.get_filename = Message.get_filename 

但是,这给了我:

Traceback (most recent call last): 
    File "client.py", line 224, in <module> 
    filename = headers.get_filename() 
TypeError: unbound method get_filename() must be called with Message instance as first argument (got nothing instead) 

现在我抓我的头......我怎么能装点我的课没有从字面上复制源方法?

有什么建议吗? :-)

问候,

乔治·马丁


  1. 在Python 2.6。我不能在生产中使用2.7或3.x。

  2. httplib.HTTPMessage继承自mimetools.Messagerfc822.Messageemail.Message有它自己的实现。

回答

2

在Python 3.x中,非绑定方法消失,因此你只得到在这种情况下该文件的对象和你的第二个示例将工作:

>>> class C(): 
... def demo(): pass 
... 
>>> C.demo 
<function demo at 0x1fed6d8> 

在Python 2.x中,你

>>> class C(): 
... def demo(): pass 
... 
>>> C.demo.im_func     # Retrieve it from the unbound method 
<function demo at 0x7f463486d5f0> 
>>> C.__dict__["demo"]    # Retrieve it directly from the class dict 
<function demo at 0x7f463486d5f0> 

后一种方法:可以通过与未结合的方法或通过直接从类字典中检索它(从而绕过该把它变成一个未绑定方法的正常查找过程)访问底层功能具有与Python 3.x向前兼容的优点。

+0

Waaaaaay干净多了:-) 高清monkeypatch_http_message(OBJ): 进口httplib的 断言isinstance(OBJ,httplib.HTTPMessage) CLS =的obj .__ class__ 从电子邮件进口utils的 从email.message进口(_parseparam,_unquotevalue,消息) funcnames =( '_get_params_preserve', 'get_params', 'get_param', 'get_filename') 为funcname的在funcnames: CLS .__字典__ [funcname的] =消息.__字典__ [funcname的] 谢谢! :-) – 2011-02-25 09:01:53

1

@ncoghlan:我不能把缩进代码中的注释,所以这里要再次重申:

def monkeypatch_http_message(obj): 
    import httplib 
    assert isinstance(obj, httplib.HTTPMessage) 
    cls = obj.__class__ 

    from email import utils 
    from email.message import (_parseparam, _unquotevalue, Message) 
    funcnames = ('_get_params_preserve', 'get_params', 'get_param', 'get_filename') 
    for funcname in funcnames: 
     cls.__dict__[funcname] = Message.__dict__[funcname] 

谢谢! :-)

+0

我得到的错误:“TypeError:'dictproxy'对象不支持项目分配”当我尝试这个(@classmethod,顺便说一句)。这种技术不适用于派生自“对象”(新风格的类)的对象。 – mckoss 2011-09-27 14:03:49

相关问题