Python 变量的Docstring

Python 变量的Docstring,python,Python,是否可以将docstring用于普通变量?例如,我有一个名为t def f(): """f""" l = lambda x: x """l""" 我也是 >>> import t >>> t.f.__doc__ 'f' 但是 示例类似于的(搜索“this is g”)。不,据我所知,您只能对模块(lambda和“normal”)函数和类执行此操作。其他对象,即使是可变对象,也会继承其类的docstring并在尝试更改时引发AttributeErr

是否可以将docstring用于普通变量?例如,我有一个名为
t

def f():
    """f"""

l = lambda x: x
"""l"""
我也是

>>> import t
>>> t.f.__doc__
'f'
但是


示例类似于的(搜索“this is g”)。

不,据我所知,您只能对模块(lambda和“normal”)函数和类执行此操作。其他对象,即使是可变对象,也会继承其类的docstring并在尝试更改时引发
AttributeError

>>> a = {}
>>> a.__doc__ = "hello"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object attribute '__doc__' is read-only
>a={}
>>>a.。\uuuu doc\uuuuu=“你好”
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“dict”对象属性“\uuuuu doc\uuuuuuu”是只读的

(您的第二个示例是有效的Python,但是字符串
“l”“”
没有任何作用。它是生成、计算和丢弃的。)

一些Python文档脚本具有可以在模块/类docstring中用于记录变量的符号

例如,对于spinx,可以使用:var和:ivar。请参见此图(大约下半部分)。

使用
键入.Annotated
为变量提供docstring。 我最初写了一个答案(见下文),我说这是不可能的。这在2012年是正确的,但Python已经向前发展了。现在,您可以为全局变量或类或实例的属性提供相当于docstring的内容。您需要至少运行Python 3.9才能使其正常工作:

from __future__ import annotations
from typing import Annotated

Feet = Annotated[float, "feet"]
Seconds = Annotated[float, "seconds"]
MilesPerHour = Annotated[float, "miles per hour"]

day: Seconds = 86400
legal_limit: Annotated[MilesPerHour, "UK national limit for single carriageway"] = 60
current_speed: MilesPerHour

def speed(distance: Feet, time: Seconds) -> MilesPerHour:
    """Calculate speed as distance over time"""
    fps2mph = 3600 / 5280  # Feet per second to miles per hour
    return distance / time * fps2mph
您可以在运行时使用
键入来访问批注。获取\u type\u提示()

使用声明变量的模块或类的提示提取有关变量的信息。请注意嵌套注释时注释是如何组合的:

>>> hints['legal_limit'].__metadata__
('miles per hour', 'UK national limit for single carriageway')
>>> hints['day']
typing.Annotated[float, 'seconds']
它甚至适用于具有类型注释但未指定值的变量。如果我尝试引用calc.current_speed,我会得到一个属性错误,但我仍然可以访问其元数据:

>>> hints['current_speed'].__metadata__
('miles per hour',)
模块的类型提示仅包括全局变量,要深入查看,您需要再次调用函数或类的
get\u type\u hints()

>>> get_type_hints(calc.speed, include_extras=True)
{'distance': typing.Annotated[float, 'feet'], 'time': typing.Annotated[float, 'seconds'], 'return': typing.Annotated[float, 'miles per hour']}
这是最初的答案,当时是正确的,但还没有经受住时间的考验:

不,这是不可能的,如果你可以的话,它也不会有用。 docstring始终是对象(模块、类或函数)的属性,不绑定到特定变量

这意味着如果你能做到:

您将为整数42而不是变量
t
设置文档。重新绑定
t
后,文档字符串将丢失。不可变对象(如字符串数)有时在不同用户之间共享一个对象,因此在本例中,您可能实际上已经为整个程序中出现的所有
42
设置了docstring

print(42 .__doc__) # would print "something" if the above worked!
对于可变对象,它不一定有害,但如果您重新绑定对象,它的用途仍然有限

如果要记录类的属性,请使用类的docstring来描述它。

Epydoc允许:

虽然语言没有直接为它们提供支持,但Epydoc支持 变量docstrings:如果变量赋值语句立即 后跟裸字符串文字,则该赋值被视为 该变量的docstring

例如:

class A:
    x = 22
    """Docstring for class variable A.x"""

    def __init__(self, a):
        self.y = a
        """Docstring for instance variable A.y

尽管Python不会将在全局定义之后立即定义的字符串视为变量的docstring,但sphinx会这样做,并且包含它们肯定不是一个坏的做法

debug = False
'''Set to True to turn on debugging mode. This enables opening IPython on 
exceptions.
'''
下面是一些代码,它们将扫描模块并提取全局变量定义的名称、值和后面的docstring

def GetVarDocs(fname):
    '''Read the module referenced in fname (often <module>.__file__) and return a
    dict with global variables, their value and the "docstring" that follows
    the definition of the variable
    '''
    import ast,os
    fname = os.path.splitext(fname)[0]+'.py' # convert .pyc to .py
    with open(fname, 'r') as f:
        fstr = f.read()
    d = {}
    key = None
    for node in ast.walk(ast.parse(fstr)):
        if isinstance(node,ast.Assign):
            key = node.targets[0].id
            d[key] = [node.value.id,'']
            continue
        elif isinstance(node,ast.Expr) and key:
            d[key][1] = node.value.s.strip()
        key = None
    return d
def GetVarDocs(fname):
''读取fname中引用的模块(通常为.__文件),并返回一个
使用全局变量及其值和后面的“docstring”进行dict
变量的定义
'''
导入ast,操作系统
fname=os.path.splitext(fname)[0]+'.py'#convert.pyc to.py
将open(fname,'r')作为f:
fstr=f.read()
d={}
键=无
对于ast.walk(ast.parse(fstr))中的节点:
如果isinstance(节点,ast.Assign):
键=节点。目标[0]。id
d[key]=[node.value.id',]
持续
elif isinstance(节点,ast.Expr)和键:
d[key][1]=node.value.s.strip()
键=无
返回d

要补充ford关于Epydoc的回答,请注意PyCharm还将使用字符串文字作为类中变量的文档:

class Fields_Obj:
    DefaultValue=None
    """Get/set the default value of the data field"""

Sphinx具有用于记录属性的内置语法(即,不是@duncan描述的值)。示例:

#: This is module attribute
x = 42

class MyClass:

    #: This is a class attribute
    y = 43
您可以在Sphinx文档中阅读更多内容:


…或者在另一个问题中:

属性可以有docstring!这涵盖了记录实例变量的最常见用例

class A:
    def __init__(self):
        self._x = 22

    @property
    def x(self):
        "document x"
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

A.x.__doc__

很多答案都假设您想要离线使用,并指向sphinx或Epydoc

但是如果您想在运行时使用它,答案是不可能将一个属性添加到另一个属性。所以不能将doctring附加到变量

当您这样做时:

a = True
print(a.__doc__)
您将获得bool类的docstring。 在我的应用程序中,我需要它作为插件。我要做的是使用关联的变量/属性

大概是这样的:

a = True
_help_a = "help for a variable"
with document:
    a = True
    """ help for a variable """
因为这看起来很难看,所以我实际上使用的是语法宏(看看模块)。代码如下所示:

a = True
_help_a = "help for a variable"
with document:
    a = True
    """ help for a variable """

我解释了整个想法

PEP 258被拒绝。可能是重复的。您想在变量中添加docstring,还是仅仅引用一个变量的文档,例如sphinx可以解析并以有用的方式呈现?@alexanderkuk:这个答案比我的好。你应该接受它。“不,如果你可以的话,它就没用了。”如果变量不是这样实现的话,它就没用了。如果可以的话,它就没用了——为什么不呢?如果我的模块使用符号,我应该如何记录它们?这样,pydoc的数据部分就有一半的用处了。它没有用处的真正原因是docstring是一个对象的属性,而不是某个特定对象中的符号
with document:
    a = True
    """ help for a variable """