Условное расширение аргумента при вызове функции

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

n_file = []
For line in file.getlines():
    n_file.append( line.replace(
            *("foo", "bar") if False else
            *("baz", "bam") if True else
            # ...
            *("", "") # no replacement
    ))
new_file.write(n_file)  

Но я столкнулся с проблемой, которую не понимаю. Проблемы - это звездочки. Всякий раз, когда звездочки стоят не на первой позиции функции replace(), это дает мне синтаксическую ошибку, и я совершенно не понимаю, почему.

Вы можете попробовать это сами. То же самое в Python 2 или 3.

def tf(a,b): print( str(a) +" "+ str(b) )

tf( *(1,1) if False else (2,2) if False else (3,3) )
# prints '3 3' as expec... intended

tf( *(1,1) if False else *(2,2) if False else *(3,3) )
# invalid syntax         ^

tf( (1,1) if False else (2,2) if False else (3,3) )
# missing 1 required positional argument: 'b'

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

С уважением.

пс. Это мой первый вопрос, и я не уверен, подходит ли заголовок (или как конкретно назвать это if-thingy, происходящее в replace()-args). Поиск ответов об этой проблеме был трудным, поэтому, если у вас есть лучшие предложения по названию или тегу, сообщите мне.


person 6EQUJ5    schedule 13.11.2017    source источник
comment
Может быть полезен будущим читателям этой темы на основе вопроса в заголовке: stackoverflow.com/questions/19525530/   -  person Snidhi Sofpro    schedule 30.04.2019


Ответы (1)


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

tf( *((1,1) if False else (2,2) if False else (3,3)) ) #-> 3 3

Более конкретно:

...
n_file.append( line.replace(
            **(("foo", "bar") if False else
               ("baz", "bam") if True else
                ...
               ("", "")) # no replacement
    ))

OTOH, код становится совершенно нечитаемым, когда вы таким образом каскадируете троичные. Было бы более читабельно использовать ванильное предложение if, присвоить переменной, а затем распаковать переменную.

person Moses Koledoye    schedule 13.11.2017
comment
Спасибо, Моисей Коледой. - person 6EQUJ5; 13.11.2017