Python: самий ідіоматичний спосіб перетворення None у порожній рядок?


156

Який самий ідіоматичний спосіб зробити наступне?

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

s = xstr(a) + xstr(b)

update: Я включаю пропозицію Tryptich використовувати str (s), що робить цю рутинну роботу для інших типів, крім рядків. Мене дуже вражає лямбдаська пропозиція Віная Саджіпа, але я хочу зробити свій код порівняно простим.

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

7
Мені подобається твій оригінальний синтаксис. Я думаю, це вже цілком зрозуміло і легко читати.
GuiSim

1
@GuiSim: Я можу бути упередженим, але моя відповідь звучить майже як звичайне англійське речення ...
SilentGhost

1
"Якщо s -" None ", поверніть порожню рядок; в іншому випадку поверніть [string of] s." Код із запитання також звучить як звичайне англійське речення.

а) Якщо рядок sприйшов з пошуку dict, де ключ не знайдений, тоді використовуйтеdict.get(key, '')
smci

б) Якщо ви хочете, щоб ця конвертація рядків була лише для форматування виводу (наприклад, для друку), ви можете безпосередньо зробити формат '... {}'. (dict.get (1)) `
smci

Відповіді:


94

Якщо ви дійсно хочете, щоб ваша функція вела себе як str()вбудована, але повертайте порожню рядок, коли аргумент є None, зробіть це:

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

Я зберігаю інше, але дякую за наконечник str (s), щоб можна було обробити кілька типів. приємно!
Марк Гаррісон

11
Або простоxstr = lambda s: '' if s is None else str(s)
Майкл Міор

2
Я люблю писати if not s:замістьif s is None
guneysus

6
@guneysus Вони не однакові: not False == Trueале False is None == False.
Лінн

Дякую @Lynn, ти маєш рацію. Я зрозумів свою провину. Але я знаю (або припускаю) sзавжди тип str / unicode або None. Так, Falseце цінність, але я віддаю перевагу саме тому, що зберігає мою клавіатуру та очі;)
guneysus

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

3
Цей синтаксис було введено в 2,5; для більш ранніх версій Python ви можете використовувати return s is not None and s or ''.
Бен Бланк

8
Я переверну його, щоб наголосити на більш зручному випадку: повернути s, якщо s - ніхто інший ""
Бер,

5
@Ber: Я б тримав це так, як є, щоб уникнути подвійного негативу.
Нікіл Челлі

8
Це хороший приклад того, як .. and .. or ..виходить з ладу і чому віддається перевага. Тут є два тонких помилки s is not None and s or ''.

1
return '' if not s else str(s)
Ікбал

110

Напевно, найкоротший був би str(s or '')

Оскільки None є неправдивим, а "x або y" повертає y, якщо x є хибним. Докладні пояснення див. У розділі " Булові оператори" . Це коротко, але не дуже явно.


1
це так чудово, дякую! Ніколи не думав використовувати orцей спосіб
user25064

15
Це не працює, якщо sце значення 0, False або будь-яке хибне значення
wisbucky,

4
Ну, це не зазначено в вимозі ОП, тому я не бачу тут вашої суті.
дорвак

2
@dorvak ОП досить чітко стосується вимоги, що вихід повинен бути ''iff s is None. Усі інші дані повинні повернутися s(або str(s)в переглянутому запиті).
StvnW

2
@fortea: це не спрацює. Якщо sце так None, результатом xstr()має бути порожній рядок, але str(None)дає рядок "None", який є тим, що повертається (оскільки рядок "None"не є хибним значенням.
dreamlax

97

Якщо ви знаєте, що значення завжди буде або рядком, або 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) # -> ''

1
на сьогоднішній день найбільш пітонічний. Використовує той факт, що python трактує None, порожній список, порожній рядок, 0 тощо, як хибний. Також використовує той факт, що або оператор повертає перший елемент, що є істинним, або останній елемент, наданий або (або групам орі). Також для цього використовуються лямбда-функції. Я дав би вам +10, але, очевидно, це мені не дозволило.
Метт

11
Це перетворить 0 і False (і все інше, що оцінюється як False при передачі bool ())
Аркадій,

9
Я не думаю, що це "на сьогоднішній день найбільш пітонічне". Це звичайна ідіома в інших мовах, і я не думаю, що це неправильно використовувати її в Python, але умовні вирази, де введено саме для уникнення подібних хитрощів.
Роберто Бонвальлет,

2
Це змушує []і {}т. Д. Давати той самий результат None, що і небажаний. xstr(False), зокрема, має бути "False"замість "". Зловживання лямбдами - це поганий приклад, використовуйте, def xstr(s): return s or ""якщо ви хочете, щоб це все було в одному рядку.

5
Зауважте, що я відповів на свою відповідь на самому початку "Якщо ви знаєте, що значення завжди буде або рядком, або Ні".
Vinay Sajip

59

return s or '' буде працювати нормально для вашої заявленої проблеми!


4
Варто зауважити, що це дасть інший результат, коли s є False або 0 (що не є оригінальним рядковим запитанням, але оновленим.)
Оновлення

@Oddthinking s = Falseабо s = 0, швидше за все, це буде кращим випадком у його використанні, і його можна легко пом'якшити, написавши це якreturn str(s or '')
Віллем ван Кетвіч

@WillemvanKetwich: У цьому абсолютно однакова проблема: s (False) повинен повернути "False", а не "". s (0) має повернути "0", а не "". Точно так само і для об'єкта, який визначає __bool__ або __nonzero__.
Відмінна думка

@Додумавшись, я бачу вашу думку. У будь-якому випадку, якщо він використовується виключно для рядкових об'єктів, таких як питання OP, це не повинно бути проблемою.
Віллем ван Кетвіч

@WillemvanKetwich: Подивіться на оновлене запитання та застереження в моєму коментарі - це було висвітлено,
Відмірковування


8

Функціональний спосіб (однолінійний)

xstr = lambda s: '' if s is None else s

1
"def xstr (s): return" "if s is None other s" теж є
онлайновим

2
Це не справжній однолінійний текст, він просто написаний одним рядком g
Даріо,

1
в якому сенсі це не справжній онлайнер? перевірте свого інтерпретатора - це не синтаксична помилка. для всіх намірів і цілей це реально, ніж лямбда ^ _ ^
SilentGhost

2
PEP 8 видів, які слід використовувати def, а не призначати лямбда змінній. Єдиною реальною перевагою лямбда є те, що ви можете писати як частину вираження (наприклад, переходячи до іншої функції), і ця перевага втрачається в такому коді. Раніше я це робив, поки не помітив, що def можна записати в одному рядку, і тоді PEP 8 не показав мені шлях. ЗАВЖДИ слідкуйте за богами пітона.
Хлопець

8

Акуратний одноколісний лайнер, щоб виконати цю будівлю на деяких інших відповідях:

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

або навіть просто:

s = (a or '') + (b or '')

Чому навіть згадувати (lambda v: v or '')?
Tvde1

Чому ні? 2 поради щодо ціни 1! 😀
Віллем ван Кетвіч

1
Зауважте, що Falseі порожній список також буде перетворений на "".
Нік О'Лай

те ж саме і 0т. д.
Вальтер Трос

6
def xstr(s):
    return {None:''}.get(s, s)

Я думаю, це досить пітонічно - як щодо цього: "xstr = lambda s: {None: ''}. Get (s, s)" - зводить всю справу до однолінійного.
Юрген

14
Не надто повільний (додаткова конструкція та пошук), і важче читати. Досить непітонічний.
Триптих

Ти маєш рацію. Це досить приємно, але це дозволяє уникнути умовного стрибка в байт-коді python.
тобідоп

4
Виклик функції get () передбачає принаймні один додатковий умовний стрибок.
Триптих

1
Я не зможу сказати, що це робити, не знаючи питання і не піднімаючи погляд get.
Даріо

5

Я використовую функцію max:

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

Працює як шарм;) Просто поставте рядок у перший параметр функції.


5
Це працює тому, що 'str'> 'NoneType' і є специфічним для CPython. З посібника : "Об'єкти різних типів, крім номерів, упорядковуються за їх назвами типів". Крім того, це не буде працювати в Python 3000, оскільки порівняння між типами більше не дозволено (TypeError: нерозбірливі типи: str ()> NoneType ()). Див. Як Python порівнює рядки та int?
plok

Добре знати спасибі, тому не дуже гарна ідея рухатися вперед із сумісним кодом python 3.x.
radtek


2

Якщо мова йде про форматування рядків, ви можете зробити наступне:

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)

1
def xstr(s):
    return s if s else ''

s = "%s%s" % (xstr(a), xstr(b))

5
Це поверне порожню рядок для всіх неправдивих значень, а це не те, що запитував плакат.
Триптих

1

Ми завжди можемо уникати кастингу типів у сценаріях, пояснених нижче.

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

У наведеному вище прикладі у випадку, якщо значення змінної замовника є "None", воно додатково отримує кастинг під час призначення "name". Порівняння в пункті "якщо" завжди буде невдалим.

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)

Наведений вище приклад буде працювати належним чином. Такі сценарії дуже поширені, коли значення отримуються з URL, JSON або XML або навіть значень потребує подальшого кастингу для будь-яких маніпуляцій.


0

Використовуйте оцінку короткого замикання:

s = a or '' + b or ''

Оскільки + не дуже хороша робота з рядками, краще використовуйте рядки формату:

s = "%s%s" % (a or '', b or '')

2
Це також перетворить "a" в порожні рядки для всіх помилкових значень, а не лише None. Наприклад, порожні кортежі, списки та дикти перетворюються на порожні рядки, що не є тим, що вказано в ОП.
Триптих

+є ідеально хорошим оператором для двох струн. Коли ви намагаєтеся використовувати його, щоб приєднатися до десятків, у вас виникли проблеми. Для двох це, мабуть, буде швидше, ніж інші варіанти; так чи інакше, це в шумі.
kquinn

+1 для мене тому, що це саме те, що мені потрібно в моєму випадку: лямбда або функція для заміни одного оператора ( or) здається для мене трохи зайвим ... Я не маю випадків інших помилкових значень - або str, або None. Крім коментаря +оператора, який може залежати від конкретного сценарію і може знадобитися тестування, ця відповідь не заслуговує на -1
міський

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.