首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >变量的Docstring

变量的Docstring
EN

Stack Overflow用户
提问于 2012-01-11 21:42:52
回答 9查看 50.6K关注 0票数 85

是否可以对普通变量使用docstring?例如,我有一个名为t的模块

代码语言:javascript
复制
def f():
    """f"""

l = lambda x: x
"""l"""

我就是这么做的

代码语言:javascript
复制
>>> import t
>>> t.f.__doc__
'f'

代码语言:javascript
复制
>>> t.l.__doc__
>>> 

示例类似于PEP 258的示例(搜索"this is g")。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2012-01-11 22:07:22

使用typing.Annotated为变量提供文档字符串。

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

代码语言:javascript
复制
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

您可以在运行时使用typing.get_type_hints()访问注释

代码语言:javascript
复制
Python 3.9.1 (default, Jan 19 2021, 09:36:39) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import calc
>>> from typing import get_type_hints
>>> hints = get_type_hints(calc, include_extras=True)
>>> hints
{'day': typing.Annotated[float, 'seconds'], 'legal_limit': typing.Annotated[float, 'miles per hour', 'UK national limit for single carriageway'], 'current_speed': typing.Annotated[float, 'miles per hour']}

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

代码语言:javascript
复制
>>> hints['legal_limit'].__metadata__
('miles per hour', 'UK national limit for single carriageway')
>>> hints['day']
typing.Annotated[float, 'seconds']

它甚至适用于具有类型注释但尚未赋值的变量。如果我试图引用calc.current_speed,我会得到一个属性错误,但我仍然可以访问它的元数据:

代码语言:javascript
复制
>>> hints['current_speed'].__metadata__
('miles per hour',)

模块的类型提示仅包括全局变量,要向下钻取,您需要在函数或类上再次调用get_type_hints()

代码语言:javascript
复制
>>> 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']}

到目前为止,我只知道一种工具可以使用typing.Annotated来存储有关变量的文档,那就是Pydantic。它比仅仅存储文档字符串稍微复杂一些,尽管它实际上需要一个pydantic.Field的实例。下面是一个例子:

代码语言:javascript
复制
from typing import Annotated
import typing_extensions
from pydantic import Field
from pydantic.main import BaseModel
from datetime import date

# TypeAlias is in typing_extensions for Python 3.9:
FirstName: typing_extensions.TypeAlias = Annotated[str, Field(
        description="The subject's first name", example="Linus"
    )]

class Subject(BaseModel):
    # Using an annotated type defined elsewhere:
    first_name: FirstName = ""

    # Documenting a field inline:
    last_name: Annotated[str, Field(
        description="The subject's last name", example="Torvalds"
    )] = ""

    # Traditional method without using Annotated
    # Field needs an extra argument for the default value
    date_of_birth: date = Field(
        ...,
        description="The subject's date of birth",
        example="1969-12-28",
    )

使用模型类:

代码语言:javascript
复制
>>> guido = Subject(first_name='Guido', last_name='van Rossum', date_of_birth=date(1956, 1, 31))
>>> print(guido)
first_name='Guido' last_name='van Rossum' date_of_birth=datetime.date(1956, 1, 31)

Pydantic模型可以为您提供JSON模式:

代码语言:javascript
复制
>>> from pprint import pprint
>>> pprint(Subject.schema())
{'properties': {'date_of_birth': {'description': "The subject's date of birth",
                                  'example': '1969-12-28',
                                  'format': 'date',
                                  'title': 'Date Of Birth',
                                  'type': 'string'},
                'first_name': {'default': '',
                               'description': "The subject's first name",
                               'example': 'Linus',
                               'title': 'First Name',
                               'type': 'string'},
                'last_name': {'default': '',
                              'description': "The subject's last name",
                              'example': 'Torvalds',
                              'title': 'Last Name',
                              'type': 'string'}},
 'required': ['date_of_birth'],
 'title': 'Subject',
 'type': 'object'}
>>> 

如果您在FastAPI应用程序中使用这个类,那么OpenApi规范中有取自相关字段的所有这三个类的示例和描述。

这是最初的答案,当时是正确的,但没有经受住时间的考验:

不,这是不可能的,即使你可以,它也不会有什么用处。

文档字符串始终是对象(模块、类或函数)的属性,而不是绑定到特定变量。

这意味着如果你可以这样做:

代码语言:javascript
复制
t = 42
t.__doc__ = "something"  # this raises AttributeError: '__doc__' is read-only

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

代码语言:javascript
复制
print(42 .__doc__) # would print "something" if the above worked!

对于可变对象,它不一定是有害的,但如果您重新绑定对象,它的使用仍然是有限的。

如果你想记录一个类的属性,那么使用类的文档字符串来描述它。

票数 87
EN

Stack Overflow用户

发布于 2013-12-12 04:56:07

Epydoc支持docstrings on variables

虽然语言没有直接提供它们,但Epydoc支持变量文档字符串:如果变量赋值语句后面紧跟一个纯字符串文字,那么该赋值将被视为该变量的文档字符串。

示例:

代码语言:javascript
复制
class A:
    x = 22
    """Docstring for class variable A.x"""

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

Stack Overflow用户

发布于 2015-08-02 01:34:58

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

代码语言:javascript
复制
debug = False
'''Set to True to turn on debugging mode. This enables opening IPython on 
exceptions.
'''

下面是一些代码,它将扫描模块并提取全局变量定义的名称、值和随后的文档字符串。

代码语言:javascript
复制
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
票数 29
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8820276

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档