Python内省Introspection :获取method_descriptor的参数列表? - python

一个代码说明作为我的问题的简介:

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

似乎我在编码时查找datetime.datetime.replace签名的唯一方法是在the doc:date.replace(year, month, day)中查找它。

似乎有效的唯一内省Introspection 部分:

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

我已经检查了Jupyter函数arglist工具提示的工作原理,它们有完全相同的问题,即argt_code没有可用的arglist。

所以这是问题:

  • 是否仍然可以通过某种方式获取参数列表?也许我可以为datetime.datetime.replace安装C源代码并通过datetime属性将它们连接起来?
  • 是否可以用arglist信息注释__file__?在那种情况下,我可以解析链接文档的markdown定义并自动注释内置模块功能。
  • 参考方案

    不,您无法获得更多信息;安装C源代码不会使您轻松访问它们。这是因为用C代码定义的大多数方法实际上并没有公开这些信息。您必须解析出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))
    

    re.findall()函数是pure Python function,因此是自省的。

    我说过大多数用C定义的方法,因为从Python 3.4开始,使用新Argument Clinic preprocessor的方法将包括一个新的__text_signature__属性,内部 inspect._signature_fromstr() function可以解析该属性。这意味着,即使对于此类C定义的方法,您也可以内省Introspection 以下参数:

    >>> 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爱。我们必须耐心等待,或者,如果您真的很在乎此,请提供将模块转换为使用Argument Clinic的补丁。

    如果要查看哪些模块已经获得支持,请查看 Modules/clinic subdirectory,其中包含生成的诊所输出。对于datetime模块,当前仅包括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]*/
    

    使方法自省:

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

    无法将信息直接附加到那些自省的C函数和方法上。他们也不支持属性。

    想要支持此类对象的大多数自动完成解决方案都使用单独的数据结构,这些结构中的信息被独立维护(数据不同步的所有固有风险)。其中一些可用于您自己的目的:

  • Komodo 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。

  • Python:无符号32位按位算术 - python

    试图回答另一篇有关其解决方案涉及IP地址和网络掩码的文章时,我陷入了普通的按位算法。在Python中,是否存在一种标准的方式来进行按位AND,OR,XOR,NOT运算,假设输入是“32位”(可能是负数)整数或long,并且结果必须是[[ 0,2 ** 32]?换句话说,我需要一个与无符号长整数之间的C按位运算有效的Python对应物。编辑:具体问题是这样的:…

    Python:如何从字节中提取特定位? - python

    我有一条消息,显示为14 09 00 79 3d 00 23 27。我可以通过调用message[4]从此消息中提取每个字节,例如,这将给我3d。如何从该字节中提取单个8位?例如,如何将24-27位作为单个消息?只需28位? 参考方案 要回答问题的第二部分,您可以使用按位运算来获取特定的位值# getting your message as int i = …

    python lxml元素的属性问题 - python

    我必须构建一个如下所示的XML文件:<?xml version='1.0' encoding='ISO-8859-1'?> <Document protocol="OCI" xmlns="C"> <sessionId>xmlns=8745878…

    Python:检查是否存在维基百科文章 - python

    我试图弄清楚如何检查Wikipedia文章是否存在。例如,https://en.wikipedia.org/wiki/Food 存在,但是https://en.wikipedia.org/wiki/Fod 不会,页面只是说:“维基百科没有此名称的文章。”谢谢! 参考方案 >>> import urllib >>> prin…

    Python Pandas导出数据 - python

    我正在使用python pandas处理一些数据。我已使用以下代码将数据导出到excel文件。writer = pd.ExcelWriter('Data.xlsx'); wrong_data.to_excel(writer,"Names which are wrong", index = False); writer.…