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