[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Python-Dev] bpo-34595: How to format a type name?


Le jeu. 13 sept. 2018 ? 16:01, Eric V. Smith <eric at trueblade.com> a ?crit :
> > * Add !t conversion to format string
>
> I'm strongly opposed to this. This !t conversion would not be widely
> applicable enough to be generally useful, and would need to be exposed
> in the f-string and str.format() documentation, even though 99% of
> programmers would never need or see it.

(I'm thinking aloud.)

In the Python code base, I found 115 lines using type(obj).__name__
and 228 lines using obj.__class__.__name__.

$ scm.py grep 'type(.*).__name__'|wc -l
115
$ scm.py grep '.__class__.__name__'|wc -l
228

I don't know how to compare these numbers, so I tried to count the
number of f-strings:

$ git grep '[^"%-]\<f"'|wc -l
405
$ git grep "[^'%-]\<f'"|wc -l
864


I'm not sure if type(obj) or obj.__class__ should be used, but I can
say that they are different: obj.__class__ can be overriden:
---
class OtherType:
    pass

class MyType:
    __class__ = OtherType

x = MyType()
print(f"type(x): {type(x)})")
print(f"x.__class__: {x.__class__}")
---

Output:
---
type(x): <class '__main__.MyType'>)
x.__class__: <class 'int'>
---


Moreover, it's also possible to override the "type" symbol in the
global or local scope:
---
type = id
num = 42
print(f"type(num): {type(num)}")
# Output: "type(num): 139665950357856"
---

One advantage of having a builtin formatter would be to always use
internally the builtin type() function to get the type of an object,
or not use "type()" in the current scope. The second advantage is to
prevent the need of having to decide between type(obj) and
obj.__class__ :-)


> raise TypeError(f"must be str, not {obj!t}")
>
> Should be written as:
> raise TypeError(f"must be str, not {type(obj)}")

f"{type(obj)}" behaves as str(type(obj)), but in practice it uses
repr(type(obj)):

>>> f"{type(42)}"
"<class 'int'>"

My proposed f"{obj!t}" returns the fully qualified name of the object type:

>>> f"{42!t}"
"int"

Do you want to modify str(type) to return a value different than repr(type)?

Or maybe it's just a typo and you wanted to write f"{type(obj):T}"?


> That said, I think this is a good idea. type.__format__() could also
> understand "#"  to specify qualname.

When I discussed with Petr Viktorin, we failed to find an usecase
where __qualname__ was needed. We agreed that we always want the fully
qualified name, not just the qualified name.


> I think "T" is a good idea, but I think you're adding in obj vs
> type(obj) just because of the borrowed reference issue in Py_TYPE().
> That issue is so much larger than string formatting the type of an
> object that it shouldn't be addressed here.

Right, that's a side effect of the discussion on the C API. It seems
like Py_TYPE() has to go in the new C API. Sorry, the rationale is not
written down yet, but Dino convinced me that Py_TYPE() has to go :-)


> > Open question: Should we also add "%t" and "%T" formatters to the str
> > % args operator at the Python level?
>
> No. Again, I think any formatting of type names should not be in a
> widely used interface, (...)

Ok, that's fine with me :-)

Victor