Подтвердить что ты не робот

Есть ли карта без результата в python?

Иногда я просто хочу выполнить функцию для списка записей - например:

for x in wowList:
   installWow(x, 'installed by me')

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

map(lambda x: installWow(x, 'installed by me'), wowList)

Но это, конечно, создает хороший список [None, None,...], поэтому мой вопрос заключается в том, есть ли подобная функция без возвращаемого списка - так как мне это просто не нужно.

(конечно же, я также могу использовать _x и, таким образом, не оставлять видимый след - но картографическое решение выглядит так аккуратно...)

4b9b3361

Ответ 1

Вы можете использовать встроенную функцию any для применения функции без оператора к любому элементу, который возвращается генератором без создания списка. Это может быть достигнуто следующим образом:

any(installWow(x, 'installed by me') for x in wowList)

Я нашел это самым кратким идолом того, чего вы хотите достичь.

Внутренне функция installWow возвращает None, которая вычисляет False в логических операциях. any в основном применяет операцию сокращения or ко всем элементам, возвращаемым генератором, которые все None, конечно, поэтому он должен перебирать все элементы, возвращаемые генератором. В конце он возвращает False, но это не должно вас беспокоить. Хорошо: список не создается как побочный эффект.

Обратите внимание, что это работает только до тех пор, пока ваша функция возвращает значение, которое оценивается как False, например, None или 0. Если в какой-то момент оно возвращает значение True, например 1, он не будет применяться ни к одному из оставшихся элементов вашего итератора. Чтобы быть в безопасности, используйте эту идиому в основном для функций без оператора возврата.

Ответ 2

Вы можете создать свою собственную "каждую" функцию:


def each(fn, items):
    for item in items:
        fn(item)


# called thus
each(lambda x: installWow(x, 'installed by me'), wowList)

В основном это просто карта, но без возвращаемых результатов. Используя функцию, вы убедитесь, что переменная "item" не течет в текущую область.

Ответ 3

Как насчет этого?

for x in wowList:
    installWow(x, 'installed by me')
del x

Ответ 4

Каждое выражение оценивает что-то, поэтому вы всегда получаете результат, независимо от того, как вы это делаете. И любой такой возвращенный объект (как и ваш список) впоследствии будет выброшен, потому что больше нет ссылки на него.

Чтобы уточнить: очень мало вещей в python - это утверждения, которые ничего не возвращают. Даже вызов функции, например

doSomething()

по-прежнему возвращает значение, даже если оно сразу же отбрасывается. В python не существует такой функции, как различие функции/процедуры Pascal.

Ответ 5

Вы можете попробовать следующее:

filter(lambda x: installWow(x, 'installed by me') and False, wowList)

Таким образом, результат возврата - это пустой список, независимо от того, что.

Или вы можете просто отказаться от and False, если вы можете заставить installWow() всегда возвращать False (или 0 или None или другое выражение, которое оценивает значение false).

Ответ 6

Вы можете использовать фильтр и функцию, которая не возвращает значение True. Вы получите пустой список возврата, так как фильтр добавляет только значения, которые оцениваются как true, что, я полагаю, спасет вам некоторую память. Что-то вроде этого:

#!/usr/bin/env python
y = 0
def myfunction(x):
  global y
  y += x

input = (1, 2, 3, 4)

print "Filter output: %s" % repr(filter(myfunction, input))
print "Side effect result: %d" % y

Запуск он производит этот вывод:

Filter output: ()
Side effect result: 10

Ответ 7

если нормально разорвать wowList

while wowList: installWow(wowList.pop(), 'installed by me')

если вы хотите сохранить wowList

wowListR = wowList[:]
while wowListR: installWow(wowListR.pop(), 'installed by me')

и если порядок имеет значение

wowListR = wowList[:]; wowListR.reverse()
while wowListR: installWow(wowListR.pop(), 'installed by me')

Хотя в качестве решения головоломки мне нравится первая:)

Ответ 8

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

reduce(lambda x,y: x(y, 'installed by me') , wowList, installWow)

только твист - установка. Вернемся, например.

def installWow(*args):
    print args
    return installWow

Ответ 9

Я проверил несколько разных вариантов, и вот результаты, которые я получил.

Python 2:

>>> timeit.timeit('for x in xrange(100): L.append(x)', 'L = []')
14.9432640076
>>> timeit.timeit('[x for x in xrange(100) if L.append(x) and False]', 'L = []')
16.7011508942
>>> timeit.timeit('next((x for x in xrange(100) if L.append(x) and False), None)', 'L = []')
15.5235641003
>>> timeit.timeit('any(L.append(x) and False for x in xrange(100))', 'L = []')
20.9048290253
>>> timeit.timeit('filter(lambda x: L.append(x) and False, xrange(100))', 'L = []')
27.8524758816

Python 3:

>>> timeit.timeit('for x in range(100): L.append(x)', 'L = []')
13.719769178002025
>>> timeit.timeit('[x for x in range(100) if L.append(x) and False]', 'L = []')
15.041426660001889
>>> timeit.timeit('next((x for x in range(100) if L.append(x) and False), None)', 'L = []')
15.448063717998593
>>> timeit.timeit('any(L.append(x) and False for x in range(100))', 'L = []')
22.087335471998813
>>> timeit.timeit('next(filter(lambda x: L.append(x) and False, range(100)), None)', 'L = []')
36.72446593800123

Обратите внимание, что значения времени не так точны (например, относительная производительность первых трех параметров варьировалась от прогона до запуска). Я пришел к выводу, что вы должны просто использовать цикл, более читабельный и, по крайней мере, выполнять как альтернативы. Если вы хотите избежать загрязнения пространства имен, просто del переменную после ее использования.

Ответ 10

сначала переписать цикл for как выражение генератора, который не выделяет никакой памяти.

(installWow(x,  'installed by me') for x in wowList )

Но это выражение на самом деле ничего не делает, не найдя способ его уничтожить. Поэтому мы можем переписать это, чтобы получить что-то определенное, а не полагаться на результат None installWow.

( [1, installWow(x,  'installed by me')][0] for x in wowList )

который создает список, но возвращает только константу 1. это можно удобно использовать с помощью reduce

reduce(sum, ( [1, installWow(x,  'installed by me')][0] for x in wowList ))

Что удобно возвращает количество элементов в wowList, которые были затронуты.

Ответ 11

Просто сделайте installWow return None или сделайте последнее утверждение таким:


def installWow(item, phrase='installed by me'):
  print phrase
  pass

и используйте это:


list(x for x in wowList if installWow(x))

x не будет задано в глобальном пространстве имен, а возвращаемый список - [] a singleton

Ответ 12

Если вы беспокоитесь о необходимости контролировать возвращаемое значение (которое вам нужно использовать для использования фильтра ) и предпочитаете более простое решение, чем пример уменьшить выше, затем рассмотрите возможность использования уменьшить напрямую. Ваша функция должна будет взять дополнительный первый параметр, но вы можете игнорировать его или использовать лямбда для его удаления:

reduce(lambda _x: installWow(_x, 'installed by me'), wowList, None)

Ответ 13

Позвольте мне предисловие к этому, сказав, что, кажется, оригинальный плакат больше беспокоился о беспорядке пространства имен, чем что-либо еще. В этом случае вы можете обернуть свои рабочие переменные в отдельное пространство имен функций и вызвать его после объявления, или вы можете просто удалить их из пространства имен после того, как вы использовали их с помощью команды del. Или, если у вас есть несколько переменных для очистки, определите функцию со всеми временными переменными в ней, запустите ее, а затем del.

Читайте, если основной проблемой является оптимизация:

Еще три способа, потенциально быстрее, чем другие, описанные здесь:

  • Для Python >= 2.7 используйте collections.deque((installWow (x, 'установлен мной) для x в wowList), 0) # сохраняет 0 записей при повторении всего генератора, но да, все еще имеет побочный продукт конечного объекта вместе с внутренней проверкой длины элемента.
  • Если вы беспокоитесь об этих накладных расходах, установите cytoolz. Вы можете использовать count, который по-прежнему имеет побочный продукт с приращением счетчика, но это может быть меньшее количество циклов, чем проверка на предмет, не уверен. Вы можете использовать его вместо any() следующим образом:
  • Замените выражение генератора на itertools.imap(когда installWow никогда не возвращает True. В противном случае вы можете рассмотреть itertools.ifilter и itertools.ifilterfalse с None для предиката): any (itertools.imap(installWow, wowList, itertools.repeat( 'установлен мной')))

Но реальная проблема заключается в том, что функция возвращает что-то, и вы не хотите, чтобы она возвращала что-либо. Поэтому, чтобы решить эту проблему, у вас есть 2 варианта. Один из них заключается в том, чтобы реорганизовать ваш код, поэтому installWow принимает в wowList и выполняет итерацию внутри него. Другой - скорее раздумья, но вы можете загрузить функцию installWow() в скомпилированный ast, например:

lines,lineno=inspect.getsourcelines(func) # func here is installWow without the parens
return ast.parse(join(l[4:] for l in lines if l)) # assumes the installWow function is part of a class in a module file.. For a module-level function you would not need the l[4:]

Затем вы можете сделать то же самое для внешней функции и пройти по аш, чтобы найти цикл for. Затем в теле цикла for вставьте тело функции функции instalWow(), сопоставляя имена переменных. Затем вы можете просто вызвать exec на самой аш и предоставить словарь пространства имен с нужными переменными, заполненными. Чтобы убедиться, что ваши изменения дерева верны, вы можете проверить, как выглядит конечный исходный код, запустив astunparse.

И если этого недостаточно, вы можете перейти на cython и написать файл .pyx, который сгенерирует и скомпилирует .c файл в библиотеку с привязками python. Затем, по крайней мере, потерянные циклы не будут потрачены на преобразование в объекты python и обратно, а также проверку типов все снова.

Ответ 14

Кто-то должен ответить -

Более питонический способ - не беспокоиться о загрязнении пространства имен и использовать __all__ для определения общедоступных переменных.

myModule/__init__.py:
     __all__ = ['func1', 'func2']

     for x in range(10): 
         print 'init {}'.format(x)

     def privateHelper1(x):
         return '{}:{}'.format(x,x)

     def func1(): 
         print privateHelper1('func1')

     def func2(): 
         print privateHelper1('func1')

затем

python -c "import myModule; help(myModule);"

init 0
init 1
init 2
init 3
init 4
init 5
init 6
init 7
init 8
init 9
Help on package mm:

NAME
    myModule

FILE
    h:\myModule\__init__.py

PACKAGE CONTENTS


FUNCTIONS
    func1()

   func2()

DATA
   __all__ = ['func1', 'func2']