Python: le moyen le plus idiomatique de convertir None en chaîne vide?

156

Quelle est la manière la plus idiomatique de faire ce qui suit?

def xstr(s):
    if s is None:
        return ''
    else:
        return s

s = xstr(a) + xstr(b)

mise à jour: J'incorpore la suggestion de Tryptich d'utiliser str (s), ce qui fait que cette routine fonctionne pour d'autres types en plus des chaînes. Je suis terriblement impressionné par la suggestion lambda de Vinay Sajip, mais je veux garder mon code relativement simple.

def xstr(s):
    if s is None:
        return ''
    else:
        return str(s)
Mark Harrison
la source
7
J'aime votre syntaxe originale. Je pense que c'est déjà assez clair et facile à lire.
GuiSim
1
@GuiSim: Je suis peut-être partial, mais ma réponse se lit presque comme une phrase anglaise normale ...
SilentGhost
1
"Si s vaut None, renvoie une chaîne vide; sinon, renvoie [string of] s." Le code de la question se lit également comme une phrase anglaise normale.
a) Si la chaîne sprovient d'une recherche de dict où la clé n'a pas été trouvée, utilisezdict.get(key, '')
smci
b) Si vous voulez seulement cette conversion de chaîne pour le formatage de sortie (par exemple pour l'impression), alors vous pouvez directement faire '... {}'. format (dict.get (1)) `
smci

Réponses:

94

Si vous voulez réellement que votre fonction se comporte comme la fonction str()intégrée, mais renvoyez une chaîne vide lorsque l'argument est Aucun, procédez comme suit:

def xstr(s):
    if s is None:
        return ''
    return str(s)
Triptyque
la source
Je garde l'autre, mais merci pour le conseil de str (s) afin que plusieurs types puissent être gérés. agréable!
Mark Harrison
12
Ou simplementxstr = lambda s: '' if s is None else str(s)
Michael Mior
2
J'aime taper if not s:au lieu deif s is None
guneysus
6
@guneysus Ce ne sont pas les mêmes: not False == Truemais False is None == False.
Lynn
Merci @Lynn, vous avez raison. J'ai réalisé ma faute. Mais je connais (ou suppose) stoujours un type in str / unicode ou None. Oui, Falsec'est une valeur mais je préfère cette façon qui sauve mon clavier et mes yeux;)
guneysus
143
def xstr(s):
    return '' if s is None else str(s)
SilentGhost
la source
3
Cette syntaxe a été introduite en 2.5; pour les versions antérieures de Python, vous pouvez utiliser return s is not None and s or ''.
Ben Blank
8
Je le retournerais pour souligner le cas le plus important: return s si s n'est pas None else ""
Ber
5
@Ber: Je le garderais tel quel, pour éviter un double négatif.
Nikhil Chelliah
8
Ceci est un bon exemple de la façon dont .. and .. or ..échoue et pourquoi if-else est préféré. Il y a deux bugs subtils s is not None and s or ''.
1
return '' if not s else str(s)
Iqbal
110

Le plus court serait probablement str(s or '')

Parce que None est False et que "x or y" renvoie y si x est false. Voir Opérateurs booléens pour une explication détaillée. C'est court, mais pas très explicite.

Dorvak
la source
1
c'est tellement génial, merci! Jamais pensé à utiliser de orcette façon
user25064
15
Cela ne fonctionne pas si la valeur sest 0, False ou toute valeur
falsifiée
4
Eh bien, ce n'est pas mentionné dans l'exigence de l'op, donc je ne vois pas votre point ici.
dorvak
2
@dorvak L'OP est assez explicite sur l'exigence selon laquelle la sortie doit être ''iff s is None. Toutes les autres entrées doivent retourner s(ou str(s)dans la demande révisée).
StvnW
2
@fortea: cela ne fonctionnera pas. Si sest None, le résultat de xstr()devrait être une chaîne vide, mais str(None)donne la chaîne "None", qui est ce qui est retourné (puisque la chaîne "None"n'est pas une valeur fausse.
dreamlax
97

Si vous savez que la valeur sera toujours une chaîne ou Aucune:

xstr = lambda s: s or ""

print xstr("a") + xstr("b") # -> 'ab'
print xstr("a") + xstr(None) # -> 'a'
print xstr(None) + xstr("b") # -> 'b'
print xstr(None) + xstr(None) # -> ''
Vinay Sajip
la source
1
de loin le plus pythonique. Utilise le fait que python traite None, une liste vide, une chaîne vide, 0, etc. comme faux. Utilise également le fait que l'instruction ou renvoie le premier élément qui est vrai ou le dernier élément donné au ou (ou aux groupes de ors). Cela utilise également des fonctions lambda. Je vous donnerais +10 mais évidemment cela ne me laissera pas.
Matt
11
Cela convertira 0 et False (et tout ce qui est évalué à False lorsqu'il est passé à bool ())
Arkady
9
Je ne pense pas que ce soit "de loin le plus pythonique". C'est un idiome courant dans d'autres langages, et je ne pense pas qu'il soit mal de l'utiliser en Python, mais les expressions conditionnelles ont été introduites précisément pour éviter des trucs comme celui-ci.
Roberto Bonvallet
2
Cela fait [], {}etc. donnent le même résultat que None, non désiré. xstr(False), en particulier, devrait être "False"au lieu de "". Abuser des lambdas est un mauvais exemple, utilisez si def xstr(s): return s or ""vous voulez tout garder sur une seule ligne.
5
Notez que j'ai qualifié ma réponse au départ par "Si vous savez que la valeur sera toujours soit une chaîne, soit Aucune".
Vinay Sajip
59

return s or '' fonctionnera très bien pour votre problème déclaré!

Alex Martelli
la source
4
Il convient de noter que cela donnera un résultat différent lorsque s est False ou 0 (ce qui n'est pas la question de chaîne d'origine, mais la question mise à jour.)
Oddthinking
@Oddthinking s = Falseou s = 0serait très probablement un cas limite dans son utilisation et pourrait être facilement atténué en l'écrivant commereturn str(s or '')
Willem van Ketwich
@WillemvanKetwich: Cela pose exactement le même problème: s (False) doit renvoyer «False», pas «». s (0) doit renvoyer «0» et non «». De même pour un objet qui définit __bool__ ou __nonzero__.
Oddthinking
@Oddthinking Je vois votre point de vue. Dans tous les cas, s'il est utilisé exclusivement pour des objets string tels que dans la question de l'OP, cela ne devrait pas être un problème.
Willem van Ketwich
@WillemvanKetwich: Jetez un œil à la question mise à jour et à la mise en garde dans mon commentaire - cela a été couvert,
Oddthinking
14
def xstr(s):
   return s or ""
Krystian Cybulski
la source
4
Ce rendement ''pour 0, [], {}, Falseet faux comme les valeurs, qui ne sont pas ce que l'affiche a demandé.
StvnW
1
juste mettre str ([...]) autour de s: def xstr(s): return str(s) or ""
Federico Simonetta
8

Mode fonctionnel (one-liner)

xstr = lambda s: '' if s is None else s
Dario
la source
1
"def xstr (s): return '' if s is None else s" est également en ligne, python n'est pas aussi strict avec les espaces après tout
SilentGhost
2
Ce n'est pas un vrai one-liner, c'est juste écrit en une seule ligne g
Dario
1
dans quel sens ce n'est pas un vrai onliner? vérifiez dans votre interpréteur - ce n'est pas une erreur de syntaxe. à toutes fins utiles, c'est bien réel que lambda ^ _ ^
SilentGhost
2
PEP 8 espèces que vous devriez utiliser def au lieu d'assigner lambda à une variable. Le seul véritable avantage de lambda est que vous pouvez écrire en tant que partie de l'expression (en passant à une autre fonction par exemple) et cet avantage est perdu dans un code comme celui-ci. J'avais l'habitude de faire cela aussi, jusqu'à ce que je remarque que def peut être écrit sur une seule ligne, puis PEP 8 m'a montré la voie à suivre. Suivez TOUJOURS les dieux python.
Guy
8

Un bon plan pour faire cette construction sur certaines des autres réponses:

s = (lambda v: v or '')(a) + (lambda v: v or '')(b)

ou même simplement:

s = (a or '') + (b or '')
Willem van Ketwich
la source
Pourquoi même mentionner (lambda v: v or '')?
Tvde1
Pourquoi pas? 2 conseils pour le prix d'un! 😀
Willem van Ketwich
1
Veuillez noter qu'une Falseliste vide sera également transformée en «».
Nik O'Lai
idem pour 0, etc.
Walter Tross
6
def xstr(s):
    return {None:''}.get(s, s)
tobidope
la source
Je pense que c'est plutôt pythonique - que diriez-vous de celui-ci: "xstr = lambda s: {None: ''}. Get (s, s)" - réduit le tout à une seule ligne.
Juergen
14
Inutilement lent (construction et recherche de dict supplémentaires) et plus difficile à lire. Assez impythonique.
Triptyque
Vous avez raison. C'est plutôt perlish mais cela évite un saut conditionnel en bytecode python.
tobidope
4
L'appel de la fonction get () implique au moins un saut conditionnel supplémentaire.
Triptyque
1
Je ne pourrais pas dire ce que cela devrait faire sans connaître la question ou sans lever les yeux get.
Dario
5

J'utilise la fonction max:

max(None, '')  #Returns blank
max("Hello",'') #Returns Hello

Fonctionne comme un charme;) Mettez simplement votre chaîne dans le premier paramètre de la fonction.

Radtek
la source
5
Cela fonctionne car «str»> «NoneType» et est spécifique à CPython. Extrait du manuel : "Les objets de types différents à l'exception des nombres sont classés par leur nom de type". De plus, cela ne fonctionnera pas dans Python 3000, car la comparaison inter-type n'est plus autorisée (TypeError: unorderable types: str ()> NoneType ()). Voir Comment Python compare-t-il string et int?
plok
Bon à savoir merci, donc ce n'est pas une bonne idée d'aller de l'avant avec du code compatible python 3.x.
radtek
4

Variante sur ce qui précède si vous devez être compatible avec Python 2.4

xstr = lambda s: s is not None and s or ''
Peter Ericson
la source
2

S'il s'agit de formater des chaînes, vous pouvez effectuer les opérations suivantes:

from string import Formatter

class NoneAsEmptyFormatter(Formatter):
    def get_value(self, key, args, kwargs):
        v = super().get_value(key, args, kwargs)
        return '' if v is None else v

fmt = NoneAsEmptyFormatter()
s = fmt.format('{}{}', a, b)
Maciek
la source
1
def xstr(s):
    return s if s else ''

s = "%s%s" % (xstr(a), xstr(b))
Phillc
la source
5
Cela renverra une chaîne vide pour toutes les valeurs de type faux, ce qui n'est pas ce que l'affiche a demandé.
Triptyque
1

Nous pouvons toujours éviter la conversion de type dans les scénarios expliqués ci-dessous.

customer = "John"
name = str(customer)
if name is None
   print "Name is blank"
else: 
   print "Customer name : " + name

Dans l'exemple ci-dessus, dans le cas où la valeur de la variable client est None, elle est ensuite castée tout en étant affectée à 'nom'. La comparaison dans la clause «if» échouera toujours.

customer = "John" # even though its None still it will work properly.
name = customer
if name is None
   print "Name is blank"
else: 
   print "Customer name : " + str(name)

L'exemple ci-dessus fonctionnera correctement. De tels scénarios sont très courants lorsque les valeurs sont extraites de l'URL, du JSON ou du XML ou même que les valeurs nécessitent une conversion de type supplémentaire pour toute manipulation.

Sonar Pralhad Narsinh
la source
0

Utilisez l'évaluation des courts-circuits:

s = a or '' + b or ''

Puisque + n'est pas une très bonne opération sur les chaînes, mieux vaut utiliser les chaînes de format:

s = "%s%s" % (a or '', b or '')
Sharjeel
la source
2
Cela convertira également «a» en chaînes vides pour toutes les valeurs de type faux, pas seulement pour Aucune. Par exemple, les tuples vides, les listes et les dictionnaires seront convertis en chaînes vides, ce qui n'est pas ce que l'OP a spécifié.
Triptyque
+est un excellent opérateur pour deux cordes. C'est lorsque vous essayez de vous en servir pour rejoindre des dizaines que vous rencontrez des difficultés. Pour deux, ce sera probablement plus rapide que les autres options; de toute façon, c'est dans le bruit.
kquinn le
+1 pour moi car c'est exactement ce dont j'ai besoin dans mon cas: lambda ou une fonction pour remplacer un seul opérateur ( or) me semble un peu exagéré ... Je n'ai pas de cas d'autres valeurs fausses - soit str ou None. Mis à part le commentaire sur l' +opérateur, qui pourrait dépendre d'un scénario spécifique et nécessiter un benchmarking, cette réponse ne mérite pas un -1
urbain du
-3

Utilisez la chaîne F si vous utilisez python v3.7

xstr = F"{s}"
user781486
la source
1
C'est faux et renvoie la chaîne 'None'si sc'est None.
Lawrence