invoke method on many instances

A

Alan G Isaac

As a recurrent situation, I need to invoke the same method
on many instances. Speed matters, but the solution should
be pure Python. Is the following convenience function
a reasonable approach?

def apply2(itr, methodname, *args, **kwargs):
f = operator.methodcaller(methodname, *args, **kwargs)
for item in itr:
f(item)

(Comment: in the case at hand, the methods return None.)

Thank you,
Alan Isaac
 
S

Steven D'Aprano

As a recurrent situation, I need to invoke the same method on many
instances. Speed matters, but the solution should be pure Python. Is
the following convenience function a reasonable approach?

def apply2(itr, methodname, *args, **kwargs):
f = operator.methodcaller(methodname, *args, **kwargs)
for item in itr:
f(item)

I don't particularly like your naming conventions, but never mind.

You could also try this:

for obj in objects:
getattr(obj, methodname)(*args, **kwargs)




See also these recipes from the "Python Cookbook":

http://code.activestate.com/recipes/52289/
http://code.activestate.com/recipes/87370/
 
R

Rainer Grimm

Hallo Alan,
def apply2(itr, methodname, *args, **kwargs):
    f = operator.methodcaller(methodname, *args, **kwargs)
    for item in itr:
        f(item)
you can do it in a functional way.
.... def hello(self): return "hello: " + str
( self.__class__.__name__ )
....
class B(A):pass ....
class C(A):pass ....
a=A()
b=B()
c=C()
a.hello() 'hello: A'
b.hello() 'hello: B'
c.hello() 'hello: C'

map( (lambda obj : getattr(obj,"hello")()),(a,b,c)) ['hello: A', 'hello: B', 'hello: C']
[ getattr(obj,"hello")() for obj in (a,b,c)]
['hello: A', 'hello: B', 'hello: C']

Greetings from Rottenburg,
Rainer
 
P

Piet van Oostrum

Rainer Grimm said:
RG> Hallo Alan,RG> you can do it in a functional way. RG> ... def hello(self): return "hello: " + str
RG> ( self.__class__.__name__ )
RG> ...
class B(A):pass RG> ...
class C(A):pass RG> ...
a=A()
b=B()
c=C()
a.hello() RG> 'hello: A'
b.hello() RG> 'hello: B'
c.hello() RG> 'hello: C'

map( (lambda obj : getattr(obj,"hello")()),(a,b,c)) RG> ['hello: A', 'hello: B', 'hello: C']
[ getattr(obj,"hello")() for obj in (a,b,c)]
RG> ['hello: A', 'hello: B', 'hello: C']

But that creates an unnecessary list.
 
G

Gabriel Genellina

Are there any obvious considerations in choosing
between those two?

The operator.methodcaller version is faster in my tests for large
collections, but slightly slower when you have very few elements.

<code>
import operator
import timeit

class X:
def method(self, x, y, **kw): pass

def apply1(itr, methodname, *args, **kwargs):
for item in itr:
getattr(item, methodname)(*args, **kwargs)

def apply2(itr, methodname, *args, **kwargs):
f = operator.methodcaller(methodname, *args, **kwargs)
for item in itr:
f(item)

L=[X() for _ in range(3000)]
apply1(L,'method', 1, 2, foo=3)
apply2(L,'method', 1, 2, foo=3)

timeit.timeit(setup="from __main__ import apply1,apply2,L",
stmt="apply1(L,'method', 1, 2, foo=3)", number=1000)
timeit.timeit(setup="from __main__ import apply1,apply2,L",
stmt="apply2(L,'method', 1, 2, foo=3)", number=1000)
</code>
 
S

Simon Forman

Are there any obvious considerations in choosing
between those two?

The operator.methodcaller version is faster in my tests for large  
collections, but slightly slower when you have very few elements.

<code>
import operator
import timeit

class X:
   def method(self, x, y, **kw): pass

def apply1(itr, methodname, *args, **kwargs):
     for item in itr:
         getattr(item, methodname)(*args, **kwargs)

def apply2(itr, methodname, *args, **kwargs):
     f = operator.methodcaller(methodname, *args, **kwargs)
     for item in itr:
         f(item)

L=[X() for _ in range(3000)]
apply1(L,'method', 1, 2, foo=3)
apply2(L,'method', 1, 2, foo=3)

timeit.timeit(setup="from __main__ import apply1,apply2,L",  
stmt="apply1(L,'method', 1, 2, foo=3)", number=1000)
timeit.timeit(setup="from __main__ import apply1,apply2,L",  
stmt="apply2(L,'method', 1, 2, foo=3)", number=1000)
</code>

If your instances are all of the same class you can pass in the method
directly like so:

def apply3(iterator, method, *args, **kwargs):
for item in iterator:
method(item, *args, **kwargs)

class X:
def method(self, x, y, **kw): pass

items = [X() for _ in range(10)]

apply3(items, X.method, 1, 2, foo=3)

HTH,
~Simon
 
A

Alan G Isaac

En Sat, 18 Jul 2009 12:31:46 -0300, Alan G Isaac:


The operator.methodcaller version is faster in my tests for large
collections, but slightly slower when you have very few elements.


So it seems. Is this easily explained?

Thanks,
Alan Isaac
 
A

Aahz


What? Abbreviations are fine, but if someone asks you about one, it
would be nice to just expand it instead of replying with another
abbreviation.
--
Aahz ([email protected]) <*> http://www.pythoncraft.com/

"At Resolver we've found it useful to short-circuit any doubt and just
refer to comments in code as 'lies'. :)"
--Michael Foord paraphrases Christian Muirhead on python-dev, 2009-03-22
 
G

Gabriel Genellina

What? Abbreviations are fine, but if someone asks you about one, it
would be nice to just expand it instead of replying with another
abbreviation.

Ok, if you insist...

NLMPI = Ni La Más Puta Idea.
IHNFI = I Have No Fucking Idea.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top