简体   繁体   中英

python string formatting - implicit str() + format specifiers

string formatting supports implicit str ifying. However, string format specifiers don't appear to be compatible with this, only explicit str objects (regardless of using type= s ). I cannot find this behavior documented anywhere without pulling up the cpython code. default ubuntu 20.04 python3.8 install. using an explicit str() call is workable but it's not very clean especially in my use case where it now liters the code.

obj = object()
explicit = str(obj)
print(f"{explicit:.5}")
print(f"{obj}")
print(f"{obj:.5}") # TypeError: unsupported format string passed to object.__format__

Question:

  • Have I interpreted this correctly
  • where should I be looking to glean this info myself (if exists outside cpython code), and
  • is there any way accomplish format specifiers {:...} while relying on the implicit str() ification?

You could either implement the __format__ method in your object class or place the str() directly in the format string:

print(f"{str(obj):.5}")

see PEP 498 for details.

note that f"{obj:s..5}" also works but, in that same specification, !s and !r are considered redundant and only maintained for backward compatibility

It works if you explicitly request string conversion:

>>> print(f"{obj!s:.5}")
<obje

Behind the scenes, I suspect that the result of the expression is not passed to str first, but rather to format :

>>> format(obj, "%s")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to object.__format__

In this case, object.__format__ itself doesn't automatically do a conversion to string using object.__str__ , for whatever reason.

From the C source

/* Issue 7994: If we're converting to a string, we
   should reject format specifications */

Issue object. format should reject format strings argues that the base object from which all other objects are formed should not assume that it is a string-like thing that supports string specifiers. Format specifiers are type specific so the parent of all types can't make any judgement about them. It would have to cast itself to one of its subtypes which does have a formatter, but which one?

An interesting example is a user defined class that doesn't implement a formatter and so uses the default.

>>> class Foo:
...     pass
... 
>>> foo = Foo()
>>> f"{foo:.5}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported format string passed to Foo.__format__

To get your desired result, object.__format__ would have to call foo.__str__().__format__(the_specifier) but that's an odd thing to do. Why should it assume that string formatters are the right thing to apply here? Why not __repr__ instead? The object was clear that it don't want no stinking format spec, so don't give it one.

The solution is to provide an explicit string conversion first

f"{obj!s:.5}"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM