0

The functional map(func,iterable) could be easily applied to normal functions, but if I want to apply the a_method to a list of instances, how can I do it? I know list comprehensions can do this in a snap, but still want to see if a functional way exist and also feels pythonic.

class cls(object):
    def __init__(self,val):
        self.val=val
    def clstest(self,val):
        return self.val==val
a=cls(9)
b=cls(18)
c=cls(19)
lst=[a,b,c]

Then the following works:list(map(repr,lst)) returns

['<__main__.Cls object at 0x00000000070EDB70>',
 '<__main__.Cls object at 0x00000000070EDBE0>',
 '<__main__.Cls object at 0x00000000070EDE80>']

, but list(map(clstest(10),lst)) will have error msg:

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-165-f10396f98b58> in <module>()
----> 1 list(map(clstest,lst))

NameError: name 'clstest' is not defined

Update: correct my mistake in defining the class. The error msg still remains.

NathaneilCapital
  • 1,389
  • 5
  • 17
  • 23
  • First of all, `def cls(object)` defines a function called `cls` that takes one parameter called `object`. If you want a class that inherits from `object`, you should go with `class cls(object)`. Secondly, try out `cls.clstest` in your `map` – inspectorG4dget Jan 23 '14 at 20:38

4 Answers4

1

Another possibility (with help from this answer)

class cls(object):
    def __init__(self,val):
        self.val=val
    def clstest(self,val):
        return self.val==val
a=cls(9)
b=cls(10)
c=cls(19)
lst=[a,b,c]
# use functools.partial
from functools import partial
list(map(partial(cls.clstest,val=10),lst))
Community
  • 1
  • 1
JPG
  • 2,224
  • 2
  • 15
  • 15
1

Is this what you are looking for?

import operator
lst = [ cls(9), cls(18), cls(19) ]
x = operator.methodcaller('clstest', 10)
map( x, lst )

The methodcaller function creates a callable object that invokes a named method on its argument, so for example x(lst[0]) is the same as lst[0].clstest(10).

chepner
  • 497,756
  • 71
  • 530
  • 681
0

You should wrap the function in a lambda:

list(map(lambda instance: instance.clstest(10), lst))

Or as you mentioned, as a list comprehension:

[instance.clstest(10) for instance in lst]

Also, this line makes me cry: lst=list([a,b,c]) should just be lst = [a,b,c]

mhlester
  • 22,781
  • 10
  • 52
  • 75
0

The very first word in your code should be class, not def. Accepted practices in Python is giving ClassNames (cls is usually used for class methods). And you indents need fixing.

Here is untetsted full answer

class MyClass(object):
    def __init__(self,val):
        self.val=val
    def clstest(self,val):
        return self.val==val

objects = [MyClass(v) for v in (9, 18,19)]
map(lambda o: o.clstest(10), objects)

The answer is - yes, you can

volcano
  • 3,578
  • 21
  • 28
  • This is very true (and probably just a typo copying into SO), but I'm not convinced it answers OP's question. – mhlester Jan 23 '14 at 20:43
  • @mhlester, I did not compete for answer - you already provided one. Did you try yours - has it worked with definitions as they are? – volcano Jan 23 '14 at 20:47
  • (downvote wasn't me btw). If you're not answering the question, this should be a comment, not an answer – mhlester Jan 23 '14 at 20:49
  • You did neither - with wrong definitions your answer is useless – volcano Jan 23 '14 at 20:50
  • @NathaneilCapital, because *clstest* is defined within a boundary of the class. See my edited answer – volcano Jan 23 '14 at 21:05
  • @volcano, you're right. I did not realize each of our answers on their own would leave OP with the same error. I apologize. – mhlester Jan 23 '14 at 21:05
  • @mhlester, an honest mistake :) – volcano Jan 23 '14 at 21:06
  • I think this answer and the above `functools.partial` doing the job, both syn taxes are less ideal, lambda probably better. – NathaneilCapital Jan 25 '14 at 16:56
  • @NathaneilCapital, there is nothing wrong with syntax in other two answers - but in simple cases **partial** is an overkill. **partial** approach is extremely useful for callbacks - but creating it on every iteration is extremely wasteful. **methodcaller** (new for me too) is good too. It is especially good when you have common methods for more than one class - or when an object does not expose API explicitly (some specialized packages? I have seen cases like that). In the end of the day, a choice between **lambda** and **methodcaller** is a matter of style – volcano Jan 26 '14 at 06:14