The format
function in builtins seems to be like a subset of the str.format
method used specifically for the case of a formatting a single object.
eg.
>>> format(13, 'x') 'd'
is apparently preferred over
>>> '{0:x}'.format(13) 'd'
and IMO it does look nicer, but why not just use str.format
in every case to make things simpler? Both of these were introduced in 2.6
so there must be a good reason for having both at once, what is it?
Edit: I was asking about str.format
and format
, not why we don't have a (13).format
format() method are essentially tuple data types and each individual value contained in the tuple can be called by its index number, which starts with the index number 0. These index numbers can be passed into the curly braces that serve as the placeholders in the original string.
In java, String format() method returns a formatted string using the given locale, specified format string, and arguments. We can concatenate the strings using this method and at the same time, we can format the output concatenated string. Parameter: The locale value to be applied on the format() method.
The __format__ method is responsible for interpreting the format specifier, formatting the value, and returning the resulting string. It is safe to call this function with a value of “None” (because the “None” value in Python is an object and can have methods.)
tldr; format
just calls obj.__format__
and is used by the str.format
method which does even more higher level stuff. For the lower level it makes sense to teach an object how to format itself.
The fact that this function shares the name and format specification with str.format
can be misleading. The existence of str.format
is easy to explain: it does complex string interpolation (replacing the old %
operator); format
can format a single object as string, the smallest subset of str.format
specification. So, why do we need format
?
The format
function is an alternative to the obj.format('fmt')
construct found in some OO languages. This decision is consistent with the rationale for len
(on why Python uses a function len(x)
instead of a property x.length
like Javascript or Ruby).
When a language adopts the obj.format('fmt')
construct (or obj.length
, obj.toString
and so on), classes are prevented from having an attribute called format
(or length
, toString
, you got the idea) - otherwise it would shadow the standard method from the language. In this case, the language designers are placing the burden of preventing name clashes on the programmer.
Python is very fond of the PoLA and adopted the __dunder__
(double underscores) convention for built-ins in order to minimize the chance of conflicts between user-defined attributes and the language built-ins. So obj.format('fmt')
becomes obj.__format__('fmt')
, and of course you can call obj.__format__('fmt')
instead of format(obj, 'fmt')
(the same way you can call obj.__len__()
instead of len(obj)
).
Using your example:
>>> '{0:x}'.format(13) 'd' >>> (13).__format__('x') 'd' >>> format(13, 'x') 'd'
Which one is cleaner and easier to type? Python design is very pragmatic, it is not only cleaner but is well aligned with the Python's duck-typed approach to OO and gives the language designers freedom to change/extend the underlying implementation without breaking legacy code.
The PEP 3101 introduced the new str.format
method and format
built-in without any comment on the rationale for the format
function, but the implementation is obviously just syntactic sugar:
def format(value, format_spec): return value.__format__(format_spec)
And here I rest my case.
Quoting the very BDFL about len
:
First of all, I chose
len(x)
overx.len()
for HCI reasons (def __len__()
came much later). There are two intertwined reasons actually, both HCI:(a) For some operations, prefix notation just reads better than postfix — prefix (and infix!) operations have a long tradition in mathematics which likes notations where the visuals help the mathematician thinking about a problem. Compare the easy with which we rewrite a formula like
x*(a+b)
intox*a + x*b
to the clumsiness of doing the same thing using a raw OO notation.(b) When I read code that says
len(x)
I know that it is asking for the length of something. This tells me two things: the result is an integer, and the argument is some kind of container. To the contrary, when I readx.len()
, I have to already know thatx
is some kind of container implementing an interface or inheriting from a class that has a standardlen()
. Witness the confusion we occasionally have when a class that is not implementing a mapping has aget()
orkeys()
method, or something that isn’t a file has awrite()
method.Saying the same thing in another way, I see ‘
len
‘ as a built-in operation. I’d hate to lose that. /…/
source: [email protected] (original post here has also the original question Guido was answering). Abarnert suggests also:
There's additional reasoning about len in the Design and History FAQ. Although it's not as complete or as good of an answer, it is indisputably official. – abarnert
This is a very practical and real-world concern in languages like Python, Ruby or Javascript because in dynamically typed languages any mutable object is effectively a namespace, and the concept of private methods or attributes is a matter of convention. Possibly I could not put it better than abarnert in his comment:
Also, as far as the namespace-pollution issue with Ruby and JS, it's worth pointing out that this is an inherent problem with dynamically-typed languages. In statically-typed languages as diverse as Haskell and C++, type-specific free functions are not only possible, but idiomatic. (See The Interface Principle.) But in dynamically-typed languages like Ruby, JS, and Python, free functions must be universal. A big part of language/library design for dynamic languages is picking the right set of such functions.
For example, I just left Ember.js in favor of Angular.js because I was tired of namespace conflicts in Ember; Angular handles this using an elegant Python-like strategy of prefixing built-in methods (with $thing
in Angular, instead of underscores like python), so they do not conflict with user-defined methods and properties. Yes, the whole __thing__
is not particularly pretty but I'm glad Python took this approach because it is very explicit and avoid the PoLA class of bugs regarding object namespace clashes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With