Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Opérateur ternaire

3 réponses
Avatar
Pierre Maurette
Bonjour,

Au fur et à mesure que je repasse sur mon code en le pythonisant.
D'abord, c'est amusant. Ensuite, le code y gagne en lisibilité globale.
Et justement, certains problèmes apparaissent alors. Je suis adepte
compulsif de l'opérateur ternaire en C, Java, Php, etc. Son absence en
Python se traduit par des lourdeurs dans le code. A tel point que
spontanément j'avais fait une méthode:
def select_level(self, cond, leveltrue, levelfalse):
if cond:
return leveltrue
else:
return levelfalse

Je suis en version 2.5 sous Windows, mais j'ai une Ubuntu avec une
2.4.4, que je peux sans doute upgrader. Donc j'hésite sur la marche à
suivre.

J'avais par exemple:
if (None if (item == ligne[-1]):
var = None
else:
var = params[item][last_position])

(je sais, les parenthèses sont inutiles, comme dans les autres
exemples)
Bien entendu, l'exemple d'une affectation simple n'est pas le plus
parlant, je veux utiliser l'opérateur ternaire dans des expressions,
des appels de fonctions, voire inclus dans lui-même.


J'ai la forme 2.5 et supérieures:
var = (None if (item == ligne[-1]) else params[item][last_position])

Pour le reste, si je veux simuler au mieux l'opérateur ternaire, les
solutions trouvées sur la toile sont souvent foireuse. J'en ai une
inspirée de la FAQ, basée sur une fonction à placer n'importe où:

from inspect import isfunction

def tern(cond, on_true, on_false):
if cond:
if not isfunction(on_true): return on_true
else: return apply(on_true)
else:
if not isfunction(on_false): return on_false
else: return apply(on_false)

L'appel se fait ainsi:
var = tern(item == ligne[-1], lambda: None, lambda:
params[item][last_position])

Sans fonction, j'ai par exemple:
var = ((lambda: None, lambda: params[item][last_position])[item !=
ligne[-1]])()

J'ai de nombreuses variantes avec et sans fonction, à base de eval ou
même apply.

Questions:

- Comment faites-vous, si vous faites quelque chose ?
- La version 2.4 est-elle dominante ?

Merci d'avance et bonne fin de week-end...

--
Pierre Maurette

3 réponses

Avatar
Pierre Maurette

[...]

Pour Python < 2.5, Un idiome très courant est le dispatch sur un tuple ou un
dict:

# tuple dispatch
result = (iffalse, ifftrue)[cond]

# dict dispatch:

result = {False:iffalse, True:ifftrue}[cond]


Merci. Attention, ces deux formes ne simulent qu'approximativement
l'opérateur ternaire. Par exemple (a[-1], a[i])[i < len(a)] plantera.
En revanche, ((lambda: a[-1], lambda: a[i])[i < len(a)])() doit le
faire.

Mon message était un peu confus, mais la solution du tuple avec lambda
est une de celles que je proposais, et que j'ai adoptée. Sans le lambda
pour les cas simples.
En attendant de faire un choix de version de Python: j'ai trois 2.5
(XP, 2000 et Suse 10.2) pour une 2.4 (Ubuntu 6.10). Je vais voir si je
peux upgrader de façon "normale", Synaptic dépôts standards.

--
Pierre Maurette

Avatar
Bruno Desthuilliers
Bonjour,

Au fur et à mesure que je repasse sur mon code en le pythonisant.
D'abord, c'est amusant. Ensuite, le code y gagne en lisibilité globale.
Et justement, certains problèmes apparaissent alors. Je suis adepte
compulsif de l'opérateur ternaire en C, Java, Php, etc. Son absence en
Python se traduit par des lourdeurs dans le code.


NB : tu le sais déjà, mais d'autres peut-être pas : cet opérateur est
une des nouveautés de la 2.5

A tel point que
spontanément j'avais fait une méthode:
def select_level(self, cond, leveltrue, levelfalse):
if cond:
return leveltrue
else:
return levelfalse


Pour Python < 2.5, Un idiome très courant est le dispatch sur un tuple
ou un dict:

# tuple dispatch
result = (iffalse, ifftrue)[cond]

# dict dispatch:

result = {False:iffalse, True:ifftrue}[cond]

Avatar
Bruno Desthuilliers

[...]

Pour Python < 2.5, Un idiome très courant est le dispatch sur un tuple
ou un dict:

# tuple dispatch
result = (iffalse, ifftrue)[cond]

# dict dispatch:

result = {False:iffalse, True:ifftrue}[cond]



Merci. Attention, ces deux formes ne simulent qu'approximativement
l'opérateur ternaire. Par exemple (a[-1], a[i])[i < len(a)] plantera. En
revanche, ((lambda: a[-1], lambda: a[i])[i < len(a)])() doit le faire.


Oeuf corse. Mais heureusement que l'opérateur ternaire arrive, parce que
ça devient un poil cryptique.

Accessoirement, un autre workaround courant est:

result = cond and ifftrue or iffalse

Le gotcha est que si ifftrue est évalué à une valeur valant False dans
un contexte booléen, c'est iffalse qui sera retourné - sans préjudice de
l'évaluation de ifftrue (et donc de ses éventuels effets de bord).

Mon message était un peu confus,


Merci de me rassurer sur ce point - je l'ai relu une paire de fois, et
je me suis dit que je ne devais pas avoir encore eu ma dose de caféine !-)

mais la solution du tuple avec lambda
est une de celles que je proposais, et que j'ai adoptée. Sans le lambda
pour les cas simples.
En attendant de faire un choix de version de Python: j'ai trois 2.5 (XP,
2000 et Suse 10.2) pour une 2.4 (Ubuntu 6.10). Je vais voir si je peux
upgrader de façon "normale", Synaptic dépôts standards.



Je ne sais pas ce que ça donner. J'ai cru voire que pas mal d'extensions
n'étaient pas encore dispos pour Python 2.5.