214

What is the most idiomatic way to do the following?

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

s = xstr(a) + xstr(b)

update: I'm incorporating Tryptich's suggestion to use str(s), which makes this routine work for other types besides strings. I'm awfully impressed by Vinay Sajip's lambda suggestion, but I want to keep my code relatively simple.

def xstr(s):
    if s is None:
        return ''
    else:
        return str(s)
Mark Harrison
  • 297,451
  • 125
  • 333
  • 465
  • 9
    I like your original syntax. I think it's already quite clear and easy to read. – GuiSim Jun 23 '09 at 19:44
  • 1
    @GuiSim: I might be biased, but my answer reads almost like a normal English sentence... – SilentGhost Jun 23 '09 at 19:49
  • 1
    "If s is None, then return an empty string; otherwise, return [string of] s." The code from the question reads like a normal English sentence too. –  Jan 02 '10 at 19:37
  • 2
    a) **If the string `s` came from a dict lookup where the key was not found, then use `dict.get(key, '')`** – smci Jul 27 '19 at 01:38
  • b) If you only want this string-conversion for output formatting (e.g. for print), then you can directly do '... {}'.format(dict.get(1))` – smci Jul 27 '19 at 01:41

17 Answers17

227

Probably the shortest would be str(s or '')

Because None is False, and "x or y" returns y if x is false. See Boolean Operators for a detailed explanation. It's short, but not very explicit.

dorvak
  • 9,219
  • 4
  • 34
  • 43
  • 2
    this is so great, thank you! Never thought of using `or` this way – user25064 Jul 11 '14 at 19:32
  • 23
    This doesn't work if `s` is 0, False, or any falsy value – wisbucky Aug 17 '15 at 18:15
  • 8
    Well, that's not mentioned in the op's requirement, so I don't see your point here. – dorvak Sep 10 '15 at 11:20
  • 4
    @dorvak The OP is quite explicit about the requirement that the output should be `''` iff `s is None`. All other input should return `s` (or `str(s)` in the revised request). – StvnW Oct 29 '15 at 22:49
  • str(...) around s only, converting an empty string to string is a nonsense... also, to the revised request: ```def xstr(s): return str(s) or ""``` – fortea Dec 24 '17 at 12:07
  • 3
    @fortea: that won't work. If `s` is `None`, the result of `xstr()` should be an empty string, but `str(None)` gives the string `"None"`, which is what is returned (since the string `"None"` is not a falsy value. – dreamlax Jul 12 '18 at 01:13
  • @wisbucky If s is 0, False works for me. These values are replaced with an empty string. – Rufat Apr 26 '23 at 02:30
172
def xstr(s):
    return '' if s is None else str(s)
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
116

If you actually want your function to behave like the str() built-in, but return an empty string when the argument is None, do this:

def xstr(s):
    if s is None:
        return ''
    return str(s)
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
  • 1
    I'm keeping the else, but thanks for the str(s) tip so multiple types can be handled. nice! – Mark Harrison Jul 01 '09 at 09:39
  • 19
    Or simply `xstr = lambda s: '' if s is None else str(s)` – Michael Mior May 21 '13 at 22:39
  • 3
    I love typing `if not s:` instead of `if s is None` – guneysus Dec 06 '15 at 15:09
  • 9
    @guneysus They aren’t the same: `not False == True` but `False is None == False`. – Lynn Feb 25 '16 at 13:39
  • Thanks @Lynn you are right. I realized my fault. But I know (or assume) `s` always a in str/unicode type or `None`. Yes, `False` is a value but I prefer this way that saves my keyboard and eyes ;) – guneysus Feb 25 '16 at 23:03
  • @guneysus still. If you want to stringify False, you can do str(False), however your xtr(False) will return ''. Depends on the behaviour you want to have, not if you love or if you don't love typing `not s` –  Sep 06 '18 at 13:23
106

If you know that the value will always either be a string or 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
  • 95,872
  • 14
  • 179
  • 191
  • 1
    by far the most pythonic. Uses the fact that python treats None, an empty list, an empty string, 0, etc as false. Also uses the fact that the or statement returns the first element that is true or the last element given to the or (or groups of ors). Also this uses lambda functions. I would give you +10 but obviously it wont let me. – Matt Jun 23 '09 at 22:59
  • 12
    This will convert 0 and False (and anything else that evaluates to False when passed to bool()) – Arkady Jun 24 '09 at 00:12
  • 9
    I don't think it's "by far the most pythonic". It's a common idiom in other languages, and I don't think it's wrong to use it in Python, but conditional expressions where introduced precisely to avoid tricks like this. – Roberto Bonvallet Jun 24 '09 at 04:44
  • I don't think that was the reasoning behind conditional expressions. It's not particularly tricky, either - there's nothing all that special about it other than it's neat and tidy. I suggest only using it if you know that s is always a string or None - as I said in the introduction. If that's the case, this seems like the most compact way. – Vinay Sajip Jun 24 '09 at 11:21
  • 2
    This makes `[]`, `{}`, etc. give the same result as `None`, which isn't desired. `xstr(False)`, in particular, should be `"False"` instead of `""`. Abusing lambdas makes for a poor example, use `def xstr(s): return s or ""` ir you want to keep it all on one line. –  Feb 09 '10 at 20:22
  • 5
    Note that I qualified my answer at the outset with "If you know that the value will always either be a string or None". – Vinay Sajip Feb 09 '10 at 22:46
  • I found this is very usefull when we know s is always a string or None. This happens when processing result of re.match(pattern, string).groups(). – Syrtis Major Jan 19 '15 at 14:53
67

return s or '' will work just fine for your stated problem!

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 4
    Worth noting that this will give a different result for when s is False or 0 (which isn't the original string question, but the updated one.) – Oddthinking Apr 30 '10 at 01:42
  • 2
    @Oddthinking `s = False` or `s = 0` would most likely be an edge case in it's use and could be easily mitigated by writing it as `return str(s or '')` – Willem van Ketwich May 13 '17 at 00:45
  • @WillemvanKetwich: That has exactly the same problem: s(False) should return 'False', not ''. s(0) should return '0', not ''. Likewise for an object that defines \_\_bool\_\_ or \_\_nonzero\__. – Oddthinking May 13 '17 at 03:27
  • @Oddthinking I see your point. In any case, if it is used exclusively for string objects such as in the OP's question it shouldn't be an issue. – Willem van Ketwich May 13 '17 at 03:55
  • @WillemvanKetwich: Have a look at the updated question and the caveat in my comment - this has been covered, – Oddthinking May 13 '17 at 06:38
  • Like the comment to @Krystian-Cybulski's aswer: just put str(...) around s: ```def xstr(s): return str(s) or ""``` – fortea Dec 24 '17 at 12:03
15
def xstr(s):
   return s or ""
Krystian Cybulski
  • 10,789
  • 12
  • 67
  • 98
  • 5
    This returns `''` for `0`, `[]`, `{}`, `False` and false-like values, which is not what the poster asked for. – StvnW Oct 29 '15 at 23:01
  • 1
    just put str([...]) around s: ```def xstr(s): return str(s) or "" ``` – fortea Dec 24 '17 at 12:01
12

UPDATE:

I mainly use this method now:

some_string = None
some_string or ''

If some_string was not NoneType, the or would short circuit there and return it, otherwise it returns the empty string.

OLD:

Max function worked in python 2.x but not in 3.x:

max(None, '')  # Returns blank
max("Hello", '') # Returns Hello
radtek
  • 34,210
  • 11
  • 144
  • 111
  • 5
    This works because 'str' > 'NoneType', and is CPython specific. From the [manual](https://docs.python.org/2/library/stdtypes.html#comparisons): "Objects of different types except numbers are ordered by their type names". Also, this won't work in Python 3000, since inter-type comparison is no longer allowed (TypeError: unorderable types: str() > NoneType()). See [How does Python compare string and int?](https://stackoverflow.com/a/3270689/184363) – plok Jun 30 '14 at 07:50
  • Good to know thanks, so not a good idea moving forward with python 3.x compatible code. – radtek Jul 04 '14 at 13:25
10

Functional way (one-liner)

xstr = lambda s: '' if s is None else s
Dario
  • 48,658
  • 8
  • 97
  • 130
  • 1
    "def xstr(s): return '' if s is None else s " is an on-liner too, python is not as strict with whitespaces after all – SilentGhost Jun 23 '09 at 19:35
  • 2
    It's no real one-liner, it's just written in one line *g* – Dario Jun 23 '09 at 19:42
  • 1
    in what sense it's not a real onliner? check in your interpreter - it's not a syntax error. for all intents and purposes it's way real than lambda ^_^ – SilentGhost Jun 23 '09 at 19:47
  • 4
    PEP 8 species that you should use def instead of assigning lambda to a variable. The only real advantage of lambda is that you can write as a part of expression(passing to another function for instance) and that advantage is lost in code like this. I used to do this too, until I noticed that def can be written in one line, and then PEP 8 showed me the way to go. ALWAYS follow the python gods. – Guy Feb 26 '14 at 14:39
10

A neat one-liner to do this building on some of the other answers:

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

or even just:

s = (a or '') + (b or '')
Willem van Ketwich
  • 5,666
  • 7
  • 49
  • 57
6
def xstr(s):
    return {None:''}.get(s, s)
tobidope
  • 560
  • 3
  • 9
  • I think, it is rather pythonic -- how about this one: "xstr = lambda s : {None:''}.get(s,s)" -- reduces the whole thing to a one-liner. – Juergen Jun 23 '09 at 19:36
  • 16
    Unnecessarily slow (extra dict construction and lookup), and harder to read. Pretty unpythonic. – Kenan Banks Jun 23 '09 at 19:37
  • You're right. It's rather perlish but it avoids a conditional jump in python bytecode. – tobidope Jun 23 '09 at 19:40
  • 4
    The get() function call implies at least one additional conditional jump. – Kenan Banks Jun 23 '09 at 19:45
  • 1
    I wouln't be able to say what this should do without knowing the question or looking up `get`. – Dario Jun 23 '09 at 19:46
  • Dario: how many language features (in any language) can you say what they do without already knowing them and without looking them up? –  Jan 02 '10 at 19:34
4

Variation on the above if you need to be compatible with Python 2.4

xstr = lambda s: s is not None and s or ''
Peter Ericson
  • 1,889
  • 1
  • 12
  • 4
2

If it is about formatting strings, you can do the following:

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
  • 3,198
  • 2
  • 26
  • 33
1
def xstr(s):
    return s if s else ''

s = "%s%s" % (xstr(a), xstr(b))
phillc
  • 7,137
  • 1
  • 22
  • 15
1

We can always avoid type casting in scenarios explained below.

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

In the example above in case variable customer's value is None the it further gets casting while getting assigned to 'name'. The comparison in 'if' clause will always fail.

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)

Above example will work properly. Such scenarios are very common when values are being fetched from URL, JSON or XML or even values need further type casting for any manipulation.

Pralhad Narsinh Sonar
  • 1,406
  • 1
  • 14
  • 23
0

Use short circuit evaluation:

s = a or '' + b or ''

Since + is not a very good operation on strings, better use format strings:

s = "%s%s" % (a or '', b or '')
sharjeel
  • 5,825
  • 7
  • 34
  • 49
  • 2
    This also will convert 'a' to empty strings for all false-like values, not just None. For instance, empty tuples, lists, and dicts will convert to empty strings, which is not what the OP specified. – Kenan Banks Jun 23 '09 at 19:41
  • `+` is a perfectly good operator for two strings. It's when you try to use it to join dozens that you have trouble. For two, it'll probably be *faster* than other options; either way, it's in the noise. – kquinn Jun 23 '09 at 22:10
  • +1 for me cause this is exactly what I need in my case: lambda or function to replace a _single_ operator (`or`) seems a bit of an overkill for me... I dont have cases of other falsly values - either str or None. Other than the comment on the `+` operator, which might depend on specific scenario and might need benchmarking, **this answer does _not_ deserve a -1** – urban Nov 28 '18 at 10:22
0

Same as Vinay Sajip's answer with type annotations, which precludes the needs to str() the result.

def xstr(s: Optional[str]) -> str:
    return '' if s is None else s
Jonathan
  • 194
  • 2
  • 5
-5

Use F string if you are using python v3.7

xstr = F"{s}"
guagay_wk
  • 26,337
  • 54
  • 186
  • 295