1

httplib.HTTPMessageおよびemail.message.Messageclasses[1]は、RFC822ヘッダー解析のメソッドを実装します。残念ながら、それらには異なる実装があり[2]、同じレベルの機能を提供していません。

私を悩ませている1つの例はそれです:

  • httplib.HTTPMessageに存在するget_filenameメソッドがありません。これにより、ヘッダーemail.Messageからファイル名を簡単に取得できます。Content-disposition: attachment; filename="fghi.xyz"

  • httplib.HTTPMessagegetparamgetplistおよびメソッドがありますが、AFAIKですが、ヘッダー解析parseplistの外部では使用できません。content-type

  • email.Messageまたはget_paramなどのパラメータを使用してRFC822ヘッダーを解析する一般的なメソッドがあります。content-dispositioncontent-type

したがって、get_filenameまたはget_paramのメソッドが必要email.message.Messageです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. Python2.6の場合。本番環境では2.7も3.xも使用できません。

  2. httplib.HTTPMessageから継承しmimetools.Message、独自の実装がありますrfc822.Messageemail.Message

4

2 に答える 2

2

Python 3.xでは、バインドされていないメソッドがなくなるため、この場合はファイルオブジェクトを取得するだけで、2番目の例が機能します。

>>> 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>

後者のアプローチには、Python3.xとの上位互換性があるという利点があります。

于 2011-02-24T21:50:03.587 に答える
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]

ありがとう !:-)

于 2011-02-25T09:06:32.493 に答える