Map with no arguments and class method?
It seems pretty simple:
# builtins work fine:
>>> map (str, [(), (), ()])
['()', '()', '()']
# but no luck for class methods:
>>> class C (object):
... d开发者_Python百科ef m(self):
... return 42
...
>>> c = C()
>>> map(c.m, [(), (), ()])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: m() takes exactly 1 argument (2 given)
You need to add a parameter to your m method, where the argument of the map will be passed.
class C (object):
def m(self, x):
return 42
>>> c = C()
>>> map(c.m, [(), (), ()])
[42, 42, 42]
See, c.m is a bound method, already like calling m(c), you need a placeholder for the additional parameter passed by map
c
and the argument passed by map are the 2 arguments to m
your stack trace is complaining about:
TypeError: m() takes exactly 1 argument (2 given)
map(f, L)
always calls f
with a single argument whose values are taken from L
. It's always a single argument, never zero. The ()
s in the list are not argument lists, they are empty tuples. Outside of a function call, things in parentheses aren't arguments to a function, they are objects called "tuples" (think of them as immutable lists). Check the difference between str()
and str(())
- str
with no arguments gives ''
and not '()'
.
If you have tuples of arguments and want to call a callable (function or method) with these arguments, you can use itertools.starmap
. In particular, if you pass empty tuples the functions will be called with no arguments. It returns an iterator, so if you need a list you need to explicitly use list()
over the result
>>> import itertools
>>> f = lambda: 42
>>> L = [(), (), ()]
>>> values = itertools.starmap(f, L)
>>> print list(values)
[42, 42, 42]
In the general case, it works with any tuple of arguments:
>>> f = lambda *x: sum(x)
>>> L = [(1,2), (4, ), (5,6)]
>>> values = itertools.starmap(f, L)
>>> print list(values)
[3, 4, 11]
If you want to simply call a function multiple times and get the result, you might consider using a list comprehension or a generator expression instead.
>>> f = lambda: 42
>>> [f() for _ in xrange(3)]
[42, 42, 42]
>>> values = (f() for _ in xrange(3))
>>> print list(values)
[42, 42, 42]
If you have a list of empty tuples like in your example, you might use xrange(len(L))
in the place of xrange(3)
.
That's not a class method, it lacks the classmethod
decorator and self
should be cls
. But you don't want a class method here anyway, as class methods are methods which operate on classes (you can pass other objects, of course, but that's not the intended use case - the @classmethod
would be grossly misleading).
You're looking for the term "unbound method", which you get by refering to a member of the class, not to an instance thereof. Use C.m
. Note of course that the method will be called with self
as (in your example) a tuple and not an instance of C
. Normally, such trickery should be restricted to avoid this (e.g. str.lower
and a bunch of strings is O.K.).
First, that's not a class method. A class method takes the class as it's first argument, and is called on the class, not an instance of it:
class C(object):
@classmethod
def m(cls):
return 42
map(C.m, range(10))
However, that will still break because map
passes in each item from the iterable to the function, and your method only accepts one argument, the class.
If you change your method to accept the extra argument (def m(cls, arg)
), it will work. You could also use an instance method instead of a class method:
class C(object):
def m(self, *args): # or def m(self, n)
return 42
c = C()
map(c.m, range(10))
You forgot your decorator to make it a class method, but you probably want a static method:
static:
class C(object):
@staticmethod
def m(arg):
return 42
class:
class C(object):
@classmethod
def m(cls, arg):
#cls is a reference to the actual "C" type, not an instance of the "C" class.
return 42
m is a 1-argument method that takes an object of type C. The syntax "c.m" is actually equivalent to "m(c)", which is just 42. But 42 is not a function you can map over a list like [(),(),()].
The following should work:
class C (object):
def f(self): return lambda x: x+1
two,three,four = map(C().f(), [1,2,3])
Now C().* returns a function, instead of a constant.
精彩评论