python - 变量的文档字符串

标签 python

是否可以将文档字符串用于普通变量?例如,我有一个名为 t

的模块
def f():
    """f"""

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

我愿意

>>> import t
>>> t.f.__doc__
'f'

但是

>>> t.l.__doc__
>>> 

示例类似于 PEP 258 's(搜索“这是 g”)。

最佳答案

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

我最初写了一个答案(见下文),我说这是不可能的。早在 2012 年就是如此,但 Python 继续前进。今天,您可以为全局变量或类或实例的属性提供等效的文档字符串。您至少需要运行 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

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

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']}

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

>>> 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_type_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']}

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

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",
    )

使用模型类:

>>> 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 模式:

>>> 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 规范包含所有这三个的示例和说明,这些示例和描述均取自相关字段。

这是当时正确但没有经受住时间考验的原始答案:

不,这是不可能的,如果可以的话,它也不会有用。

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

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

t = 42
t.__doc__ = "something"  # this raises AttributeError: '__doc__' is read-only

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

print(42 .__doc__) # would print "something" if the above worked!

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

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

关于python - 变量的文档字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8820276/

相关文章:

python - 使用 Python 和 Pandas 在具有不同列名的 statsmodels.formula 数据上使用 predict()

python - 如何使用 Mayavi 绘制 3D 椭球体

python - 如何将 numpy 数组拆分为单个值?

python - 从键值对列表创建矩阵

python - 在 GAME 和 python 中查询具有特定父属性的实体?

python - 搜索和计算字典键值对

python - Python中使用keras错误进行多分类

python - JSON 元架构的 Pydantic 模型

python - 使用 ctypes 在 Python 中调用 Fortran 共享库

python - 如何在 Django 中将纯文本转换为散列密码