Косая черта и звездочка в определении функции

Когда вы читаете документацию к некоторым функциям, вы видите, что в определении функции передаются косая черта (/) и звездочка (*). Зачем они нужны?

Зачем используются косая черта и звездочка?

Косая черта (/) и звездочка (*) используются для определения того, как должен передаваться аргумент при вызове функции.

Параметры с левой стороны от косой черты должны передаваться только как позиционные аргументы, в то время как параметры с правой стороны могут передаваться как позиционные или как именованные.

Звездочка указывает на то, что параметры справа от нее должны передаваться только как именованные, а параметры слева могут передаваться как позиционные или как именованные.

Косая черта и звездочка в параметрах функции
Параметры слеваСимволПараметры справа
Только позиционные аргументы/Или позиционные, или именованные аргументы
Или позиционные, или именованные аргументы*Только именованные аргументы

Косая черта и звездочка в параметре функции

Вот простой пример, показывающий, что когда в определении функции появляются косая черта и звездочка, то параметры привязываются исключительно к позиционным или именованным аргументам.

# Normal Function
def func_params(x, y, /, *, z):
    print(x, y, z)

Можно сделать вывод, что x и y – это исключительно позиционные параметры, а z — исключительно именованный. Давайте экспериментально проверим, связаны ли параметры только с позиционными и только с именованными аргументами.

params = func_params(2, y=3, z=4)

Параметр x передается как позиционный аргумент, а y и z – как именованные. При запуске кода будет получен следующий вывод:

Traceback (most recent call last):
  ...
    params = func_params(2, y=3, z=4)
             ^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: func_params() got some positional-only arguments passed as keyword arguments: 'y'

Python выдает ошибку TypeError, указывая на то, что исключительно позиционный параметр (y), был задан в виде именованного аргумента. Если вы просто передадите y как позиционный аргумент, код не выдаст никаких ошибок.

# Normal Function
def func_params(x, y, /, *, z):
    print(x, y, z)
 
# x & y passed as positional argument and z as a keyword argument
params = func_params(2, 3, z=4)
 
--------------------
2 3 4

Можно ли использовать звездочку перед косой чертой

Если вы используете и косую черту, и звездочку, то косая черта должна стоять перед звездочкой, иначе Python выдаст синтаксическую ошибку.

# Used asterisk before slash
def func_params(x, y, *, /, z):
    print(x, y, z)
 
params = func_params(2, 3, z=4)

Код был изменен, и звездочка используется перед косой чертой. Запустив код, вы получите ошибку синтаксиса.

  ...
    def func_params(x, y, *, /, z):
                             ^
SyntaxError: / must be ahead of *

Логически вставка звездочки перед косой чертой не имеет смысла, потому что параметры справа от звездочки относятся только к именованным, а параметры слева от косой черты – только к позиционным.

Это не будет работать вообще. Вот пример, демонстрирующий эту ситуацию.

# Used asterisk before slash
def func_params(x, y, *, a, b, /, z):
    print(x, y, a, b, z)
 
params = func_params(2, 3, a=5, b=6, z=4)

Параметры a и b находятся между звездочкой и косой чертой, поэтому неясно, являются ли они позиционными или исключительно именованными. Этот код все равно выдаст синтаксическую ошибку даже после передачи a и b в качестве именованных аргументов.

Использование в параметре функции или косой черты, или звездочки

Вы можете использовать косую черту и звездочку по отдельности, в зависимости от типа параметров, которые вам нужны. Вот пример, демонстрирующий использование только косой черты в определении функции.

def func_params(pos1, pos2, /, pos_or_kw):
    print(pos1, pos2, pos_or_kw)
 
params = func_params(2, 3, pos_or_kw=4)
 
--------------------
2 3 4

Параметры pos1 и pos2 являются исключительно позиционными, а pos_or_kw – позиционным или именованным.

Аналогично, в определении функции можно использовать и только звездочку.

def func_params(pos_or_kw, *, kw1, kw2):
    print(pos_or_kw, kw1, kw2)
 
params = func_params(4, kw1=3, kw2=2)
 
--------------------
4 3 2

Написание функции, принимающей только позиционные аргументы

Если вы хотите создать функцию или класс, принимающий только позиционные аргументы, добавьте косую черту в конце списка параметров.

# Function that takes only positional arguments
def prescription(med1, med2, med3, /):
    print("Prescribed Meds:")
    print(f"Med 1: {med1}")
    print(f"Med 2: {med2}")
    print(f"Med 3: {med3}")
 
prescription("Paracetamol", "Omeprazole", "Ibuprofen")
 
--------------------
Prescribed Meds:
Med 1: Paracetamol
Med 2: Omeprazole
Med 3: Ibuprofen

Функция prescription() принимает три аргумента: med1, med2 и med3. Вы видите, что в конце параметров стоит косая черта, которая делает их исключительно позиционными.

Если вы попытаетесь передать в функцию prescription() именованный аргумент, то получите ошибку.

prescription("Paracetamol", "Omeprazole", med3="Ibuprofen")
--------------------
Traceback (most recent call last):
  ...
    prescription("Paracetamol", "Omeprazole", med3="Ibuprofen")
TypeError: prescription() got some positional-only arguments passed as keyword arguments: 'med3'

Написание функции, принимающей только именованные аргументы

Вы можете использовать звездочку в определении функции, чтобы сделать параметры в правой части исключительно именованными.

Если вам нужна функция, принимающая только именованные параметры, просто включите звездочку в начало списка параметров функции.

# Function that takes only keyword arguments
def prescription(*, med1, med2, med3):
    print("Prescribed Meds:")
    print(f"Med 1: {med1}")
    print(f"Med 2: {med2}")
    print(f"Med 3: {med3}")
 
prescription(med1="Paracetamol", med2="Omeprazole", med3="Ibuprofen")
 
-------------------
Prescribed Meds:
Med 1: Paracetamol
Med 2: Omeprazole
Med 3: Ibuprofen

Теперь функция prescription() принимает только аргументы с именами и не допускает позиционных аргументов.

Допустимые и недопустимые определения функций

Вот несколько допустимых определений функций, которые могут сочетаться с косой чертой и звездочкой. Источник.

def f(p1, p2, /, p_or_kw, *, kw):
def f(p1, p2=None, /, p_or_kw=None, *, kw):
def f(p1, p2=None, /, *, kw):
def f(p1, p2=None, /):
def f(p1, p2, /, p_or_kw):
def f(p1, p2, /):

Скорее всего, вы знакомы с правилами определения позиционных и именованных параметров. В соответствии с этими правилами приведенные выше определения функций валидны.

Однако следующие определения функций считаются невалидными, поскольку они определены не в соответствии с правилами.

def f(p1, p2=None, /, p_or_kw, *, kw):
def f(p1=None, p2, /, p_or_kw=None, *, kw):
def f(p1=None, p2, /):

После определения параметра со значением по умолчанию все последующие параметры (для параметров после звездочки – опционально) должны быть тоже определены со значением по умолчанию, чтобы избежать двусмысленности в вызовах функций.

Заключение

Косая черта и звездочка определяют, как должен передаваться аргумент при вызове функции.

Косая черта в определении функции указывает на то, что параметры слева от нее должны рассматриваться только как позиционные.

Звездочка в определении функции указывает на то, что параметры справа от нее должны рассматриваться только как именованные.

В определении функции можно использовать как оба символа, так и какой-то один. Если вы используете и косую черту, и звездочку, косая черта должна идти перед звездочкой.

Источник: https://peps.python.org/pep-0570/

Перевод статьи “Why Slash and Asterisk Used in Function Definition”.

1 комментарий к “Косая черта и звездочка в определении функции”

  1. Пингбэк: Позиционные и именованные аргументы в функциях Python

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *