Мне просто было интересно, как в Python было бы предпочтительнее сделать группу аргументов функции необязательной, но только как всю группу. Значение: они должны быть либо все даны, либо ни один.

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

Теперь я хочу, чтобы эта функция печатала на стандартный вывод, если файл не указан, и в файл в противном случае. Хитрость заключается в следующем: я хочу, чтобы эта функция всегда требовала указания кодировки всякий раз, когда используется файл. И вызов этой функции с кодировкой, но никаким файлом тоже нельзя запрещать.

В Java я мог бы перегрузить функцию и дать реализации для обоих допустимых вариантов:

public void print(string message);
public void print(string message, File f, string encoding);

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

В Python я могу сделать отдельные аргументы необязательными, указав значение по умолчанию, но я не могу сгруппировать их вместе.

def print(msg, file=None, encoding=None)

Позволяет мне вызвать функцию, предоставив сообщение и ни один, оба или только один из других параметров:

print("test")
print("test", file=someFile)
print("test", encoding="utf-8")
print("test", file=someFile, encoding="utf-8")

Все это допустимые вызовы объявления Python выше, даже несмотря на то, что в моей реализации установка кодировки или файла без другой может не иметь смысла.

Я знаю, что могу просто проверить оба параметра на наличие недопустимого значения по умолчанию и вызвать исключение во время выполнения всякий раз, когда я нахожу, что установлен только один, но я думаю, что это плохо по нескольким причинам:

  1. Исключение возникает только в том случае, если выполняется недопустимый вызов, поэтому во время тестирования это может не произойти.
  2. Я не могу сказать, что оба параметра необходимы как пара, просто взглянув на объявление или автоматически сгенерированный краткий справочник, не углубляясь в реализацию.
  3. Ни один инструмент анализа кода не смог бы предупредить меня о недопустимом вызове.

Итак, есть ли лучший способ синтаксически указать, что несколько необязательных аргументов сгруппированы вместе?

0
Sorontik 19 Янв 2022 в 18:29
Может быть, вы можете использовать кортеж как один параметр, а затем вызывать индексы отдельно внутри функции?
 – 
Ayush
19 Янв 2022 в 18:30
1
if file is not None and encoding is None: raise TypeError("print() missing 1 argument: 'encoding'?
 – 
Tomerikoo
19 Янв 2022 в 18:34
В Python нет ничего, что мешало бы вам вручную проверить, имеет ли смысл комбинация аргументов. Даже в больших библиотеках вы часто читаете документы, в которых говорится что-то вроде «аргумент X действителен только вместе с аргументом Y» и т. д.
 – 
timgeb
19 Янв 2022 в 18:37
Не уверен, что цель дублируется, но связана: Несколько необязательных аргументов python
 – 
Tomerikoo
19 Янв 2022 в 18:42
Как я писал в своем вопросе, я знаю о такой возможности, но я также перечислил несколько причин, почему я не думаю, что это хорошее решение, и я бы не стал рассматривать другой вопрос как дублировать, потому что другой вопрос сосредоточен на том, как определить «вариант» функции, которая должна выполняться во время выполнения, тогда как я ищу возможность записать такие требования в сжатой синтаксической форме, которая читабельна/очевидна для людей а также автоматические средства проверки кода перед выполнением (во время компиляции в таких языках, как C/C++ или java)
 – 
Sorontik
19 Янв 2022 в 20:09

3 ответа

Python не поддерживает методы перегрузки. И нет действительно хорошего способа имитировать перегруженный дизайн. Лучшее, что вы можете сделать, это использовать операторы if с разными параметрами. Как и вы в своем методе.

1
undercontr 19 Янв 2022 в 18:33
Что ж, разбрасывание каскада условных операторов по всей функции для обеспечения соблюдения неявных правил в отношении аргументов кажется не очень читабельным, очевидным или «красивым» и, следовательно, не звучит для меня очень питонически.
 – 
Sorontik
19 Янв 2022 в 20:18

Я имею в виду, что вы можете заставить один параметр ожидать кортеж в качестве входных данных. Как и idk, 2D-массив может иметь атрибут size, который требует ввода в форме (x, y). Хотя это не избавит вас от необходимости во время выполнения проверять, имеют ли смысл предоставленные значения, не так ли?

0
haxor789 19 Янв 2022 в 18:33
Я подумал об этом, но также было бы очень сложно документировать, какие значения ожидаются внутри кортежа/списка, сколько и в каком порядке, так что это было бы не очень читабельно
 – 
Sorontik
19 Янв 2022 в 19:51

После прочтения других ответов мне кажется, что наиболее простым и читаемым решением было бы написать функцию со всеми обязательными параметрами, а затем добавить вторую функцию-оболочку, которая имеет сокращенный набор параметров, передает эти аргументы в исходная функция включена, а также дает значения по умолчанию для других параметров:

def print(msg, file, encoding):
    # no default values here, so no parameter is optional
    pass

def printout(msg):
    # forward the argument and provide default values for the others
    print(msg, sys.stdout, "")
0
Sorontik 19 Янв 2022 в 20:38