Building CPython

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri May 15 06:14:31 EDT 2015


On Fri, 15 May 2015 06:59 pm, Marko Rauhamaa wrote:

> However, in some respects, Python might be going overboard with its
> dynamism; are all those dunder methods really needed? Must "false" be
> defined so broadly? Must a method lookup necessarily involve object
> creation?

Yes, what do you mean, and no.

(1) Yes, the dunder methods are necessary to support operator overloading
and various other protocols. The existence of dunder methods doesn't have
any runtime costs except for that related to memory usage. Fortunately, the
dunder methods only exist on the class itself, not each and every instance.

(2) What do you mean by false being defined so broadly?

The singleton instance False is not defined broadly at all. It is a built-in
constant, and there's only one of it. In Python 3, "False" is even a
keyword, so you cannot redefine the name. (It's not a keyword in Python 2
because of historical reasons.)

Perhaps you are talking about falsey (false-like) instances, e.g. 

    if []: ...
    else: ...

will run the else block. That's quite broad, in a sense, but it has no real
runtime cost over and above a more Pascal-ish language would force you to
have:

    if len([]) == 0: ...
    else: ...

Because True and False are singletons, the overhead of testing something in
a boolean context is no greater than the cost of testing the same condition
by hand. That is, it makes no difference whether you manually compare the
list's length to zero, or let its __nonzero__ or __bool__ method do the
same. (If anything, using an implicit boolean test will be faster than an
explicit manual test, because it doesn't have to call the len() global.)

(3) Method lookups don't *necessarily* have to involve object creation. The
only semantics which Python requires (so far as I understand it) are:

- Taking a reference to an unbound method:

    ref = str.upper

  may return the function object itself, which clearly already exists.

- Taking a reference to a bound method:

    ref = "some string".upper

  must return a method object, but it doesn't have to be recreated from
  scratch each and every time. It could cache it once, then always return
  that. That, I believe, is an implementation detail.

- Calling a method may bypass creating a method, and just use the 
  function object directly, provided Python knows that the descriptor
  has no side-effects.

For example, since FunctionType.__get__ has no side-effects, a Python
interpreter could special-case function objects and avoid calling the
descriptor protocol when it knows that the method is just going to be
called immediately.


But... having said all that... how do you know that these issues are
bottlenecks that eliminating them would speed up the code by any
significant amount?




-- 
Steven




More information about the Python-list mailing list