20 ноября 2012 г.

Снова функции


Функции и другие их возможности

Применяемые операции к функциям:
Рассмотрим некую функцию foo
>>> def foo(a):
...     b = ‘spam’
...     return b * a
...
>>> foo(8)   # является операцией(выражение вызова)применимой к 
‘spamspamspamspamspamspamspamspam’             # функции
-----------------------------------------------------------------

Получение базового доступа к атрибутам функции:

>>> foo.__name__


‘foo’
>>> dir(foo)
[‘__annotations__’, ‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’,
...остальные имена опущены...
‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’]

Похожий механизм, называется интроспекцией - механизм исследования деталей реализации функции. Примеры:

>>> fоо.__code__
<code object fоо at 0x0257C9B0, file “<stdin>”, line 1>

>>> dir(fоо.__code__)
[‘__class__’, ‘__delattr__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’,
...остальные имена опущены...
‘co_argcount’, ‘co_cellvars’, ‘co_code’, ‘co_consts’, ‘co_filename’,
‘co_firstlineno’, ‘co_flags’, ‘co_freevars’, ‘co_kwonlyargcount’, ‘co_lnotab’,
‘co_name’, ‘co_names’, ‘co_nlocals’, ‘co_stacksize’, ‘co_varnames’]

>>> fоо.__code__.co_varnames
(‘a’, ‘b’)
>>> fоо.__code__.co_argcount
1
-----------------------------------------------------------------

К функциям можно присоединять свои атрибуты:
>>> foo
<function foo at 0x0257C738>
>>> foo.count = 0
>>> foo.count += 1
>>> foo.count
1
>>> foo.handles = ‘Button-Press’
>>> foo.handles
‘Button-Press’
>>> dir(foo)
[‘__annotations__’, ‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’,
...остальные имена опущены...
__str__’, ‘__subclasshook__’, ‘count’, ‘handles’]

Такие  атрибуты  можно использовать для  хранения информации о состоянии непосредственно в  объекте функции и  отказаться  от  использования других приемов,  таких  как применение  глобальных или нелокальных переменных и классов.
-----------------------------------------------------------------

Аннотации функций, версия 3.0:
Краткое описание (аннотация) – произвольные данные об аргумен
тах  функции  и  о  возвращаемом значении.

Аннотации необязательны, но если они есть, тогда они просто сохраняются в атрибутах __annotations__  объектов функций и могут использоваться другими инструментами.

Не аннотированная функция: 
>>> def func(a, b, c):
...     return a + b + c
...
>>> func(1, 2, 3)
6

Аннотированная функция:
>>> def func(a: ‘spam’, b: (1, 10), c: float) -> int:
...     return a + b + c
...
>>> func(1, 2, 3)
6
Аннотированы все три аргумента. Аннотации для аргументов указываются через двоеточие, сразу после имени аргумента. Для возвращаемого значения – после символов ->, вслед за списком аргументов.

Если в объявлении функции присутствуют аннотации, интерпретатор 
соберет их в словарь и присоединит его к объекту функции. 

Имена аргументов станут ключами, аннотация возвращаемого значения будет сохранена в ключе «return», а значениям ключей этого словаря будут присвоены результаты выражений в аннотациях:
>>> func.__annotations__
{‘a’: ‘spam’, ‘c’: <class ‘float’>, ‘b’: (1, 10), ‘return’: <class ‘int’>}
-----------------------------------------------------------------

Обработка аннотаций:
>>> def func(a: ‘spam’, b, c: 99):
...     return a + b + c
...
>>> func(1, 2, 3)
6
>>> func.__annotations__
{‘a’: ‘spam’, ‘c’: 99}

>>> for arg in func.__annotations__:
...     print(arg, ‘=>’, func.__annotations__[arg])
...
a => spam
c => 99
В данном примере выполнен обход аннотаций.
-----------------------------------------------------------------

Аннотации и значения по умолчанию:
Также можно указывать значения по умолчанию – аннотация (и символ : ) находится перед значением по умолчанию (и перед символом). В следующем примере фрагмент 
a: ‘spam’ = 4 означает, что аргумент a по умолчанию получает значение 4 и аннотирован строкой ‘spam’:
>>> def func(a: ‘spam’ = 4, b: (1, 10) = 5, c: float = 6) -> int:
...     return a + b + c
...
>>> func(1, 2, 3)
6
>>> func()         # 4 + 5 + 6 (все аргументы получают значения по умолчанию)
15
>>> func(1, c=10)  # 1 + 5 + 10 (именованные аргументы действуют как обычно)
16
>>> func.__annotations__
{‘a’: ‘spam’, ‘c’: <class ‘float’>, ‘b’: (1, 10), ‘return’: <class ‘int’>}
вы можете использовать или не использовать пробелы между компонентами в заголовках функций, однако отказ от использования пробелов может ухудшить удобочитаемость программного кода.

1 комментарий:

  1. Отличное описание аннотаций. То что я искал. Благодарю :-)

    ОтветитьУдалить