4

I'm doing string formatting with tuples:

a = (1,2,3)
s = f"something in {a}"
print(s)
'something in (1, 2, 3)'

Everything is fine until I encounter a single-element tuple, which gives:

a = (1,)
s = f"something in {a}"
'something in (1,)'

what I actually want is:

'something in (1)'

How do I make tuple string formatting behaves consistently and remove the trailing comma?

Azuuu
  • 853
  • 8
  • 17
  • 1
    `type((1))` is `int`; `type((1,))` is `tuple`. Without trailing comma it's different type – JL0PD Jul 28 '21 at 03:41
  • @JL0PD Yeah, but how do I achieve the same formatting since I don't know what `a` will be like since it is served as a parameter in my own code. – Azuuu Jul 28 '21 at 03:43

5 Answers5

3

You could use your own formatting logic, e.g.

a = (1,2,3)
s = ','.join([str(x) for x in a])
print(s)  # 1,2,3

a = (1,)
s = ','.join([str(x) for x in a])
print(s)  # 1
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
2

You can use regex:

import re

tuple = (1,)
s = "something in "  + re.sub(r',(?=\))', '', str(tuple))
print(s)

Result:

something in (1)

You don't need any for loop etc.

Inputvector
  • 1,061
  • 10
  • 22
1

Python have 2 magic methods for formatting values: __str__ and __repr__.

__str__ may return any string, but __repr__ must return string that can be passed to eval and recreate value. It's not required, but you should do it. print tries to use __str__ if it's overriden, otherwise it uses __repr__. This means that you can use eval(repr(some_value)) to clone value, because most builtin types have overridden __repr__ properly. That's why you get trailing comma when formatting (1,).

If you really want to format tuple without trailing comma then use

def format_tuple(value):
    return "(" + ",".join(repr(v) for v in value) + ")"
# (1,) -> "(1)"
# () -> "()"
# (1, 2, 3,) -> "(1, 2, 3)"
# (1, 2, 3) -> "(1, 2, 3)"
JL0PD
  • 3,698
  • 2
  • 15
  • 23
0

Based on @Tim Biegeleisen's answer:

a = (1,)
s = f"something in ({','.join([str(x) for x in a])})"
print(s)
'something in (1)'
Azuuu
  • 853
  • 8
  • 17
  • @Inputvector Great! But why `regular expression ` is superior to for-loop? – Azuuu Jul 28 '21 at 04:31
  • You can check here: https://stackoverflow.com/questions/42742810/speed-up-millions-of-regex-replacements-in-python-3/42747503#42747503 – Inputvector Jul 28 '21 at 04:42
  • 1
    @Inputvector Thanks! But in my case, performance isn't an issue for tuples are often less than 10 elements. I presume a for-loop combined with `f-string` might be more readable than a regular expression here. Thanks for showing me a great way of performance-boosting anyway! – Azuuu Jul 28 '21 at 05:40
0

In Python, tuples are string serialized such that they can be de-serialized back to the original form.

That means, tuples with only one element are serialized (1,) etc.

If all you want is to avoid this "exception", serialize tuples of length one differently

for tp in [(1,2), ("1",)]:
  if len(tp) > 1:
    print(tp)
  else:
    s = str(tp)
    s = s[0:-2] + s[-1:]
    print(s)
CervEd
  • 3,306
  • 28
  • 25