2017-02-09 14 views
20

私の質問へのイントロとしてコードイラスト:date.replace(year, month, day)Pythonのイントロスペクション:method_descriptorの引数リストを取得しますか?

import re, inspect, datetime 

inspect.getargspec (re.findall) 
# => 
# ArgSpec(args = ['pattern', 'string', 'flags'], varargs=None, 
# keywords=None, defaults = (0,)) 

type (datetime.datetime.replace) 
# => <type 'method_descriptor'> 

inspect.getargspec (datetime.datetime.replace) 
# => Traceback (most recent call last): 
#  File "<stdin>", line 1, in <module> 
#  File "/usr/lib/python2.7/inspect.py", line 816, in getargspec 
#  raise TypeError('{!r} is not a Python function'.format(func)) 
# TypeError: <method 'replace' of 'datetime.datetime' objects> is 
# not a Python function 

それは私のコードはthe docでそれを見ている間、私はdatetime.datetime.replaceの署名を見つけるための唯一の方法と思われます。

動作するようです唯一のイントロスペクションの一部:

datetime.datetime.replace.__doc__ 
# => 'Return datetime with new specified fields.' 

私はJupyter関数引数リストのツールチップがどのように機能するか、彼らは正確に同じ問題が、datetime.datetime.replaceために利用可能な、すなわち無引数リストを持って検討してきました。だからここ

が質問です:

  1. は何とか引数リストを取得することは可能ですか?たぶん私はdatetimeのCソースをインストールし、__file__属性を介してそれらを接続することができますか?

  2. <type 'method_descriptor'>にarglist情報を付けることはできますか?その場合、リンクされたドキュメントのマークダウン定義を解析し、組み込みモジュール関数に自動的に注釈を付けることができます。

答えて

7

いいえ、詳細を知ることはできません。 Cソースをインストールしても、同じソースに簡単にアクセスすることはできません。これは、のCコードで定義されているのメソッドが実際にはこの情報を公開していないためです。

if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO$i:replace", 
            datetime_kws, 
            &y, &m, &d, &hh, &mm, &ss, &us, 
            &tzinfo, &fold)) 

re.findall()機能がpure Python functionなので、イントロスペクションです:あなたはrather cryptic piece of C codeを解析する必要があると思います。

アップのPython 3.4とのとして、新しいArgument Clinic preprocessorを使用する方法は、内部inspect._signature_fromstr() functionを解析できる新しい__text_signature__属性が含まれますので、私は、Cで定義された最も方法を述べました。これはさえ、このようなC-定義されたメソッドのために、あなたは引数をイントロスペクションできることを意味します

>>> import io 
>>> import inspect 
>>> type(io.BytesIO.read) 
<class 'method_descriptor'> 
>>> inspect.signature(io.BytesIO.read) 
<Signature (self, size=None, /)> 

はまたWhat are __signature__ and __text_signature__ used for in Python 3.4

datetimeモジュールは、まだ多くの引数クリニックの愛を受け取っていない参照してください。私たちは忍耐を持たなければなりません。または、これについて本当に心配しているのであれば、Argument Clinicを使用してモジュールを変換するパッチを提供してください。

あなたはが発生したクリニックの出力が含まれていModules/clinic subdirectoryを見て、すでにサポートされていないモジュールを見たい場合は、 モジュールの場合、現在はdatetime.datetime.now()のみが含まれています。その方法defines a clinic block:メソッドイントロスペクション製造

/*[clinic input] 
@classmethod 
datetime.datetime.now 
    tz: object = None 
     Timezone object. 
Returns new datetime object representing current time local to tz. 
If no tz is specified, uses local timezone. 
[clinic start generated code]*/ 

static PyObject * 
datetime_datetime_now_impl(PyTypeObject *type, PyObject *tz) 
/*[clinic end generated code: output=b3386e5345e2b47a input=80d09869c5267d00]*/ 

:直接イントロスペクションではないもの、C関数やメソッドに情報を添付する方法はありません

>>> import datetime 
>>> inspect.signature(datetime.datetime.now) 
<Signature (tz=None)> 

と、属性もサポートしていません。

このようなオブジェクトをサポートしたいオートコンプリートソリューションのほとんどは、情報が独立して維持される別々のデータ構造を使用します(データが同期するすべての固有のリスクを伴います)。これらのいくつかは、あなた自身の目的のために用意されています

  • コモドIDEのコード・インテリジェンス・ライブラリーは、(オープンソースは、あまりにも他のエディタを使用)、このデータをエンコードするためにCIX formatを使用しています。あなたはdownload the Python 3 catalogでした。残念ながら、あなたの具体的な例のために、datetime.replace()関数のシグネチャはを肉付けのいずれかされていません。

    <scope doc="Return datetime with new specified fields." ilk="function" name="replace" /> 
    
  • 構文をほのめかし新しいPythonの3.5タイプは、オブジェクトが期待する引数の種類を知る必要があり、この端スタブへイントロスペクトされないオブジェクトに対してファイルを提供する必要があります。 Python typeshed projectはこれらを提供します。これはdatetime moduleのためのすべての引数名が含まれています

    class datetime: 
        # ... 
        def replace(self, year: int = ..., month: int = ..., day: int = ..., hour: int = ..., 
         minute: int = ..., second: int = ..., microsecond: int = ..., tzinfo: 
         Optional[_tzinfo] = None) -> datetime: ... 
    

    あなたは、このようなファイルを解析する必要があると思います自分自身。彼らは常に、まだ定義されていないスタブ参照型としてインポートではなく、forward referencesを使用することはできません。

    >>> import importlib.machinery 
    >>> path = 'stdlib/3/datetime.pyi' 
    >>> loader = importlib.machinery.SourceFileLoader('datetime', path) 
    >>> loader.load_module() 
    Traceback (most recent call last): 
        File "<stdin>", line 1, in <module> 
        File "<frozen importlib._bootstrap_external>", line 399, in _check_name_wrapper 
        File "<frozen importlib._bootstrap_external>", line 823, in load_module 
        File "<frozen importlib._bootstrap_external>", line 682, in load_module 
        File "<frozen importlib._bootstrap>", line 251, in _load_module_shim 
        File "<frozen importlib._bootstrap>", line 675, in _load 
        File "<frozen importlib._bootstrap>", line 655, in _load_unlocked 
        File "<frozen importlib._bootstrap_external>", line 678, in exec_module 
        File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed 
        File "stdlib/3/datetime.pyi", line 12, in <module> 
        class tzinfo: 
        File "stdlib/3/datetime.pyi", line 13, in tzinfo 
        def tzname(self, dt: Optional[datetime]) -> str: ... 
    NameError: name 'datetime' is not defined 
    

    あなたが事前に定義されたモジュールオブジェクトとグローバルを使用して、その回避できる可能性があり、その後の反復処理しますそれがインポートするまで名前エラー。私はそれを読者のための練習として残しておきます。 Mypyと他のタイプチェッカーはコードを実行しようとせず、単にASTを構築します。

3

問題は、Cコード関数が署名を公開していないことが原因で発生しています。このanswer to "How to find out the arity of a method in Python"の詳細については、こちらをご覧ください。 datetime.datetime.replaceがC(datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)を参照)で記述されている間、あなたのケースで

は、re.findallは(def findall(pattern, string, flags=0):参照)Pythonで定義されています。

あなたがdir組み込みと機能で利用可能なさまざまな属性(特に__code__属性)を使用して見ることができます。通常

>>> dir(datetime.datetime.replace) 
['__call__', '__class__', '__delattr__', '__doc__', '__format__', '__get__', '__getattribute__', '__hash__', '__init__', '__name__', '__new__', '__objclass__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] 
>>> dir(re.findall) 
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] 
>>> datetime.datetime.replace.__code__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'method_descriptor' object has no attribute '__code__' 
>>> re.findall.__code__ 
<code object findall at 0x7fe7234e74b0, file "/usr/lib/python2.7/re.py", line 173> 

helpはあなたが必要なものを提供します(__doc__に基づきます属性)が、あなたの場合には、それははるかに助けていないようです:

>>> help(datetime.datetime.replace) 
Help on method_descriptor: 

replace(...) 
    Return datetime with new specified fields. 

また、アイデアが何かの共同へ__code__属性を設定しようとするかもしれませんお客様のニーズに対応しますが、you can't tweak much on builtin types without subclassingです。

関連する問題