Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>It sounds like you have a <code>list</code> of, say, 10 items, and then you want to run 50 functions on each item in the <code>list</code>, and you don't want to have to write 50 <code>for</code> loops.</p> <p>One possibility is to write a function that wraps that up:</p> <pre><code>def apply(method, seq): for item in seq: method(item) </code></pre> <p>Then, instead of this:</p> <pre><code>for thing in self.list_of_objects: # Yuck!! thing.some_function() for thing in self.list_of_objects: # Yuck!! thing.other_function() for thing in self.list_of_objects: # Yuck!! thing.third_function() # ... 47 more times </code></pre> <p>You can do this:</p> <pre><code>apply(ThingClass.some_function, self.list_of_objects) apply(ThingClass.other_function, self.list_of_objects) apply(ThingClass.third_function, self.list_of_objects) # ... 47 more times </code></pre> <p>Functions and methods are first-class objects in Python, just like anything else, so you can pass them around to other functions easily. Of course <code>first_thing.some_function</code> and <code>second_thing.some_function</code> are actually different bound methods; the trick is that you can get the unbound method from the class, and then pass it the object as an explicit <code>self</code> parameter. (Try printing out <code>first_thing.some_function</code>, <code>ThingClass.some_function</code>, <code>type(first_thing.some_function)</code>, and <code>type(ThingClass.some_function)</code>, and playing with them in the interactive interpreter.)</p> <p>This assumes, of course, that the reason all of these items have the same methods is that they're instances of the same class. If that's not true, and you're relying on duck typing instead, then you need something slightly different:</p> <pre><code>def apply(methodname, seq): for item in seq: getattr(item, methodname)() apply('some_function', self.list_of_objects) # ... 49 more times </code></pre> <p>Here, the trick is the <code>getattr</code> function, which lets you get any method or member by name at runtime.</p> <p>But if you think about it, what you really want here is to iterate over those 50 unbound methods or names, and not have to repeat yourself at all. For example:</p> <pre><code>for name in ('some_function', 'other_function', 'third_function', # ... 47 more names ): for obj in self.list_of_objects: getattr(obj, name)() </code></pre> <p>Note that the first version of the <code>apply</code> method could just as easily be replaced by the built-in <code>map</code> (only in Python 2.x, not 3.x), or even a list comprehension. However, there are some reasons not do to that:</p> <ul> <li>It's generally considered questionable style to use <code>map</code> or a comprehension when you're only calling the function for its side-effects.</li> <li>If you have a <em>lot</em> of items, instead of just 50*10, it wastes memory and time building up <code>list</code>s of results that you don't need.</li> <li>In Python 3, <code>map</code> returns an iterator instead of a <code>list</code>, so it won't actually perform the functions at all unless you iterate over it somehow. (You're obviously using 2.x today, because of your <code>print</code> statements, but presumably one day you will switch to 3.x.)</li> </ul> <p>You can solve those problems by using <code>itertools.imap</code> (or a generator expression) instead of <code>map</code> (or a list comprehension) and disposing of the iterable by, e.g., feeding it into a 0-sized <code>deque</code>. But at that point, it's not exactly clear what your code is doing.</p> <p>Meanwhile, writing the function explicitly means it's easy to modify into, e.g., the second version when you discover you need to.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload