Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A Python 3000 Question

2 views
Skip to first unread message

brad

unread,
Oct 29, 2007, 4:25:56 PM10/29/07
to
Will len(a_string) become a_string.len()? I was just reading

http://docs.python.org/dev/3.0/whatsnew/3.0.html

One of the criticisms of Python compared to other OO languages is that
it isn't OO enough or as OO as others or that it is inconsistent. And
little things such as this seem to support those arguments. Not that it
matters really... just seems that classes with methods used in a more
consistent manner would be more appropriate in an OO langauage. Is there
a reason that len cannot be a method?

a_string.lower() makes sense, as does a_string.split(),
a_string.strip()... why not a_string.len()?

Rob Wolfe

unread,
Oct 29, 2007, 5:12:27 PM10/29/07
to
brad <byte...@gmail.com> writes:

I wonder why people always complain about `len` function but never
about `iter` or `pprint.pprint`? :)

And to answer the question. In OO programming generic functions
are no less important than classes and objects.

Regards,
Rob

brad

unread,
Oct 29, 2007, 5:26:06 PM10/29/07
to
Rob Wolfe wrote:

> I wonder why people always complain about `len` function but never
> about `iter` or `pprint.pprint`? :)

Not complaining. len is simple and understandable and IMO fits nicely
with split(), strip(), etc... that's why I used it as an example, but
list(), etc. could be used as examples as well:

a_string.list() instead of list(a_string)

> And to answer the question. In OO programming generic functions
> are no less important than classes and objects.

Do they not take away from the OOness of the overall language and
introduce inconsistencies?

Terry Reedy

unread,
Oct 29, 2007, 5:49:59 PM10/29/07
to pytho...@python.org

"brad" <byte...@gmail.com> wrote in message
news:fg5fku$5c1$1...@solaris.cc.vt.edu...
| Will len(a_string) become a_string.len()?

No.

which says nothing about such a change, except for one in the opposite
direction: o.next() changes to next(o) which in turn calls o.__next__(),
just as len(o) calls o.__len__()

| One of the criticisms of Python compared to other OO languages is that
| it isn't OO enough or as OO as others or that it is inconsistent.

Python is object-based and has a nice user-defined type (class) system, but
I do not believe Guido has ever called it object oriented. So the
comparision is besides the point even if true.

| Is there a reason that len cannot be a method?

It corresponds to and calls method .__len__ , when such exists. Yes,
Python could have been designed differently, with no builtin functions, but
is was not. Python is also a functional language with first-class generic
functions.

| why not a_string.len()?

You are free to bypass builtins and call methods directly if you like:
a_string.__len__().

But consider rewriting the following:

def table(func, seq):
return zip(seq, map(func,seq))

table(len, ('', (), []))

If you *really* want to be super-OO, like functionless OO languages, you
can also call methods instead of using operator symbols, which in effect
are names of builtin functions.

Instead of a+b, write a.__add__(b). And so on.

Terry Jan Reedy

Bjoern Schliessmann

unread,
Oct 29, 2007, 6:08:14 PM10/29/07
to
brad wrote:
> One of the criticisms of Python compared to other OO languages is
> that it isn't OO enough or as OO as others or that it is
> inconsistent.

If OO meant "everything must be a method" then yes, Python wasn't
OO.

> And little things such as this seem to support those
> arguments. Not that it matters really... just seems that classes
> with methods used in a more consistent manner would be more
> appropriate in an OO langauage. Is there a reason that len cannot
> be a method?

Is there any particular reason why it should be a method?

> a_string.lower() makes sense, as does a_string.split(),
> a_string.strip()... why not a_string.len()?

Just a fuzzy comment: lower, split and strip work specifically for
strings and/or sequence types, and return a modified copy of them
(or modify them directly, as with other methods like sorted or
shuffle). len, OTOH, works for much more objects and returns some
kind of norm that makes objects comparable and whose type is the
same for all objects.

To make a long story short: Most methods do specific things with
objects; but len is a common function to get a simple property of
an object.

Regards,


Björn

--
BOFH excuse #164:

root rot

Bjoern Schliessmann

unread,
Oct 29, 2007, 6:15:02 PM10/29/07
to
brad wrote:

> a_string.list() instead of list(a_string)

A string can be stripped, "lowercased" or split, but why should it
be able to be "listed"? IMHO, list is a conversion function to make
a list from something.



>> And to answer the question. In OO programming generic functions
>> are no less important than classes and objects.
>
> Do they not take away from the OOness of the overall language and
> introduce inconsistencies?

Not at all. Explain, why should they? Functions can be objects, too.
And are in Python.

The inconsistencies arise, IMHO, if an OO language introduces
non-object types for performance reasons, after that gets wrapper
classes to wrap those primitives, and even later gets the ability
to automatically cast a primitive into a wrapper class instance.
That's just ugly.

Regards,


Björn

--
BOFH excuse #56:

Electricians made popcorn in the power supply

Carl Banks

unread,
Oct 29, 2007, 7:23:23 PM10/29/07
to
On Oct 29, 4:25 pm, brad <byte8b...@gmail.com> wrote:
> One of the criticisms of Python compared to other OO languages is that
> it isn't OO enough or as OO as others or that it is inconsistent.

Python is less thoroughly OO than some other languages, yes. The
underlying assumption, that being thoroughly OO is a good thing, is
very dubious.


Carl Banks

Marc 'BlackJack' Rintsch

unread,
Oct 29, 2007, 8:11:58 PM10/29/07
to
On Mon, 29 Oct 2007 17:26:06 -0400, brad wrote:

> Rob Wolfe wrote:
>
>> I wonder why people always complain about `len` function but never
>> about `iter` or `pprint.pprint`? :)
>
> Not complaining. len is simple and understandable and IMO fits nicely
> with split(), strip(), etc... that's why I used it as an example, but
> list(), etc. could be used as examples as well:
>
> a_string.list() instead of list(a_string)

`list()` takes any iterable and turns it into a list object. That's a
generic operation coded *once*. If you have `str.list()`, `tuple.list()`,
`list.list()`, `dict.list()`, `file.list()`, `MyIterableSomething.list()`,
etc. you have to code the same over and over again for all those objects.
How could that be a benefit!?

>> And to answer the question. In OO programming generic functions
>> are no less important than classes and objects.
>
> Do they not take away from the OOness of the overall language and
> introduce inconsistencies?

No not at all. Why do you think so? There are things that are best
expressed as functions. Other allegedly more OO languages have them
too, but you need to stuff them as static methods into classes or even
uglier you see code like ``Spam().spammify(eggs)`` instead of a plain
function call.

And functions are first class objects in Python. That sounds quite OO to
me. You can think of a module with functions as a singleton.

Ciao,
Marc 'BlackJack' Rintsch

Wildemar Wildenburger

unread,
Oct 29, 2007, 8:59:09 PM10/29/07
to
Bjoern Schliessmann wrote:
> The inconsistencies arise, IMHO, if an OO language introduces
> non-object types for performance reasons, after that gets wrapper
> classes to wrap those primitives, and even later gets the ability
> to automatically cast a primitive into a wrapper class instance.
> That's just ugly.
>
If you mean Java, then just say Java.

;)
/W

Michael L Torrie

unread,
Oct 29, 2007, 9:35:04 PM10/29/07
to pytho...@python.org
brad wrote:
> Not complaining. len is simple and understandable and IMO fits nicely
> with split(), strip(), etc... that's why I used it as an example, but
> list(), etc. could be used as examples as well:
>
> a_string.list() instead of list(a_string)

This is a great example of why list() needs to be a singleton and *not*
a method of any particular class. Consider the following contrived
object (yes object):

def foo():
for x in xrange(6):
yield x


If we eliminated list() as a first class singleton and forced it to be a
method call, how would it work with this generator object? Right now I
can say:

mylist=list(foo())

Saying list() should be a method only of something iterable is not only
foolish, but wasteful. Why should I burden every iterable object with
redundant code? And how would you deal with generators in your scenario?

In short, making list() a method is wrong-thinking. Reminds me of java.
Ugg.

>
>> And to answer the question. In OO programming generic functions
>> are no less important than classes and objects.
>
> Do they not take away from the OOness of the overall language and
> introduce inconsistencies?

If find Python to be more OO through and through than Java. Once you
understand that functions are objects, and duck-typing, things like
len() being a function rather than a method make perfect sense.


George Sakkis

unread,
Oct 29, 2007, 10:50:14 PM10/29/07
to
On Oct 29, 5:49 pm, "Terry Reedy" <tjre...@udel.edu> wrote:

> I was just reading
> |http://docs.python.org/dev/3.0/whatsnew/3.0.html
>
> which says nothing about such a change, except for one in the opposite
> direction: o.next() changes to next(o) which in turn calls o.__next__(),
> just as len(o) calls o.__len__()

Ugh. A great example of complexification (if there's such a word).

> | why not a_string.len()?
>
> You are free to bypass builtins and call methods directly if you like:
> a_string.__len__().
>
> But consider rewriting the following:
>
> def table(func, seq):
> return zip(seq, map(func,seq))
>
> table(len, ('', (), []))

table(lambda x:x.__len__(), ('',[],()))

What was the point again ?

> If you *really* want to be super-OO, like functionless OO languages, you
> can also call methods instead of using operator symbols, which in effect
> are names of builtin functions.
>
> Instead of a+b, write a.__add__(b). And so on.

True, if ones wants to go all the way to, say, Java. Operator
overriding though is pretty handy in terms of syntax sugar to give up,
especially for expressions that are identical or strongly similar from
a familiar context (e.g. maths). This cannot be claimed about len()
though. My main problem with len() is not so much the function/method
inconsistency, but rather that it doesn't apply to all (or even most)
objects. I am much less against, say, getattr(), being a function
since it makes sense for all objects. But why len()? At best it's a
subjective judgment call of where to draw the line, at worst it's
plain inconsistent.

And while we're at it, what's the rationale of len() insisting that
the return value is >=0 ? That also looks odd in a dynamic language
with a "we're all adults here" philosophy and much less hand-holding
in areas that matter more (e.g. allowed by default comparisons between
instances of different types - at least that's one of the warts Python
3 gets right).

George

George Sakkis

unread,
Oct 30, 2007, 1:30:13 AM10/30/07
to
On Oct 29, 9:35 pm, Michael L Torrie <torr...@chem.byu.edu> wrote:
> brad wrote:
> > Not complaining. len is simple and understandable and IMO fits nicely
> > with split(), strip(), etc... that's why I used it as an example, but
> > list(), etc. could be used as examples as well:
>
> > a_string.list() instead of list(a_string)
>
> This is a great example of why list() needs to be a singleton and *not*
> a method of any particular class.

The whole discussion about list() is moot since it's not a function
anyway, it's a type. As long as a list knows hows to initialize itself
given any iterable, it would be useless to require it as a method to
the iterables as well (unless perhaps there are significant
performance improvements when one can create a list much faster than
iterating through it).

> Saying list() should be a method only of something iterable is not only
> foolish, but wasteful. Why should I burden every iterable object with
> redundant code?

Does the same argument apply for len() ? Nope, you still have to
define __len__. Having a builtin len() that calls the method __len__
seems (using your words) "not only foolish but wasteful".

> In short, making list() a method is wrong-thinking. Reminds me of java.
> Ugg.

Agreed, but you're beating a dead horse with list().

> If find Python to be more OO through and through than Java. Once you
> understand that functions are objects, and duck-typing, things like
> len() being a function rather than a method make perfect sense.

Does the fact that index() or split() are methods make perfect sense
as well? I guess after some time using Python it does, but for most
unbiased users the distinction seems arbitrary.

George

Marc 'BlackJack' Rintsch

unread,
Oct 30, 2007, 3:58:38 AM10/30/07
to
On Mon, 29 Oct 2007 19:50:14 -0700, George Sakkis wrote:

> On Oct 29, 5:49 pm, "Terry Reedy" <tjre...@udel.edu> wrote:
>
>> | why not a_string.len()?
>>
>> You are free to bypass builtins and call methods directly if you like:
>> a_string.__len__().
>>
>> But consider rewriting the following:
>>
>> def table(func, seq):
>> return zip(seq, map(func,seq))
>>
>> table(len, ('', (), []))
>
> table(lambda x:x.__len__(), ('',[],()))
>
> What was the point again ?

Beautiful is better than ugly!? ;-)

Ciao,
Marc 'BlackJack' Rintsch

Thomas Wittek

unread,
Oct 30, 2007, 4:06:42 AM10/30/07
to
Bjoern Schliessmann:

> Is there any particular reason why it should be a method?
>
> [..]

>
> To make a long story short: Most methods do specific things with
> objects; but len is a common function to get a simple property of
> an object.

You said it. IMHO it really could be a *property*, say `object.len`.
It doesn't do something on the object, but rather gives some information
about its "state".

--
Thomas Wittek
Web: http://gedankenkonstrukt.de/
Jabber: strea...@jabber.i-pobox.net
GPG: 0xF534E231

Bruno Desthuilliers

unread,
Oct 30, 2007, 5:08:45 AM10/30/07
to
brad a écrit :

> Will len(a_string) become a_string.len()? I was just reading
>
> http://docs.python.org/dev/3.0/whatsnew/3.0.html
>
> One of the criticisms of Python compared to other OO languages is that
> it isn't OO enough

Really ? IIRC, Python doesn't have primitive types, functions are
objects, methods are objects, classes are objects, even modules are
objects... Isn't this 'OO enough' ?

> or as OO as others

Which ones ? Java, that does have primitive types ?

(snip question about len() not being a method - no personal opinion on
the topic)

Bruno Desthuilliers

unread,
Oct 30, 2007, 5:22:58 AM10/30/07
to
brad a écrit :

> Rob Wolfe wrote:
>
>> I wonder why people always complain about `len` function but never
>> about `iter` or `pprint.pprint`? :)
>
> Not complaining. len is simple and understandable and IMO fits nicely
> with split(), strip(), etc... that's why I used it as an example, but
> list(), etc. could be used as examples as well:
>
> a_string.list() instead of list(a_string)

Oh, fine. And a_string.tuple(), a_string.int(), a_string.this(),
a_string.that() etc ?

In case you don't know, list is a type, not a function !-)

>> And to answer the question. In OO programming generic functions
>> are no less important than classes and objects.
>
> Do they not take away from the OOness of the overall language

Why so ?

> and
> introduce inconsistencies?

The monotonic approach to callables in Python (I mean: functions are
callable objects, classes are callable objects, so instanciation and
function call have the exact same syntax - which let you decouple
interface from implementation) is another way to be consistent. because
you can switch from type to factory function (or from closure to
callable object, etc) back and forth without breaking client code.

Dustan

unread,
Oct 30, 2007, 7:11:39 AM10/30/07
to
On Oct 29, 7:59 pm, Wildemar Wildenburger

There was no need to; it was heavily implied.

Eduardo O. Padoan

unread,
Oct 30, 2007, 7:11:18 AM10/30/07
to brad, pytho...@python.org

brad

unread,
Oct 30, 2007, 8:56:02 AM10/30/07
to
Eduardo O. Padoan wrote:

Thanks to all for the feedback. I'm no language designer. I just see and
hear these criticisms and I wanted to think through it a bit by posting
here. I now better understand generic functions and why they are used in
some cases.

Steven D'Aprano

unread,
Oct 30, 2007, 10:09:39 AM10/30/07
to
On Tue, 30 Oct 2007 00:11:58 +0000, Marc 'BlackJack' Rintsch wrote:

>>> And to answer the question. In OO programming generic functions are no
>>> less important than classes and objects.
>>
>> Do they not take away from the OOness of the overall language and
>> introduce inconsistencies?
>
> No not at all. Why do you think so?

I disagree. I think they *do* take away from the overall Object-Oriented
nature of the language, and that is A Very Good Thing Indeed.

OO is a tool, and like any tool, it has it's uses and misuses. Some
things are best written as objects, some as imperative procedures, some
as functions. As you say:

> There are things that are best expressed as functions.

Agreed. It is a *good thing* that Python doesn't try to be 100%
functional, or 100% Object Oriented, or 100% procedural.

(Aside: I think it a shame that there is one major paradigm that Python
doesn't have *any* support for at all: logic programming, like Prolog. I
don't quite know what it is good for, but I'd like to find out!)


> Other allegedly more OO languages have them
> too, but you need to stuff them as static methods into classes or even
> uglier you see code like ``Spam().spammify(eggs)`` instead of a plain
> function call.


I'm reminded of a very famous proverb from the Kingdom of the Nouns:

For the lack of a nail,
throw new HorseshoeNailNotFoundException("no nails!");

For the lack of a horseshoe,
EquestrianDoctor.getLocalInstance().getHorseDispatcher().shoot();

For the lack of a horse,
RidersGuild.getRiderNotificationSubscriberList().getBroadcaster().run(
new BroadcastMessage(StableFactory.getNullHorseInstance()));

For the rest of the proverb, which is well worth reading, you'll have to
see here:


http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

--
Steven.
(no, not that Steve in the URL)

Jean-Paul Calderone

unread,
Oct 30, 2007, 10:33:14 AM10/30/07
to pytho...@python.org
On Tue, 30 Oct 2007 14:09:39 -0000, Steven D'Aprano <st...@remove-this-cybersource.com.au> wrote:
>
> [snip]

>
>(Aside: I think it a shame that there is one major paradigm that Python
>doesn't have *any* support for at all: logic programming, like Prolog. I
>don't quite know what it is good for, but I'd like to find out!)
>

If you have some time to experiment, PyPy has some support for logic
programming with Python.

http://codespeak.net/pypy/dist/pypy/doc/objspace-proxies.html#the-logic-object-space

Jean-Paul

Neil Cerutti

unread,
Oct 30, 2007, 11:25:54 AM10/30/07
to

Holy Airy Persiflage Batman!

Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('len(seq)', 'seq = range(100)').timeit()
0.20332271187463391
>>> timeit.Timer('seq.__len__()', 'seq = range(100)').timeit()
0.48545737364457864

--
Neil Cerutti

Jean-Paul Calderone

unread,
Oct 30, 2007, 12:02:19 PM10/30/07
to pytho...@python.org

Not sure what you're trying to demonstrate. Here's another pointless
transcript, though:

exarkun@charm:~$ python -m timeit -s '
seq = range(100)
' 'len(seq)'
1000000 loops, best of 3: 0.211 usec per loop
exarkun@charm:~$ python -m timeit -s '
seq = range(100)
' 'seq.__len__()'
1000000 loops, best of 3: 0.317 usec per loop
exarkun@charm:~$ python -m timeit -s '
class X(object):
def __len__(self): return 100
seq = X()
' 'seq.__len__()'
1000000 loops, best of 3: 0.427 usec per loop
exarkun@charm:~$ python -m timeit -s '
class X(object):
def __len__(self): return 100
seq = X()
' 'len(seq)'
1000000 loops, best of 3: 0.701 usec per loop
exarkun@charm:~$

I guess we've learned that sometimes something is faster than something
else, and other times the contrary.

Jean-Paul

George Sakkis

unread,
Oct 30, 2007, 12:16:40 PM10/30/07
to
On Oct 30, 11:25 am, Neil Cerutti <horp...@yahoo.com> wrote:

> On 2007-10-30, Eduardo O. Padoan <eduardo.pad...@gmail.com> wrote:
>
> > This is a FAQ:
> >http://effbot.org/pyfaq/why-does-python-use-methods-for-some-function...

>
> Holy Airy Persiflage Batman!
>
> Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.>>> import timeit
> >>> timeit.Timer('len(seq)', 'seq = range(100)').timeit()
> 0.20332271187463391
> >>> timeit.Timer('seq.__len__()', 'seq = range(100)').timeit()
>
> 0.48545737364457864

Common mistake; try this instead:

timeit.Timer('seqlen()',
'seq = range(100); seqlen=seq.__len__').timeit()

George

Paul Boddie

unread,
Oct 30, 2007, 12:27:05 PM10/30/07
to
On 30 Okt, 15:09, Steven D'Aprano <st...@REMOVE-THIS-
cybersource.com.au> wrote:
>

[Language "OOness", hand-waving]

> I disagree. I think they *do* take away from the overall Object-Oriented
> nature of the language, and that is A Very Good Thing Indeed.

But everything is an object in Python: nothing has been taken
away. ;-) Anyway, I don't sympathise with the "methods for everything"
mentality, either, but there's a reason for Java doing things this way
- for Python, in fact, you actually get something extra over and above
Java's implementation of object-orientation.

[...]

> http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns...

As always, a pinch of salt is required when reading the works of
certain commentators (or skimming them, for those making slightly
better use of their time). Some choice words sum up the attitude we
see in works like this:

http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html#c114516329036008490

Thankfully, various decisions in the design of Python and its built-in
types and functions let us leave such squabbles to eat up the time of
the Ruby and Java fanboys.

Paul

Neil Cerutti

unread,
Oct 31, 2007, 8:44:53 AM10/31/07
to
On 2007-10-30, Jean-Paul Calderone <exa...@divmod.com> wrote:
> On Tue, 30 Oct 2007 15:25:54 GMT, Neil Cerutti <hor...@yahoo.com> wrote:
>>On 2007-10-30, Eduardo O. Padoan <eduardo...@gmail.com> wrote:
>>> This is a FAQ:
>>> http://effbot.org/pyfaq/why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list.htm
>>
>>Holy Airy Persiflage Batman!
>>
>>Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
>>win32
>>Type "help", "copyright", "credits" or "license" for more information.
>>>>> import timeit
>>>>> timeit.Timer('len(seq)', 'seq = range(100)').timeit()
>>0.20332271187463391
>>>>> timeit.Timer('seq.__len__()', 'seq = range(100)').timeit()
>>0.48545737364457864
>
> Not sure what you're trying to demonstrate.

That len as a builtin can be faster than len as an attribute, and
doesn't need any further explanation than that.

> Here's another pointless transcript, though:
>
> exarkun@charm:~$ python -m timeit -s '
> seq = range(100)
> ' 'len(seq)'
> 1000000 loops, best of 3: 0.211 usec per loop
> exarkun@charm:~$ python -m timeit -s '
> seq = range(100)
> ' 'seq.__len__()'
> 1000000 loops, best of 3: 0.317 usec per loop
> exarkun@charm:~$ python -m timeit -s '
> class X(object):
> def __len__(self): return 100
> seq = X()
> ' 'seq.__len__()'
> 1000000 loops, best of 3: 0.427 usec per loop
> exarkun@charm:~$ python -m timeit -s '
> class X(object):
> def __len__(self): return 100
> seq = X()
> ' 'len(seq)'
> 1000000 loops, best of 3: 0.701 usec per loop
> exarkun@charm:~$
>
> I guess we've learned that sometimes something is faster than
> something else, and other times the contrary.

It demonstratess that len is faster than __len__ for lists (and
probably for all builtin types) but not for user defined type X
(and probably not for any user defined type).

Or it may demonstrate that I'm all wet. If so, I've brought my
shampoo.

But if I'm wrong about the performance benefits then I guess I'm
still in the dark about why len is a builtin. The only compelling
thing in the linked explation was the signatures of the guys who
wrote the artible. (Guido does admit he would, "hate to lose it
as a builtin," but doesn't explain why that should be a bad
thing).

--
Neil Cerutti
It isn't pollution that is hurting the environment; it's the impurities in our
air and water that are doing it. --Dan Quayle

Neil Cerutti

unread,
Oct 31, 2007, 8:44:53 AM10/31/07
to

Why would I want to do that?

--
Neil Cerutti
These people haven't seen the last of my face. If I go down, I'm going down
standing up. --Chuck Person

George Sakkis

unread,
Oct 31, 2007, 9:14:41 AM10/31/07
to
On Oct 31, 8:44 am, Neil Cerutti <horp...@yahoo.com> wrote:

> On 2007-10-30, George Sakkis <george.sak...@gmail.com> wrote:
>
>
>
> > On Oct 30, 11:25 am, Neil Cerutti <horp...@yahoo.com> wrote:
> >> On 2007-10-30, Eduardo O. Padoan <eduardo.pad...@gmail.com> wrote:
>
> >> > This is a FAQ:
> >> >http://effbot.org/pyfaq/why-does-python-use-methods-for-some-function...
>
> >> Holy Airy Persiflage Batman!
>
> >> Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
> >> win32
> >> Type "help", "copyright", "credits" or "license" for more information.>>> import timeit
> >> >>> timeit.Timer('len(seq)', 'seq = range(100)').timeit()
> >> 0.20332271187463391
> >> >>> timeit.Timer('seq.__len__()', 'seq = range(100)').timeit()
>
> >> 0.48545737364457864
>
> > Common mistake; try this instead:
>
> > timeit.Timer('seqlen()',
> > 'seq = range(100); seqlen=seq.__len__').timeit()
>
> Why would I want to do that?


To realize that __len__ is actually faster than len in this case; your
second timing is dominated by the time to do attribute lookup.


George

Neil Cerutti

unread,
Oct 31, 2007, 9:33:04 AM10/31/07
to

I knew that going in. Making len a builtin saves us from writing
our own seqlen functions. ;)

--
Neil Cerutti
He's a guy who gets up at six o'clock in the morning regardless of what time
it is. --Lou Duva

Duncan Booth

unread,
Oct 31, 2007, 9:49:50 AM10/31/07
to
Neil Cerutti <hor...@yahoo.com> wrote:

> But if I'm wrong about the performance benefits then I guess I'm
> still in the dark about why len is a builtin. The only compelling
> thing in the linked explation was the signatures of the guys who
> wrote the artible. (Guido does admit he would, "hate to lose it
> as a builtin," but doesn't explain why that should be a bad
> thing).

With most of the builtin functions there is an advantage since they wrap
a bit of extra logic round the implementation: e.g. getattr hooks to
__getattr__ or __getattribute__.

With len that doesn't really apply, as the only extra logic seems fairly
pointless: sequences and mappings implement length differently so you
could have a type which acts as both and returns different lengths for
each. Also the result returned from __len__ is cast from a Python object
to a C value and back again so you can't return a length which is too
large to convert.

The main benefit that I can think of is that it avoids namespace
pollution: most Python special methods (the ones you aren't supposed to
call directly) have the double-underscores flagging them as separate
from user methods. This is a good thing: you can create a class which
acts like a builtin sequence, but which has any attributes you fancy:
the obvious example being the classic "it's a tuple but all the elements
are also accessible as attributes" returned from time.localtime(),
os.stat(). Try this in a language like Javascript and nasty things
happen when your attribute names clash with internal attribute names.

So that's my conclusion: it is a builtin function rather than a method
in order to avoid polluting the user attribute space of user-defined
classes.

Obviously it isn't an absolute thing: lists and dictionaries do have
other methods in the user namespace, so the decision to keep len out of
that namespace is partly a judgement call, and partly historical (I
think tuples didn't used to have any methods at all).

Neil Cerutti

unread,
Oct 31, 2007, 10:13:28 AM10/31/07
to
On 2007-10-31, Duncan Booth <duncan...@invalid.invalid> wrote:
> Obviously it isn't an absolute thing: lists and dictionaries do
> have other methods in the user namespace, so the decision to
> keep len out of that namespace is partly a judgement call, and
> partly historical (I think tuples didn't used to have any
> methods at all).

Thanks for the interesting note. I didn't know that tuples
originally had no methods. That made len mandatory, I suppose.

--
Neil Cerutti
The Pastor would appreciate it if the ladies of the congregation would lend
him their electric girdles for the pancake breakfast next Sunday morning.
--Church Bulletin Blooper

Duncan Booth

unread,
Oct 31, 2007, 10:45:59 AM10/31/07
to
Neil Cerutti <hor...@yahoo.com> wrote:

> On 2007-10-31, Duncan Booth <duncan...@invalid.invalid> wrote:
>> Obviously it isn't an absolute thing: lists and dictionaries do
>> have other methods in the user namespace, so the decision to
>> keep len out of that namespace is partly a judgement call, and
>> partly historical (I think tuples didn't used to have any
>> methods at all).
>
> Thanks for the interesting note. I didn't know that tuples
> originally had no methods. That made len mandatory, I suppose.
>

Only if you think tuples are a sequence rather than a record. :)

Come to think of it, strings didn't have methods either, so len needed to
be a function to get the length of a string.

I'm not sure when tuples sprouted methods. Strings grew methods in 1.6, but
I think numbers and tuples may not have got any methods until the
introduction of new-style classes (Python 2.2)

Carl Banks

unread,
Oct 31, 2007, 10:59:58 AM10/31/07
to
On Oct 31, 8:44 am, Neil Cerutti <horp...@yahoo.com> wrote:

> On 2007-10-30, George Sakkis <george.sak...@gmail.com> wrote:
>
>
>
> > On Oct 30, 11:25 am, Neil Cerutti <horp...@yahoo.com> wrote:
> >> On 2007-10-30, Eduardo O. Padoan <eduardo.pad...@gmail.com> wrote:
>
> >> > This is a FAQ:
> >> >http://effbot.org/pyfaq/why-does-python-use-methods-for-some-function...
>
> >> Holy Airy Persiflage Batman!
>
> >> Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on
> >> win32
> >> Type "help", "copyright", "credits" or "license" for more information.>>> import timeit
> >> >>> timeit.Timer('len(seq)', 'seq = range(100)').timeit()
> >> 0.20332271187463391
> >> >>> timeit.Timer('seq.__len__()', 'seq = range(100)').timeit()
>
> >> 0.48545737364457864
>
> > Common mistake; try this instead:
>
> > timeit.Timer('seqlen()',
> > 'seq = range(100); seqlen=seq.__len__').timeit()
>
> Why would I want to do that?

If your point is to measure the time of just the operation as
accurately as possible, you don't want the extra dict lookup in
seq.__len__ affecting things. Though it seems to me that if your
intention is to determine if builtin or method style is faster, it's
not such a great idea to replace the method call with a builtin call.

As for what benefit there is for len to be a builtin:

Python considers len to be an operator for all intents and purposes.
Python chose to spell this operator like a regular function, but it
could easily have given a special syntax to the length operation (for
instance, $#x).

Do you think that, if the length operation had its own syntax, people
would be saying "No, length shouldn't be an operator, it should be a
method"? I don't think so; length is a fundamental and ubiquitous
operation and it wouldn't be unreasonable to give it its own syntax.

That suggests to me that, when people complain that len should be a
method, their complaint is a superficial complaint about spelling.
They are not considering whether len is important enough to be an
operator or not.


Carl Banks

Steven D'Aprano

unread,
Oct 31, 2007, 5:59:05 PM10/31/07
to
On Wed, 31 Oct 2007 14:45:59 +0000, Duncan Booth wrote:

>> Thanks for the interesting note. I didn't know that tuples originally
>> had no methods. That made len mandatory, I suppose.
>>
> Only if you think tuples are a sequence rather than a record.

Even records have a length. The length of a record is the number of
fields it has.

--
Steven.

Steven D'Aprano

unread,
Oct 31, 2007, 6:13:46 PM10/31/07
to


What Neil has done is the correct thing to measure in this case.

What you have measured is a local optimization that is only useful when
you have a tight loop with lots of calls to the same len():


Len = sequence.__len__
while Len() < 100000:
foo(sequence)


But what Neil is measuring is relevant for the more general case of
calling len() on arbitrary objects at arbitrary times:

x = len(sequence)
y = 42 + len("xyz")
if len(records) == 12:
print "twelve!"


To get the benefit of the micro-optimization you suggested, you would
need to write this:

Len = sequence.__len__
x = Len()
Len = "xyz".__len__
y = 42 + Len()
Len = records.__len__
if Len() == 12:
print "twelve!"


Not only is that an especially ugly, confusing piece of code, it is also
counter-productive as you still have to do the method lookup every single
time.

Taking the method lookup is an apple-and-oranges comparison. It is useful
to know for the times when you don't want an apple, you want an orange
(i.e. the tight loop example above).

This is an apples-and-apples comparison:

>>> import timeit
>>> timeit.Timer("Len = seq.__len__; Len()", "seq = range(12)").repeat()
[1.3109469413757324, 0.7687380313873291, 0.55280089378356934]
>>> timeit.Timer("len(seq)", "seq = range(12)").repeat()
[0.60111594200134277, 0.5977931022644043, 0.59935498237609863]


The time to do the lookup and call the method is about 0.6 microseconds
whether you do it manually or let len() do it.

The logic behind the micro-optimization trick is to recognize when you
can avoid the cost of repeated method lookups by doing it once only. That
is not relevant to the question of whether len() should be a function or
a method.

--
Steven.

Steven D'Aprano

unread,
Oct 31, 2007, 6:29:13 PM10/31/07
to
On Wed, 31 Oct 2007 07:59:58 -0700, Carl Banks wrote:

> Python considers len to be an operator for all intents and purposes.
> Python chose to spell this operator like a regular function, but it
> could easily have given a special syntax to the length operation (for
> instance, $#x).

I hope you're not serious that $# would make a good operator. Apart from
conflicting with the comment marker, it is u-g-l-y.

That's the problem with operators... all the good ones are taken.


> Do you think that, if the length operation had its own syntax, people
> would be saying "No, length shouldn't be an operator, it should be a
> method"? I don't think so; length is a fundamental and ubiquitous
> operation and it wouldn't be unreasonable to give it its own syntax.

I think they would.

You seem to have missed the context of the thread. The Original Poster
was complaining that len() should be a method, because that is more
purely Object Oriented.

If len() were an operator, that too would be a compromise to the ideal of
"every function is an object method". I'm sure there are OO fan[atic]s
who dislike operators too.

--
Steven.

George Sakkis

unread,
Oct 31, 2007, 7:02:58 PM10/31/07
to
On Oct 31, 6:13 pm, Steven D'Aprano

> What you have measured is a local optimization that is only useful when
> you have a tight loop with lots of calls to the same len():
>
> Len = sequence.__len__
> while Len() < 100000:
> foo(sequence)

Exactly what timeit() does, a tight loop.

> But what Neil is measuring is relevant for the more general case of
> calling len() on arbitrary objects at arbitrary times:
>
> x = len(sequence)
> y = 42 + len("xyz")
> if len(records) == 12:
> print "twelve!"
>
> To get the benefit of the micro-optimization you suggested, you would
> need to write this:
>
> Len = sequence.__len__
> x = Len()
> Len = "xyz".__len__
> y = 42 + Len()
> Len = records.__len__
> if Len() == 12:
> print "twelve!"
>
> Not only is that an especially ugly, confusing piece of code, it is also
> counter-productive as you still have to do the method lookup every single
> time.

The whole point of the optimization is avoiding 99999 attribute
lookups of the timeit loop. For a single call both times are
practically zero so the snippet above is just silly.

> Taking the method lookup is an apple-and-oranges comparison. It is useful
> to know for the times when you don't want an apple, you want an orange
> (i.e. the tight loop example above).
>
> This is an apples-and-apples comparison:
>
> >>> import timeit
> >>> timeit.Timer("Len = seq.__len__; Len()", "seq = range(12)").repeat()
>
> [1.3109469413757324, 0.7687380313873291, 0.55280089378356934]>>> timeit.Timer("len(seq)", "seq = range(12)").repeat()
>
> [0.60111594200134277, 0.5977931022644043, 0.59935498237609863]
>
> The time to do the lookup and call the method is about 0.6 microseconds
> whether you do it manually or let len() do it.

That assumes you know the internals of len(). Perhaps it does
something smarter for lists, or perhaps attribute lookup is faster at
the C level. I don't know, and that's exactly the point, I don't need
to know the internals to do the comparison of two callables.

> The logic behind the micro-optimization trick is to recognize when you
> can avoid the cost of repeated method lookups by doing it once only. That
> is not relevant to the question of whether len() should be a function or
> a method.

No disagreement here; I didn't bring up performance and it's not at
all a reason I consider len() as a function to be a design mistake.
What I dispute is Neil's assertion that "len as a builtin can be
faster than len as an attribute" and bringing as evidence the timings
that include attribute lookups. That statement is just wrong;
comparing X to an attribute assumes you have the attribute in the
first place, you don't need to look it up.

George

Chris Mellon

unread,
Oct 31, 2007, 7:58:05 PM10/31/07
to pytho...@python.org

For the record, the apples to apples way is to STORE_FAST len, because
what this does is compare the speed of LOAD_GLOBAL(len) to a
LOAD_ATTR, a STORE_FAST, and a LOAD_FAST. len() is still faster on
builtins when you do it "right":

C:\>python -m timeit -s "s=range(12);l=type([]).__len__" "l(s)"
1000000 loops, best of 3: 0.258 usec per loop

C:\>python -m timeit -s "l = len;s=range(12)" "l(s)"
10000000 loops, best of 3: 0.0994 usec per loop

This is absolutely apples to apples because exactly the same bytecodes
are being timed.

However, you can make the first faster by using an already bound
method. This saves some runtime cost inside the __len__ method, and it
saves a LOAD_FAST in the call. It's still slower than len(), by the
barest fraction of a second (I ran these a few dozen time each and the
difference, while tiny, was consistent - __len__ was always just over
a tenth of a usec, len() was always just under it).

C:\>python -m timeit -s "s=range(12);l=s.__len__" "l()"
10000000 loops, best of 3: 0.114 usec per loop

> > [0.60111594200134277, 0.5977931022644043, 0.59935498237609863]
> >
> > The time to do the lookup and call the method is about 0.6 microseconds
> > whether you do it manually or let len() do it.
>
> That assumes you know the internals of len(). Perhaps it does
> something smarter for lists, or perhaps attribute lookup is faster at
> the C level. I don't know, and that's exactly the point, I don't need
> to know the internals to do the comparison of two callables.
>

Types implemented in C implement the sequence protocol as a struct of
function pointers, which len() derefs and calls directly, while
__len__ on the builtin is a Python boundmethod.

The speed difference will be reversed for types implemented in Python,
though. So now you know.

> > The logic behind the micro-optimization trick is to recognize when you
> > can avoid the cost of repeated method lookups by doing it once only. That
> > is not relevant to the question of whether len() should be a function or
> > a method.
>
> No disagreement here; I didn't bring up performance and it's not at
> all a reason I consider len() as a function to be a design mistake.
> What I dispute is Neil's assertion that "len as a builtin can be
> faster than len as an attribute" and bringing as evidence the timings
> that include attribute lookups. That statement is just wrong;
> comparing X to an attribute assumes you have the attribute in the
> first place, you don't need to look it up.
>

And I don't think it's a design mistake for all the other reasons
mentioned, not because it's 6 thousands of a millisecond faster in a
microbenchmark.

Carl Banks

unread,
Nov 1, 2007, 1:48:12 AM11/1/07
to
On Oct 31, 6:29 pm, Steven D'Aprano <st...@REMOVE-THIS-

cybersource.com.au> wrote:
> On Wed, 31 Oct 2007 07:59:58 -0700, Carl Banks wrote:
> > Python considers len to be an operator for all intents and purposes.
> > Python chose to spell this operator like a regular function, but it
> > could easily have given a special syntax to the length operation (for
> > instance, $#x).
>
> I hope you're not serious that $# would make a good operator.

If you happen to know where I borrowed it from, it would be pretty
evident that I wasn't being serious.


Carl Banks

Carl Banks

unread,
Nov 1, 2007, 2:00:15 AM11/1/07
to
On Oct 30, 1:30 am, George Sakkis <george.sak...@gmail.com> wrote:
> Having a builtin len() that calls the method __len__
> seems (using your words) "not only foolish but wasteful".

But what about (for instance) having the bitwise not operator (^)
calling __bitwise_not__. Is that foolish and wasteful? Would a
hypothetical special syntax for len be foolish and wasteful.

All I'm trying to say here is that len is a built-in for a reason:
because Python considers len to be an operator. It's not inconsistent
design. It's not a defective spelling for a method. len was
deliberately given a status greater than method calls.


Carl Banks

Steven D'Aprano

unread,
Nov 1, 2007, 10:24:38 AM11/1/07
to
On Wed, 31 Oct 2007 22:48:12 -0700, Carl Banks wrote:

>> I hope you're not serious that $# would make a good operator.
>
> If you happen to know where I borrowed it from, it would be pretty
> evident that I wasn't being serious.

Ooh, now I'm curious.


--
Steven.

Tim Roberts

unread,
Nov 1, 2007, 11:40:59 PM11/1/07
to

Seriously? You didn't know that $#x in perl returns the length of the
array @x, minus 1?
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Steven D'Aprano

unread,
Nov 2, 2007, 3:29:06 AM11/2/07
to
On Fri, 02 Nov 2007 03:40:59 +0000, Tim Roberts wrote:

> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
>
>>On Wed, 31 Oct 2007 22:48:12 -0700, Carl Banks wrote:
>>
>>>> I hope you're not serious that $# would make a good operator.
>>>
>>> If you happen to know where I borrowed it from, it would be pretty
>>> evident that I wasn't being serious.
>>
>>Ooh, now I'm curious.
>
> Seriously? You didn't know that $#x in perl returns the length of the
> array @x, minus 1?

I don't speak Perl. You know there are million of us who have managed to
avoid it.


--
Steven.

Paul Rubin

unread,
Nov 2, 2007, 4:05:25 AM11/2/07
to
Steven D'Aprano <ste...@REMOVE.THIS.cybersource.com.au> writes:
> > Seriously? You didn't know that $#x in perl returns the length of the
> > array @x, minus 1?
> I don't speak Perl. You know there are million of us who have managed to
> avoid it.

I used to use perl (though I was never an expert) and I didn't know that
$#x returns yada yada. Lucky me.

Bruno Desthuilliers

unread,
Nov 2, 2007, 4:35:40 AM11/2/07
to
Steven D'Aprano a écrit :

> On Fri, 02 Nov 2007 03:40:59 +0000, Tim Roberts wrote:
>
>> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> wrote:
>>
>>> On Wed, 31 Oct 2007 22:48:12 -0700, Carl Banks wrote:
>>>
>>>>> I hope you're not serious that $# would make a good operator.
>>>> If you happen to know where I borrowed it from, it would be pretty
>>>> evident that I wasn't being serious.
>>> Ooh, now I'm curious.
>> Seriously? You didn't know that $#x in perl returns the length of the
>> array @x, minus 1?
>
>
>
> I don't speak Perl.

Nor do I, but such an ugly syntax is a sure hint !-)

0 new messages