to pass self or not to pass self

Joaquin Abian gatoygata2 at gmail.com
Thu Mar 18 01:55:41 CET 2010


On Mar 18, 12:11 am, Patrick Maupin <pmau... at gmail.com> wrote:
> On Mar 17, 5:34 pm, Joaquin Abian <gatoyga... at gmail.com> wrote:
>
>
>
> > On Mar 17, 3:43 pm, Patrick Maupin <pmau... at gmail.com> wrote:
>
> > > On Mar 17, 4:12 am, Bruno Desthuilliers <bruno.
>
> > > 42.desthuilli... at websiteburo.invalid> wrote:
> > > > Patrick Maupin a écrit :
>
> > > > > On Mar 16, 1:59 pm, Jason Tackaberry <t... at urandom.ca> wrote:
> > > > >> Why not create the bound methods at instantiation time, rather than
> > > > >> using the descriptor protocol which has the overhead of creating a new
> > > > >> bound method each time the method attribute is accessed?
>
> > > > > Well, for one thing, Python classes are open.  They can be added to at
> > > > > any time.  For another thing, you might not ever use most of the
> > > > > methods of an instance, so it would be a huge waste to create those.
>
> > > > A possible optimization would be a simple memoization on first access.
>
> > > I do agree that memoization on access is a good pattern, and I use it
> > > frequently.  I don't know if I would want the interpreter
> > > automagically doing that for everything, though -- it would require
> > > some thought to figure out what the overhead cost is for the things
> > > that are only used once.
>
> > > Usually, I will have a slight naming difference for the things I want
> > > memoized, to get the memoization code to run.  For example, if you add
> > > an underbar in front of everything you want memoized:
>
> > > class foo(object):
>
> > >     def _bar(self):
> > >         pass
>
> > >     def __getattr__(self, aname):
> > >         if aname.startswith('_'):
> > >             raise AttributeError
> > >         value = getattr(self, '_' + aname)
> > >         self.aname = value
> > >         return value
>
> > > obj = foo()
>
> > > So then the first time you look up obj.bar, it builds the bound
> > > method, and on subsequent accesses it just returns the previously
> > > bound method.
>
> > > Regards,
> > > Pat
>
> > Patrick, I was trying to understand the way your code was working but
> > I thing I'm not getting it.
>
> > I tested:
>
> > from time import time
>
> > class foo1(object):
> >     def _bar(self):
> >         pass
> >     def __getattr__(self, name):
> >         value = getattr(self, '_' + name)
> >         self.name = value
> >         return value
>
> > class foo2(object):
> >     def bar(self):
> >         pass
>
> > def a(klass, count):
> >     ins = klass()
> >     for i in xrange(count):
> >         z = ins.bar()
>
> > t0 = time()
> > a(foo1,  10000000)
> > t1 = time()
> > a(foo2, 10000000)
> > t2 = time()
>
> > print t1-t0   #75 sec
> > print t2-t1   #11 sec
>
> > foo1 is a lot slower than foo2. I understood that memoization should
> > optimize atribute calls. Maybe I am putting my foot in my mouth...
>
> > Thanks
> > JA
>
> I don't think you are putting your foot in your mouth.  I always have
> to test to remember what works faster and what doesn't.  Usually when
> I memoize as I showed, it is not a simple attribute lookup, but
> something that takes more work to create.  As I stated in my response
> to Terry, I overstated my case earlier, because of some optimizations
> in len(), I think.  Nonetheless, (at least on Python 2.6) I think the
> advice I gave to the OP holds.  One difference is that you are doing
> an attribute lookup in your inner loop.  I do find that performance
> hit surprising, but to compare with what the OP is describing, you
> either need to look up an unbound function in a dict and call it with
> a parameter, or look up a bound method in a dict and call it without
> the parameter.  Since the dict lookup doesn't usually do anything
> fancy and unexpected like attribute lookup, we pull the dict lookup
> out of the equation and out of the inner loop, and just do the
> comparison like this:
>
> >>> class foo(object):
>
> ...     def bar(self):
> ...         pass
> ...>>> x = foo()
>
> >>> def a(func, count):
>
> ...     for i in xrange(count):
> ...         z=func()
> ...>>> def b(func, param, count):
>
> ...     for i in xrange(count):
> ...         z=func(param)
> ...
>
>
>
> >>> a(x.bar,      100000000)  # 13 seconds
> >>> b(foo.bar, x, 100000000)  # 18 seconds
>
> Regards,
> Pat

OK, Thanks. Need to play a little bit with it.
Cheers
JA



More information about the Python-list mailing list