没有参数和类方法的映射?

时间:2011-03-02 19:58:37

标签: python functional-programming map

看起来很简单:

# builtins work fine:
>>> map (str, [(), (), ()])
['()', '()', '()']

# but no luck for class methods:
>>> class C (object):
...   def 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)

6 个答案:

答案 0 :(得分:4)

您需要在m方法中添加一个参数,其中将传递地图的参数。

class C (object):
    def m(self, x):
        return 42

>>> c = C()
>>> map(c.m, [(), (), ()])
[42, 42, 42]

参见,c.m是一个绑定方法,就像调用m(c)一样,你需要一个占位符来为map传递的附加参数

c和map传递的参数是你的堆栈跟踪抱怨的m的2个参数:

TypeError: m() takes exactly 1 argument (2 given)

答案 1 :(得分:4)

map(f, L)始终使用单个参数调用f,其值取自L。它总是一个参数,永远不会为零。列表中的()不是参数列表,它们是空元组。在函数调用之外,括号中的内容不是函数的参数,它们是称为“元组”的对象(将它们视为不可变列表)。检查str()str(()) - str之间的区别,不带任何参数,'' '()'

如果你有参数元组并希望用这些参数调用可调用的(函数或方法),你可以使用itertools.starmap。特别是,如果传递空元组,则将调用函数而不使用参数。它返回一个迭代器,所以如果你需要一个列表,你需要在结果上明确使用list()

>>> import itertools
>>> f = lambda: 42
>>> L = [(), (), ()]
>>> values = itertools.starmap(f, L)
>>> print list(values)
[42, 42, 42]

在一般情况下,它适用于任何参数元组:

>>> f = lambda *x: sum(x)
>>> L = [(1,2), (4, ), (5,6)]
>>> values = itertools.starmap(f, L)
>>> print list(values)
[3, 4, 11]

如果您想简单地多次调用函数并获得结果,您可以考虑使用列表推导或生成器表达式。

>>> f = lambda: 42
>>> [f() for _ in xrange(3)]
[42, 42, 42]
>>> values = (f() for _ in xrange(3))
>>> print list(values)
[42, 42, 42]

如果您的示例中包含空元组列表,则可以在xrange(len(L))的位置使用xrange(3)

答案 2 :(得分:2)

这不是一个类方法,它缺少classmethod装饰器而self应该是cls。但是你不需要这里的类方法,因为类方法是对类进行操作的方法(当然,你可以传递其他对象,但这不是预期的用例 - @classmethod会产生严重误导)

您正在寻找术语“未绑定方法”,您可以通过引用的成员而不是其实例来获取该术语。使用C.m。请注意,该方法将使用self作为(在您的示例中)调用元组,而不是C的实例。通常,应该限制这种欺骗以避免这种情况(例如str.lower并且一串字符串是O.K。)。

答案 3 :(得分:1)

你忘了装饰器使它成为一个类方法,但你可能想要一个静态方法:

静态:

class C(object):
    @staticmethod
    def m(arg):
        return 42

类:

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

答案 4 :(得分:1)

首先,这不是一种类方法。类方法将类作为它的第一个参数,并在类上调用,而不是它的实例:

class C(object):
    @classmethod
    def m(cls):
        return 42

map(C.m, range(10))

然而,由于map将每个项目从iterable传递给函数,因此仍会中断,并且您的方法只接受一个参数,即类。

如果您更改方法以接受额外参数(def m(cls, arg)),它将起作用。您也可以使用实例方法而不是类方法:

class C(object):
    def m(self, *args): # or def m(self, n)
        return 42
c = C()
map(c.m, range(10))

答案 5 :(得分:0)

m是一个1参数方法,它接受C类型的对象。语法“cm”实际上等同于“m(c)”,它只是42.但是42不是一个可以映射到的函数列表如[(),(),()]。

以下内容应该有效:

class C (object):
    def f(self): return lambda x: x+1

two,three,four = map(C().f(), [1,2,3])

现在C()。 * 返回一个函数,而不是常量。