тройная итерация Python с пониманием списка

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

c = 0  
list1 = [4, 6, 7, 3, 4, 5, 3, 4]  
c += 1 if 4 == i for i in list1 else 0  

Более практический пример:

strList = ['Ulis', 'Tolus', 'Utah', 'Ralf', 'Chair']
counter = 0  
counter += 1 if True == i.startswith('U') for i in strList else 0  
return counter  

person Jack J    schedule 01.02.2013    source источник


Ответы (3)


Ваш «практический пример» записывается как:

>>> strList = ['Ulis', 'Tolus', 'Utah', 'Ralf', 'Chair']
>>> sum(1 for el in strList if el.startswith('U'))
2

Ваш другой пример (если я правильно понимаю):

>>> list1 = [4, 6, 7, 3, 4, 5, 3, 4]
>>> list1.count(4)
3

(или просто адаптируйте пример strList, но ничего плохого в использовании встроенных методов)

person Jon Clements♦    schedule 01.02.2013
comment
Это немного неряшливо, но sum() примет значение bool, преобразуя False в 0 и True в 1. Таким образом, этот код также будет работать: sum(el.startswith('U') for el in strList) - person steveha; 01.02.2013
comment
@steveha: python bool является подклассом int (по историческим причинам); это не sum преобразование, а просто целочисленная арифметика; 0 + True == 1. - person Martijn Pieters; 01.02.2013
comment
@MartijnPieters действительно - --True + --False всегда хорошо :) - person Jon Clements♦; 01.02.2013
comment
@MartijnPieters, пока они не стали ключевыми словами, а не синглтонами :) - person Jon Clements♦; 01.02.2013
comment
@MartijnPieters, хорошо, я мог бы сформулировать это лучше. - person steveha; 01.02.2013

@Jon Clements дал вам отличный ответ: как решить проблему, используя идиому Python. Если другие программисты Python посмотрят на его код, они сразу его поймут. Это правильный способ сделать это с помощью Python.

Чтобы ответить на ваш актуальный вопрос: нет, это не работает. Тернарный оператор имеет следующую форму:

expr1 if condition else expr2

condition должно быть чем-то, что оценивается как bool. Тернарное выражение выбирает одно из expr1 и expr2 и все.

Когда я попробовал такое выражение, как c += 1 if condition else 0, я был удивлен, что оно сработало, и отметил это в первой версии этого ответа. @TokenMacGuy указал, что на самом деле происходило следующее:

c += (1 if condition else 0)

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

c += 1 if condition else x += 2  # syntax error on x += 2

Это связано с тем, что Python не считает оператор присваивания выражением.

Вы не можете сделать эту распространенную ошибку:

if x = 3:  # syntax error!  Cannot put assignment statement here
    print("x: {}".format(x))

Здесь программист, вероятно, хотел x == 3 для проверки значения, но набрал x = 3. Python защищает от этой ошибки, не рассматривая присваивание как выражение.

Вы не можете сделать это по ошибке, и вы не можете сделать это намеренно.

person steveha    schedule 01.02.2013
comment
c += 1 - это не выражение, это присваивание. Оператор будет заключен в скобки как c += (truthy if cond else falsey). Вы не можете не использовать c += 1 где-либо еще, например, truthy if cond else c += 1 заключает в скобки (truthy if cond else c) += 1, что отклонено, потому что вы не можете присвоить условное выражение. - person SingleNegationElimination; 01.02.2013
comment
Ааа, ты прав! Я был удивлен, что это сработало, но я недостаточно думал о том, что происходит на самом деле. Что ж, пора отредактировать мой ответ. Спасибо, что поправили меня. - person steveha; 01.02.2013

Вы также можете выбрать свои элементы с пониманием списка и взять количество элементов в списке.

strList = ['Ulis', 'Tolus', 'Utah', 'Ralf', 'Chair']
len([k for k in strList if k.startswith('U')])
person kiriloff    schedule 01.02.2013
comment
Если вы хотите использовать len(), вы должны прибегнуть к пониманию списка, не так ли? или, по крайней мере, это способ сделать это - person kiriloff; 01.02.2013
comment
@antitrust Я думаю, что @Jon говорит, что sum(generator) предпочтительнее len(list), потому что вам не нужно составлять список, а затем считать его - person Alex L; 01.02.2013
comment
@антимонопольный, т.е. sum(1 for k in strList if k.startswith('U')) - person Alex L; 01.02.2013
comment
@AlexL Да - если вам не нужен список после - не материализуйте его ради него - person Jon Clements♦; 01.02.2013