2017-02-09 15 views
20

Một mã minh họa như một giới thiệu cho những câu hỏi của tôi:Nhạy cảm với Python: lấy danh sách đối số của 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 

Có vẻ như rằng cách duy nhất để tôi tìm ra chữ ký của datetime.datetime.replace trong khi tôi đang xem xét nó trong the doc: date.replace(year, month, day).

Phần mẫn duy nhất mà dường như làm việc:

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

Tôi đã kiểm tra như thế nào Jupyter chức năng arglist công trình cụ-tip, họ có vấn đề chính xác cùng, tức là không có sẵn cho arglist datetime.datetime.replace.

Vì vậy, đây là những câu hỏi sau:

  1. là nó vẫn có thể để có được danh sách đối số bằng cách nào đó? Có lẽ tôi có thể cài đặt các nguồn C cho datetime và kết nối chúng thông qua thuộc tính __file__?

  2. Có thể chú thích một số <type 'method_descriptor'> bằng thông tin arglist không? Trong trường hợp đó, tôi có thể phân tích cú pháp định nghĩa markdown của tài liệu được liên kết và tự động chú thích các hàm mô-đun được tích hợp sẵn.

Trả lời

7

Không, bạn không thể nhận thêm thông tin; việc cài đặt các nguồn C sẽ không cho phép bạn truy cập dễ dàng như vậy. Đó là bởi vì hầu hết các phương thức được xác định trong mã C không thực sự hiển thị thông tin này; bạn phải phân tích ra một rather cryptic piece of C code:

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

Chức năng re.findall() là một pure Python function, như vậy là introspectable.

tôi đã nói nhất phương pháp quy định tại C, bởi vì như của Python 3.4 trở lên, phương pháp sử dụng mới Argument Clinic preprocessor sẽ bao gồm một __text_signature__ thuộc tính mới, mà nội inspect._signature_fromstr() function có thể phân tích cú pháp.Điều này có nghĩa rằng ngay cả đối với các phương pháp C định nghĩa như vậy, bạn có thể nội quan các đối số:

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

Xem thêm What are __signature__ and __text_signature__ used for in Python 3.4

Module datetime vẫn chưa nhận được nhiều Argument Clinic tình yêu. Chúng tôi sẽ phải kiên nhẫn, hoặc nếu bạn thực sự quan tâm nhiều về điều này, hãy cung cấp các bản vá để chuyển đổi mô-đun sang sử dụng Phòng khám Argument.

Nếu bạn muốn xem mô-đun nào do đã hỗ trợ, hãy xem Modules/clinic subdirectory có chứa đầu ra phòng khám được tạo; đối với mô-đun datetime, chỉ có datetime.datetime.now() hiện được bao gồm. Đó là phương pháp 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]*/ 

làm cho phương pháp introspectable:

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

Không có cách nào để trực tiếp đính kèm thông tin cho những chức năng C và phương pháp mà không phải là introspectable; chúng cũng không hỗ trợ các thuộc tính.

Hầu hết các giải pháp tự động hoàn tất muốn hỗ trợ các đối tượng đó sử dụng cấu trúc dữ liệu riêng biệt, nơi thông tin được duy trì độc lập (với tất cả rủi ro vốn có của dữ liệu không đồng bộ). Một số trong số này là có sẵn cho mục đích riêng của mình:

  • Các Komodo IDE thư viện mã thông minh (mã nguồn mở, sử dụng biên tập viên khác quá) sử dụng CIX format để mã hóa dữ liệu này; bạn có thể download the Python 3 catalog. Thật không may cho ví dụ cụ thể của bạn, chữ ký datetime.replace() chức năng chưa được fleshed ra hoặc:

    <scope doc="Return datetime with new specified fields." ilk="function" name="replace" /> 
    
  • Các Python 3.5 loại cú pháp gián tiếp mới cũng cần phải biết những gì loại của các đối số đối tượng mong đợi, và còn sơ khai mục đích này các tệp cần phải được cung cấp cho các đối tượng không thể được xem xét. Các Python typeshed project cung cấp các. Điều này bao gồm tất cả tên đối số cho số 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: ... 
    

    Bạn phải tự phân tích cú pháp tệp đó; họ có thể không phải lúc nào được nhập khẩu như các loại tài liệu tham khảo khai chưa được xác định, chứ không phải sử dụng 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 
    

    Bạn có thể làm việc xung quanh đó bằng cách sử dụng một đối tượng mô-đun được xác định trước và globals, sau đó iterating trên tên lỗi cho đến khi nó nhập khẩu mặc dù. Tôi sẽ để nó như một bài tập cho người đọc. Mypy và các loại checkers khác không cố gắng thực thi mã, chúng chỉ xây dựng một AST.

3

Sự cố bạn gặp phải là do các chức năng được mã hóa bằng chữ C không để lộ chữ ký của chúng. Bạn sẽ tìm thấy thêm thông tin về số này answer to "How to find out the arity of a method in Python".

Trong trường hợp của bạn, re.findall được định nghĩa bằng Python (xem def findall(pattern, string, flags=0):) trong khi datetime.datetime.replace được viết bằng C (xem datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw)).

Bạn có thể xem bằng cách sử dụng các thuộc tính khác nhau có sẵn (và __code__ thuộc tính đặc biệt) về chức năng với dir dựng sẵn:

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

Thông thường, help mang đến cho bạn những gì bạn cần (dựa trên __doc__ thuộc tính) nhưng trong trường hợp của bạn, nó dường như không giúp được gì nhiều:

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

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

Ngoài ra, một ý tưởng có thể là để cố gắng thiết lập các thuộc tính __code__ một cái gì đó đồng rresponding nhu cầu của bạn nhưng you can't tweak much on builtin types without subclassing.

Các vấn đề liên quan