Карта без аргументов и метода класса? - PullRequest
2 голосов
/ 02 марта 2011

Кажется довольно просто:

# 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 ]

4 голосов
/ 02 марта 2011

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).

4 голосов
/ 02 марта 2011

Вам нужно добавить параметр в ваш метод m, в который будет передан аргумент карты.

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

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

Видите, cm - это связанный метод, уже как вызов m (c), вынужен заполнитель для дополнительного параметра, передаваемого картой

c, а аргумент, передаваемый картой, является двумя аргументами m, на которые трассируется ваш стек:

TypeError: m() takes exactly 1 argument (2 given)
2 голосов
/ 02 марта 2011

Это не метод класса, в нем отсутствует декоратор classmethod, а self должно быть cls. Но вам все равно не нужен здесь метод класса, так как методы класса - это методы, которые работают с классами (конечно, вы можете передавать другие объекты, но это не тот случай использования - @classmethod будет вводить в заблуждение).

Вы ищете термин «несвязанный метод», который вы получаете, ссылаясь на члена класса , а не на его экземпляр. Используйте C.m. Обратите внимание, что метод будет вызываться с self как (в вашем примере) как кортеж, а не как экземпляр C. Обычно такие хитрости должны быть ограничены, чтобы избежать этого (например, str.lower и набор строк - О.К.).

1 голос
/ 02 марта 2011

Во-первых, это не метод класса.Метод класса принимает класс в качестве первого аргумента и вызывается для класса, а не для его экземпляра:

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

map(C.m, range(10))

Однако, он все равно будет прерываться, потому что map передает в каждый элемент из итерируемогок функции, и ваш метод принимает только один аргумент, класс.

Если вы измените свой метод для принятия дополнительного аргумента (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))
1 голос
/ 02 марта 2011

Вы забыли свой декоратор, чтобы сделать его методом класса, но вам, вероятно, нужен статический метод:

Статическая:

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
0 голосов
/ 02 марта 2011

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 (). * вместо этого возвращает функциюпостоянной.

...