Например, у меня есть основной метод, который возвращает список перестановок.
Теперь я понимаю, что в своем текущем состоянии этот код не будет выполняться, потому что вторые elements
не определены, но есть ли и элегантный способ выполнить то, что я пытаюсь сделать здесь? Если это все еще не ясно, я хочу сделать значение setLength
по умолчанию равным первому переданному аргументу. Спасибо.
Ответ 4
Ответ 1:
Решение сверху выглядит так:
def cast_to_string_concat(a, b, c=None):
c = a if c is None else c
return str(a) + str(b) + str(c)
Хотя такой подход решит множество потенциальных проблем (и, возможно, ваших)! Я хотел написать функцию, в которой возможный ввод для переменной " c
" действительно является единственным None
, поэтому мне пришлось больше копаться.
Чтобы объяснить это далее, вызовите функцию со следующими переменными:
A='A'
B='B'
my_var = None
Урожайность:
cast_to_string_concat(A, B, my_var):
>>>'ABA'
В то время как пользователь может ожидать, что, поскольку он вызвал функцию с тремя переменными, он должен напечатать три переменные, например:
cast_to_string_concat(A, B, my_var):
>>> 'ABNone' # simulated and expected outcome
Таким образом, эта реализация игнорирует третью переменную, даже когда она была объявлена, поэтому это означает, что функция больше не может определять, была ли определена переменная " c
".
Таким образом, для моего варианта использования значение по умолчанию None
не совсем подходит.
Для ответов, которые предлагают это решение, прочитайте эти:
Но если это не работает для вас, то, возможно, продолжайте читать!
Комментарий в первой ссылке выше упоминает использование _sentinel
определенного object()
.
Таким образом, это решение исключает использование None и заменяет его на object()
посредством использования подразумеваемого частного sentinel
.
Ответ 2:
_sentinel = object()
def cast_to_string_concat(a, b, c=_sentinel):
c = a if c == _sentinel else c
return str(a) + str(b) + str(c)
A='A'
B='B'
C='C'
cast_to_string_append(A,B,C)
>>> 'ABC'
cast_to_string_concat(A,B)
>>> 'ABA'
Так что это довольно круто! Это правильно обрабатывает вышеупомянутый крайний случай! Посмотреть на себя:
A='A'
B='B'
C = None
cast_to_string_concat(A, B, C)
>>> 'ABNone'
Итак, мы закончили, верно? Есть ли вероятный способ, что это может не сработать? Хм... наверное нет! Но я сказал, что это был ответ из трех частей, так что вперед! ;)
Для полноты картины, давайте представим, что наша программа работает в пространстве, где каждый возможный сценарий действительно возможен. (Это может быть неоправданным предположением, но я полагаю, что можно получить значение _sentinel
с достаточным количеством информации об архитектуре компьютера и реализации выбора объекта. Итак, если вы хотите, давайте предположим, что это действительно так. возможно, и давайте представим, что мы решили проверить эту гипотезу, ссылающуюся на _sentinel
как определено выше.
_sentinel = object()
def cast_to_string_concat(a, b, c=_sentinel):
c = a if c == _sentinel else c
return str(a) + str(b) + str(c)
A='A'
B='B'
S = _sentinel
cast_to_string_append(A,B,S)
>>> 'ABA'
Подождите минуту! Я ввел три аргумента, поэтому я должен увидеть объединение строк из трех из них вместе!
* очередь на въезд в страну непредвиденных последствий *
Я имею в виду, не на самом деле. Ответ: "Это ничтожно малый край дела !!" или его подобие совершенно оправдано.
И это чувство правильно! В этом случае (и, вероятно, в большинстве случаев) об этом действительно не стоит беспокоиться!
Но стоит ли беспокоиться об этом или если вы просто хотите получить математическое удовлетворение от устранения всех крайних случаев, о которых вы знаете... вперед!
Упражнение, оставленное читателю:
Отказываясь от этой техники, вы можете прямо утверждать c=object()
, однако, честно говоря, я не получил такой способ работать на меня. Мое исследование показало, что c == object()
- False
, а str(c) == str(object())
- также False
, и именно поэтому я использую реализацию от Martin Pieters.
Хорошо, после этого долгого упражнения мы вернулись!
Напомним, что цель состоит в том, чтобы написать функцию, которая потенциально может иметь n
входов, и только если одна переменная не указана - тогда вы скопируете другую переменную в положение i
.
Вместо определения переменной по умолчанию, что если мы изменим подход, чтобы разрешить произвольное количество переменных?
Поэтому, если вы ищете решение, которое не ставит под угрозу потенциальные входные данные, где допустимым входным значением может быть None
, object()
или _sentinel
... тогда (и только тогда), на данный момент, я думаю, мое решение будет полезно. Источником вдохновения для этой техники послужила вторая часть ответа Джона Клемента.
Ответ 3:
Мое решение этой проблемы состоит в том, чтобы изменить наименование этой функции и обернуть эту функцию функцией предыдущего соглашения об именах, но вместо переменных мы используем *args
. Затем вы определяете исходную функцию в локальной области (с новым именем) и допускаете только те несколько возможностей, которые вам нужны.
По шагам:
- Переименуйте функцию в нечто подобное
- Удалите настройки по умолчанию для вашего необязательного параметра
- Начните создавать новую функцию чуть выше и добавьте оригинальную функцию в.
def cast_to_string_concat(*args):
- Определите арность вашей функции - (я нашел это слово в моем поиске... это число параметров, переданных в данную функцию)
- Используйте внутри себя инструкцию case, которая определяет, правильно ли вы ввели правильное количество переменных, и внесите соответствующие коррективы!
def cast_to_string_append(*args):
def string_append(a, b, c):
# this is the original function, it is only called within the wrapper
return str(a) + str(b) + str(c)
if len(args) == 2:
# if two arguments, then set the third to be the first
return string_append(*args, args[0])
elif len(args) == 3:
# if three arguments, then call the function as written
return string_append(*args)
else:
raise Exception(f'Function: cast_to_string_append() accepts two or three arguments, and you entered {len(args)}.')
# instantiation
A='A'
B='B'
C='C'
D='D'
_sentinel = object()
S = _sentinel
N = None
""" Answer 3 Testing """
# two variables
cast_to_string_append(A,B)
>>> 'ABA'
# three variables
cast_to_string_append(A,B,C)
>>> 'ABC'
# three variables, one is _sentinel
cast_to_string_append(A,B,S)
>>>'AB<object object at 0x10c56f560>'
# three variables, one is None
cast_to_string_append(A,B,N)
>>>'ABNone'
# one variable
cast_to_string_append(A)
>>>Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> File "<input>", line 13, in cast_to_string_append
>>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 1.
# four variables
cast_to_string_append(A,B,C,D)
>>>Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> File "<input>", line 13, in cast_to_string_append
>>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 4.
# ten variables
cast_to_string_append(0,1,2,3,4,5,6,7,8,9)
>>>Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> File "<input>", line 13, in cast_to_string_append
>>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 10.
# no variables
cast_to_string_append()
>>>Traceback (most recent call last):
>>> File "<input>", line 1, in <module>
>>> File "<input>", line 13, in cast_to_string_append
>>>Exception: Function: cast_to_string_append() accepts two or three arguments, and you entered 0.
""" End Answer 3 Testing """
Итак, в итоге:
- Ответ 1 - самый простой ответ и работает в большинстве случаев.
def cast_to_string_concat(a, b, c=None):
c = a if c is None else c
return str(a) + str(b) + str(c)
- Ответ 2 - используйте, если
None
фактически не обозначает пустой параметр, переключаясь на object()
через _sentinel
.
_sentinel = object()
def cast_to_string_concat(a, b, c=_sentinel):
c = a if c == _sentinel else c
return str(a) + str(b) + str(c)
- Ответ 3 ищет общее решение, использующее функцию-обертку с произвольной арностью, используя
*args
, и обрабатывает допустимые случаи внутри:
def cast_to_string_append(*args):
def string_append(a, b, c):
# this is the original function, it is only called within the wrapper
return str(a) + str(b) + str(c)
if len(args) == 2:
# if two arguments, then set the third to be the first
return string_append(*args, args[0])
elif len(args) == 3:
# if three arguments, then call the function as written
return string_append(*args)
else:
raise Exception(f'Function: cast_to_string_append() accepts two or three arguments, and you entered {len(args)}.')
Используйте то, что работает для вас! Но для меня я буду использовать вариант 3;)