В дополнении к "моржовому оператору"
в Python 3.8 появится ещё один специальный символ для описания параметров функции.
Если до этого мы имели дело со звёздочкой (*
), то теперь ещё получим
косую черту/слеш (/
).
Напомню, что звёздочка как параметр функции используется для указания начала списка именованных (обязательно) параметров. То есть при вызове такой функции будет необходимо все последующие аргументы передавать с указанием их имени. Например,
def get_statistic(stat_data, *, user, date_from=None, date_to=None):
"""Получение статистики по пользователю с фильтром по дате"""
Таким образом мы обязаны передать параметр stat_data
(данные для фильтрации),
а также передать юзера как именованный аргумент. Остальные – также
указываются как именованные аргументы, но являются необязательными:
>>> get_statistic([], user='user_login')
>>> get_statistic([], user='user_login', date_from='2019-05-01')
>>> get_statistic([], 'user_login')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: get_statistic() takes 1 positional argument but 2 were given
– довольно полезно и наглядно, когда параметров много. Например, для указания параметров фильтрации, где потенциально их может быть очень много.
Аналогично работает /
. Однако, все параметры, которые шли до него,
обязаны быть позиционными. То есть, если мы опишем функцию:
def contains(collection, key, /):
"""Поиск элемента в коллекции"""
– то мы не сможем вызвать эту функцию как contains([1, 2, 3], key=2)
, а только
contains([1, 2, 3], 2)
. К слову, посмотрите, как описан метод __contains__
объекта
range
уже сейчас:
>>> help(range)
Help on class range in module builtins:
class range(object)
| range(stop) -> range object
...
| __contains__(self, key, /)
| Return key in self.
...
Такой синтаксис уже давно используется для Python-функций, написанных на Си. Теперь так можно будет писать прямо в Python (на момент 3.8.0a3 уже есть такая возможность).
PEP по этой новой синтаксической возможности довольно интересен. Особенно часть "Rejected Ideas". Однако, сейчас хочется больше рассмотреть раздел с мотивацией.
Помимо более жёсткого прибивания гвоздями вариантов вызова функций... и консистентности языка в плане "как в хелпе сишных функций"... Пожалуй, логичным выглядит довод с параметрами, которые имеют смысл как последовательность. Например,
range(stop=5, start=0, step=2)
range(stop=5, step=2, start=0)
range(step=2, start=0, stop=5)
range(step=2, stop=5, start=0)
– и да, range не примет и так позиционные аргументы, но порядок старт-финиш-шаг привычен. Изменение его (если бы это можно было сделать) могло бы запутать. Правда, таких "злобных буратин" надо ещё поискать... Тем не менее, это уже имеет определённый смысл. Ожидаем в Python 3.8!
И всё же, молю пользоваться новыми возможностями с осторожностью: не у всякого выдержит психика подобный код:
def name(
positional_only_parameters,
/,
positional_or_keyword_parameters,
*,
keyword_only_parameters
):
А если ещё без форматирования, да с type-hinting-ом, да дефолтными значениями...