如何用另一个类的方法装饰(monkeypatch…)一个Python类?
如何用另一个类的方法装饰(monkeypatch…)一个Python类?,python,class,decorator,monkeypatching,rfc822,Python,Class,Decorator,Monkeypatching,Rfc822,httplib.HTTPMessage和email.message.messageclasses[1]都实现了RFC822头解析的方法。不幸的是,它们有不同的实现[2],并且它们不提供相同级别的功能 困扰我的一个例子是: httplib.HTTPMessage缺少email.Message中的get_filename方法,该方法允许您从内容配置:附件中轻松检索文件名;filename=“fghi.xyz”标题 httplib.HTTPMessage具有getparam、getplist和par
httplib.HTTPMessage
和email.message.message
classes[1]都实现了RFC822头解析的方法。不幸的是,它们有不同的实现[2],并且它们不提供相同级别的功能
困扰我的一个例子是:
缺少httplib.HTTPMessage
中的email.Message
方法,该方法允许您从get_filename
标题内容配置:附件中轻松检索文件名;filename=“fghi.xyz”
具有httplib.HTTPMessage
、getparam
和getplist
方法,但在parseplist
头解析之外不能使用它们内容类型
有一个通用的email.Message
方法来解析任何带有参数的RFC822头,如get_param
或内容配置
内容类型
httplib.HTTPMessage
中的get_filename
或get_param
方法email.message.message
,但是,当然,我不能修补httplib.HTTPMessage
,因为它在标准库中-q
最后,这里是装饰主题…:-)
我成功地创建了一个monkeypatch\u http\u 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)
回溯(最近一次呼叫最后一次):
文件“client.py”,第224行,在
filename=headers.get_filename()
TypeError:必须使用Message instance作为第一个参数调用未绑定的方法get_filename()(而不是获取任何内容)
我现在在挠头。。。如何在不复制源方法的情况下装饰类
有什么建议吗?:-)
问候,
乔治·马丁
httplib.HTTPMessage
继承自mimetools.Message
和rfc822.Message
,而email.Message
有自己的实现在Python3.x中,未绑定的方法消失了,因此在本例中,您只需要获取文件对象,第二个示例就可以了:
>>> class C():
... def demo(): pass
...
>>> C.demo
<function demo at 0x1fed6d8>
>>C类()
... def demo():通过
...
>>>C.演示
在Python2.x中,您可以通过unbound方法访问底层函数,也可以直接从类字典中检索底层函数(从而绕过将其转换为unbound方法的正常查找过程):
>>C类()
... def demo():通过
...
>>>C.demo.im#func#从unbound方法中检索它
>>>C.uu dict_uu[“demo”]#直接从类dict中检索它
后一种方法的优点是与Python 3.x向前兼容。@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]
谢谢!:-) Waaaaaay更干净:-)def monkeypatch_http_message(obj):import-httplib assert-isinstance(obj,httplib.HTTPMessage)cls=obj.\uu class_uuuuuuuuuuuu来自电子邮件导入utils来自email.message导入(\u parseparam,\u unquotevalue,message)funcnames=在funcnames:cls中为funcname指定(“\u get\u params\u preserve”、“get\u params”、“get\u param”、“get\u filename”)。\u dict\uuuuuuuu[funcname]=Message.\uu dict\uuuuuuuuuu[funcname]谢谢:-)我尝试此操作时(在@classmethod上,顺便说一句)收到错误:“TypeError:'dictproxy'对象不支持项分配”。此技术不适用于从“对象”(新样式类)派生的对象。
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]