Python: najbardziej idiomatyczny sposób konwersji None na pusty ciąg?

156

Jaki jest najbardziej idiomatyczny sposób na wykonanie następujących czynności?

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

s = xstr(a) + xstr(b)

aktualizacja: Włączam sugestię Trypticha, aby użyć str (s), co sprawia, że ​​ta rutynowa działa dla innych typów oprócz ciągów. Jestem pod ogromnym wrażeniem sugestii lambda Vinaya Sajipa, ale chcę, aby mój kod był stosunkowo prosty.

def xstr(s):
    if s is None:
        return ''
    else:
        return str(s)
Mark Harrison
źródło
7
Podoba mi się twoja oryginalna składnia. Myślę, że jest już dość jasny i łatwy do odczytania.
GuiSim
1
@GuiSim: Mogę być stronniczy, ale moja odpowiedź brzmi prawie jak normalne angielskie zdanie ...
SilentGhost
1
„Jeśli s ma wartość Brak, zwróć pusty ciąg; w przeciwnym razie zwróć [ciąg] s.” Kod z pytania również brzmi jak normalne angielskie zdanie.
a) Jeśli ciąg spochodzi z wyszukiwaniadict.get(key, '')
dyktowania, w
b) Jeśli chcesz tę konwersję ciągów tylko do formatowania wyjściowego (np. do drukowania), możesz bezpośrednio wykonać '... {}'. format (dict.get (1)) `
smci

Odpowiedzi:

94

Jeśli faktycznie chcesz, aby Twoja funkcja zachowywała się jak funkcja str()wbudowana, ale zwracała pusty ciąg, gdy argument ma wartość None, zrób to:

def xstr(s):
    if s is None:
        return ''
    return str(s)
Tryptyk
źródło
Zatrzymuję inne, ale dzięki za wskazówkę str (s), więc można obsłużyć wiele typów. miły!
Mark Harrison
11
Lub po prostuxstr = lambda s: '' if s is None else str(s)
Michael Mior
2
Uwielbiam pisać if not s:zamiastif s is None
guneysus
6
@guneysus Nie są takie same: not False == Trueale False is None == False.
Lynn,
Dzięki @Lynn masz rację. Zrozumiałem swoją winę. Ale wiem (lub zakładam) szawsze typ in str / unicode lub None. Tak, Falseto wartość, ale wolę taki sposób, który oszczędza klawiaturę i oczy;)
guneysus
143
def xstr(s):
    return '' if s is None else str(s)
SilentGhost
źródło
3
Ta składnia została wprowadzona w 2.5; we wcześniejszych wersjach Pythona można użyć return s is not None and s or ''.
Ben Blank,
8
Odwróciłbym to, aby podkreślić bardziej powszechny przypadek: zwraca s, jeśli s jest inny niż Nikt inny ""
Ber,
5
@Ber: Zachowałbym to tak, jak jest, aby uniknąć podwójnego negatywu.
Nikhil Chelliah
8
To jest dobry przykład tego, jak .. and .. or ..zawodzi i dlaczego preferowana jest opcja if-else. Istnieją dwa subtelne błędy s is not None and s or ''.
1
return '' if not s else str(s)
Iqbal
110

Prawdopodobnie najkrótszy str(s or '')

Ponieważ None jest fałszem, a „x lub y” zwraca y, jeśli x jest fałszywe. Aby uzyskać szczegółowe wyjaśnienie, zobacz Operatory boolowskie . Jest krótki, ale niezbyt wyraźny.

dorvak
źródło
1
to wspaniale, dziękuję! Nigdy nie myślałem o używaniu w orten sposób
user25064
15
To nie działa, jeśli swynosi 0, False lub jakakolwiek fałszywa wartość
wisbucky
4
Cóż, nie ma o tym wzmianki w wymaganiach operatora, więc nie widzę tutaj twojego punktu widzenia.
dorvak
2
@dorvak W OP dość jasno sprecyzowano, że dane wyjściowe powinny mieć wartość ''iff s is None. Wszystkie inne dane wejściowe powinny zostać zwrócone s(lub str(s)w poprawionym żądaniu).
StvnW
2
@fortea: to nie zadziała. Jeśli stak None, wynikiem xstr()powinien być pusty ciąg, ale str(None)daje ciąg "None", który jest zwracany (ponieważ ciąg "None"nie jest fałszywą wartością.
dreamlax
97

Jeśli wiesz, że wartość zawsze będzie ciągiem lub None:

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
źródło
1
zdecydowanie najbardziej pytoniczny. Używa faktu, że Python traktuje None, pustą listę, pusty łańcuch, 0 itd. Jako fałsz. Wykorzystuje również fakt, że instrukcja lub zwraca pierwszy element, który jest prawdziwy, lub ostatni element podany elementowi lub (lub grupom ors). Również to wykorzystuje funkcje lambda. Dałbym ci +10, ale oczywiście mi nie pozwoli.
Matt
11
Spowoduje to przekonwertowanie wartości 0 i False (i wszystkiego innego, co po przekazaniu do bool ())
daje
9
Nie sądzę, że jest to „zdecydowanie najbardziej pytoniczne”. Jest to powszechny idiom w innych językach i nie sądzę, aby używanie go w Pythonie było niewłaściwe, ale wyrażenia warunkowe zostały wprowadzone właśnie w celu uniknięcia takich sztuczek.
Roberto Bonvallet
2
To sprawia [], że {}itp. Dają taki sam wynik jak None, co nie jest pożądane. xstr(False)w szczególności powinno być "False"zamiast "". Nadużywanie lambd to kiepski przykład, użyj def xstr(s): return s or ""ir, jeśli chcesz, aby wszystko było w jednej linii.
5
Zwróć uwagę, że na początku określiłem moją odpowiedź słowami „Jeśli wiesz, że wartością zawsze będzie ciąg znaków lub Brak”.
Vinay Sajip
59

return s or '' będzie działać dobrze dla podanego problemu!

Alex Martelli
źródło
4
Warto zauważyć, że da to inny wynik, gdy s jest fałszywe lub 0 (co nie jest oryginalnym pytaniem typu string, ale zaktualizowanym).
Oddthinking
@Oddthinking s = Falselub s = 0najprawdopodobniej byłby skrajnym przypadkiem w jego użyciu i można go łatwo złagodzić, pisząc to jakoreturn str(s or '')
Willem van Ketwich
@WillemvanKetwich: To ma dokładnie ten sam problem: s (False) powinno zwracać „False”, a nie „”. s (0) powinno zwracać „0”, a nie „”. Podobnie jest w przypadku obiektu, który definiuje __bool__ lub __nonzero__.
Dziwne myślenie
@Oddthinking Rozumiem twój punkt widzenia. W każdym razie, jeśli jest używany wyłącznie do obiektów łańcuchowych, takich jak w pytaniu PO, nie powinno to stanowić problemu.
Willem van Ketwich
@WillemvanKetwich: Spójrz na zaktualizowane pytanie i zastrzeżenie w moim komentarzu - zostało to omówione,
Oddthinking
14
def xstr(s):
   return s or ""
Krystian Cybulski
źródło
4
Spowoduje to powrót ''do 0, [], {}, Falsei fałszywie jak wartości, która nie ma co prosić o plakat.
StvnW
1
po prostu umieść str ([...]) wokół s: def xstr(s): return str(s) or ""
Federico Simonetta
8

Funkcjonalny sposób (jedna linijka)

xstr = lambda s: '' if s is None else s
Dario
źródło
1
"def xstr (s): return '' if s is None else s" też jest on-linerem, Python nie jest jednak tak rygorystyczny z białymi
znakami
2
To nie jest prawdziwa jedna linijka, jest po prostu napisana w jednej linii g
Dario
1
w jakim sensie to nie jest prawdziwy onliner? sprawdź swój interpreter - to nie jest błąd składni. pod każdym względem jest bardziej realne niż lambda ^ _ ^
SilentGhost
2
PEP 8, których powinieneś używać def zamiast przypisywać lambdę do zmiennej. Jedyną prawdziwą zaletą lambdy jest to, że możesz pisać jako część wyrażenia (na przykład przekazując do innej funkcji) i ta zaleta jest tracona w kodzie takim jak ten. Ja też to robiłem, dopóki nie zauważyłem, że def można zapisać w jednej linii, a wtedy PEP 8 wskazał mi drogę. ZAWSZE podążaj za bogami pytonów.
Guy,
8

Zgrabna jedna linijka do zrobienia tego budynku na niektórych innych odpowiedziach:

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

lub po prostu:

s = (a or '') + (b or '')
Willem van Ketwich
źródło
Po co w ogóle wspominać (lambda v: v or '')?
Tvde1
Dlaczego nie? 2 napiwki w cenie 1! 😀
Willem van Ketwich
1
Należy pamiętać, że Falsepusta lista również zostanie zmieniona na „”.
Nik O'Lai
to samo dla 0itd.
Walter Tross
6
def xstr(s):
    return {None:''}.get(s, s)
tobidope
źródło
Myślę, że jest raczej pythonowy - a co powiesz na ten: "xstr = lambda s: {None: ''}. Get (s, s)" - redukuje całość do jednej linijki.
Juergen
14
Niepotrzebnie wolne (dodatkowe tworzenie i wyszukiwanie dyktowania) i trudniejsze do odczytania. Całkiem nieszablonowy.
Tryptyk
Masz rację. Jest raczej zgubny, ale unika warunkowego skoku w kodzie bajtowym Pythona.
tobidope
4
Wywołanie funkcji get () implikuje co najmniej jeden dodatkowy skok warunkowy.
Tryptyk
1
Nie byłbym w stanie powiedzieć, co to powinno zrobić, nie znając pytania lub nie patrząc w górę get.
Dario
5

Używam funkcji max:

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

Działa jak urok;) Po prostu umieść swój napis w pierwszym parametrze funkcji.

radtek
źródło
5
To działa, ponieważ „str”> „NoneType” i jest specyficzne dla CPythona. Z instrukcji : „Obiekty różnych typów z wyjątkiem numerów są uporządkowane według nazw typów”. Również to nie zadziała w Pythonie 3000, ponieważ porównanie między typami nie jest już dozwolone (TypeError: unorderable types: str ()> NoneType ()). Zobacz, jak Python porównuje ciąg i int?
plok
Dobrze wiedzieć, dziękuję, więc nie jest to dobry pomysł, aby przejść dalej z kodem zgodnym z Python 3.x.
radtek
4

Odmiana powyższego, jeśli chcesz być kompatybilny z Pythonem 2.4

xstr = lambda s: s is not None and s or ''
Peter Ericson
źródło
2

Jeśli chodzi o formatowanie ciągów, możesz wykonać następujące czynności:

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
źródło
1
def xstr(s):
    return s if s else ''

s = "%s%s" % (xstr(a), xstr(b))
phillc
źródło
5
To zwróci pusty ciąg dla wszystkich wartości podobnych do fałszu, o co nie prosił plakat.
Tryptyk
1

Zawsze możemy uniknąć rzutowania typów w scenariuszach opisanych poniżej.

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

W powyższym przykładzie, jeśli wartością zmiennej customer jest None, zostanie ona dalej rzutowana, gdy zostanie przypisana do 'name'. Porównanie w klauzuli „if” zawsze kończy się niepowodzeniem.

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)

Powyższy przykład zadziała poprawnie. Takie scenariusze są bardzo powszechne, gdy wartości są pobierane z adresu URL, JSON lub XML, a nawet wartości wymagają dalszego rzutowania typów w celu dowolnej manipulacji.

Sonar Pralhad Narsinh
źródło
0

Użyj oceny zwarcia:

s = a or '' + b or ''

Ponieważ + nie jest zbyt dobrą operacją na łańcuchach, lepiej użyj ciągów formatu:

s = "%s%s" % (a or '', b or '')
sharjeel
źródło
2
Spowoduje to również przekonwertowanie „a” na puste łańcuchy dla wszystkich wartości typu false, a nie tylko None. Na przykład puste krotki, listy i dykty zostaną przekonwertowane na puste łańcuchy, co nie jest tym, co określono w OP.
Tryptyk
+to doskonały operator na dwa struny. Kiedy próbujesz użyć go do połączenia dziesiątek, masz kłopoty. Dla dwojga prawdopodobnie będzie to szybsze niż inne opcje; tak czy inaczej, jest w hałasie.
kquinn
+1 dla mnie, bo to jest dokładnie to, czego potrzebuję w moim przypadku: lambda lub funkcja zastępująca pojedynczy operator ( or) wydaje mi się trochę przesadą ... Nie mam przypadków innych fałszywych wartości - ani str, ani None. Poza komentarzem na temat +operatora, który może zależeć od konkretnego scenariusza i może wymagać analizy porównawczej, ta odpowiedź nie zasługuje na -1
miejski
-3

Użyj ciągu F, jeśli używasz języka Python w wersji 3.7

xstr = F"{s}"
user781486
źródło
1
To jest błędne i zwraca ciąg, 'None'jeśli sjest None.
Lawrence,