[解決済み] 変数の文字列
質問
docstringをプレーンな変数に使用することは可能ですか?例えば、私は
t
def f():
"""f"""
l = lambda x: x
"""l"""
で、私は
>>> import t
>>> t.f.__doc__
'f'
しかし
>>> t.l.__doc__
>>>
のような例です。 PEP 258 のものです("this is g"を検索してください)。
どのように解決するのですか?
使用方法
typing.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
実行時にアノテーションにアクセスするには
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だけです。これは単に docstring を格納するよりも少し複雑ですが、実際には 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仕様には、関連するFieldから引用したこれら3つすべての例と説明があります。
そしてこれが、当時は正しかったが、時の試練に耐えていないオリジナルの答えです。
いいえ、それはできませんし、できても便利ではありません。
docstringは常にオブジェクト(モジュール、クラス、関数)の属性であり、特定の変数に結びつけられるものではありません。
つまり、もしあなたが ができました。 することができます。
t = 42
t.__doc__ = "something" # this raises AttributeError: '__doc__' is read-only
という変数ではなく、整数値42のドキュメントを設定することになります。
t
. を再定義するとすぐに
t
を再バインドするとすぐにdocstringを失います。文字列の数値のような不変のオブジェクトは、時に一つのオブジェクトを異なるユーザ間で共有することがあります。したがってこの例では、おそらく実際には
42
のすべての出現に対して docstring を設定したことになります。
print(42 .__doc__) # would print "something" if the above worked!
ミュータブルオブジェクトの場合、必ずしも有害ではありませんが、オブジェクトを再バインドした場合、まだ使用は限定的でしょう。
もしあなたがクラスの属性を文書化したいのであれば、それを記述するためにクラスのdocstringを使用してください。
関連
-
[解決済み] __init__.py でも「非パッケージで相対的なインポートを試みた」を修正する方法
-
[解決済み] for'ループでインデックスにアクセスする?
-
[解決済み] PandasでDataFrameの行を反復処理する方法
-
[解決済み] 最小限の驚き」と「変更可能なデフォルトの引数
-
[解決済み] 環境変数の値にアクセスする方法
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] モジュールの関数名(文字列)を使って、モジュールの関数を呼び出す。
-
[解決済み] 億の相対的輸入
-
[解決済み】forループを使った辞書の反復処理
-
[解決済み] Pythonでファイルの読み込みと上書きをする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Pythonのキャッシュライブラリはありますか?
-
[解決済み] 小数点以下1桁を取得する[重複]。
-
[解決済み] なぜ(0-6)は-6=偽なのか?重複
-
[解決済み] pandasのタイムゾーンに対応したDateTimeIndexを、特定のタイムゾーンに対応したナイーブなタイムスタンプに変換する。
-
[解決済み] Flask でグローバル変数はスレッドセーフか?リクエスト間でデータを共有するには?
-
[解決済み] djangoフレームワークでフォームフィールドから値を取得するには?
-
[解決済み] Pythonによる一対のクロスプロダクト [重複] (英語)
-
[解決済み] virtualenvsはどこに作成するのですか?
-
[解決済み] Pythonでランダムなファイル名を生成する最良の方法
-
[解決済み] Django filter queryset __in for *every* item in list