関数アノテーションとは
関数アノテーションとは関数の引数と戻り値に付加情報をつける機能です。PEP 3107 -- Function Annotationsで定義されていて、
まずは、
>>> def foo(a: "a argument", b: int) -> ["return", "value"]:
... return a+b
...
>>> help(foo)
Help on function foo in module __main__:
foo(a: 'a argument', b: int) -> ['return', 'value']
>>> foo.__annotations__
{'a': 'a argument', 'b': <class 'int'>, 'return': ['return', 'value']}
>>> foo(3,5)
8
このように、
アノテーションの内容は関数オブジェクトの `__
今回は、
アノテーションでドキュメントを書く
Pythonでは一般的に docstring と呼ばれる方法で関数のドキュメントを書きます。引数や戻り値に関する説明も docstring の中に記述していました。たとえば以下のような感じです。
def load_config(conf_file):
"""設定ファイルを読み込む.
file は設定ファイルのパスを示す str オブジェクト。
設定値を格納した dict オブジェクトを返す。"""
アノテーションは help() や pydoc で表示されるので、
def load_config(conf_file: "設定ファイルのパス (str)") -> "設定値 (dict)":
"""設定ファイルを読み込む."""
...
>>> help(load_config)
Help on function load_config in module __main__:
load_config(conf_file: '設定ファイルのパス (str)') -> '設定値 (dict)'
設定ファイルを読み込む.
anntoolsで自動型変換
アノテーションを活用しているライブラリとして、
anntools は関数の引数や戻り値が想定している型や値になっているかどうかをチェックしたり、
Python 2.
def blog_edit(post_id):
post_id = int(post_id)
# ... post_id を元に記事を取得し編集画面を表示する
リクエストのURLから関数へマッピングするツール
これを、
>>> from anntools.conversion import *
>>> @convert(post_id = AsInt)
... def blog_edit(post_id):
... print type(post_id)
...
>>> blog_edit("32")
<type 'int'>
>>> blog_edit("foo-bar")
#tracebackは省略
ConversionError: Error converting argument 'post_id' of function 'blog_edit' by AsInt converter: post_id = 'foo-bar'
確かにうまく動くのですが、
今度は Python 3.
>>> from anntools.conversion import *
>>> @convert
... def blog_edit(post_id: AsInt):
... print(type(post_id))
...
>>> blog_edit(3)
<class 'int'>
>>> blog_edit("32")
<class 'int'>
>>> blog_edit("thirty two")
anntools.conversion.ConversionError: Error converting argument 'post_id' of function 'blog_edit' by AsInt converter: post_id = 'thirty two'
アノテーションがあると型情報を関数に付けることができるので、
anntoolsの型変換以外の機能として、
>>> from anntools.validation import *
>>> @validate
... def foo(n:Int(min=0, max=10)):
... print(n)
...
>>> foo(3)
3
>>> foo(-1)
anntools.validation.ValidationError: Error checking argument 'n' of function 'foo' with the Int validator: n = -1
範囲を指定できるなら、
アノテーションでoverloading
今度はアノテーションを使ってoverloading
overloadingとは静的型付け言語では一般的な機能で、
たとえばJavaのPrintStreamクラスでは println()メソッドをオーバーロードしていて、
public class Test {
static public void main(String[] args) {
// System.out は PrintStream型
System.out.println(3); // println(int) が呼ばれる. => "3"
System.out.println(2 == 3); // println(boolean) が呼ばれる. => "false"
System.out.println("foobar"); // println(String) が呼ばれる. => "foobar"
}
}
もちろんPythonのprint関数
from __future__ import print_function
def myprint(obj):
if isinstance(obj, int):
myprint_int(obj)
elif isinstance(obj, str):
myprint_str(obj)
elif ...
def myprint_int(obj):
print("<int>", obj, "</int>", sep="")
def myprint_str(obj):
print("<str>", obj, "</int>", sep="")
...
このようにisinstance()の列を書いていると、
この中のprettyprinter.
@overloaded
def pprint(self, obj):
self.write(repr(obj))
@pprint.register(object, list)
def pprint_list(self, obj):
if not obj:
# ...
先ほどのPython 2.
@overloaded
def pprint(self, obj):
self.write(repr(obj))
@pprint.register
def pprint_list(self, obj: list):
if not obj:
# ...
アノテーションで型指定していない引数は自動でobject型として扱うようにしたので、
おわりに
いくつかのサンプルを挙げてみたのですが、
Python 2.