it-roy-ru.com

Использование цикла for для определения нескольких функций - Python

Предположим, мне нужно создать 10 функций с именами add1, add2, ..., add10. Для каждого i addi принимает целое число x и выводит x + i

Python дал мне NameError, когда я попробовал следующее и оценил add2 (10).

for i in range(10):
    def addi(x):
        return x + (i+1)

Я знаю, что приведенный выше код неверен, поскольку определенные мной функции addi не являются изменяемыми; Я почти уверен, что все, что я сделал, переопределил ADDI 10 раз. Как можно быстро определить эти 10 функций?

5
jessica

Используйте functools.partial в сочетании со словарем в этой ситуации.

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

from functools import partial

def add(x, i):
    return x + i

d = {f'add{k}': partial(add, i=k) for k in range(1, 10)}

d['add3'](5)  # 8

Объяснение

  • Рекомендуется хранить переменное число связанных объектов в специально определенном словаре.
  • functools.partial - это функция высшего порядка, которая возвращает функцию ввода с фиксированными выбранными аргументами.
4
jpp

Функции вообще не изменяемы; но они могут иметь ссылки на данные, которые есть. В вашем фрагменте эта ссылка немного неясна, но i встречается только один раз в теле функции, как чтение. Поэтому он читает из некоторой внешней области, обычно это функция или модуль, в котором содержится ваш цикл for. Поскольку это общий контекст, каждая функция addi будет иметь одинаковую i

Другая проблема заключается в том, что вы используете имя addi на каждой итерации, и функция никогда не появлялась под другим именем. Поэтому все функции addi, которые были определены ранее, теряются. Это приводит нас к третьему вопросу; почему вы хотите создавать имена (например, имена функций) динамически? Почти всегда лучше использовать коллекцию, такую ​​как словарь d в ответе jpp. Иначе, какой код будет ссылаться на созданные вами функции? 

Все это говорит о том, что все еще можно делать то, что вы просили, хотя и очень странно. Вот один из способов:

def addfunc(n):
    def addn(x):
        return x+n
    return addn

for i in range(1,10):
    globals()['add{}'.format(i)] = addfunc(i)

Это злоупотребляет globals для вставки динамически созданных имен в пространство имен модуля и вкладывает каждую из этих функций в другую, чтобы создать пространства имен, содержащие их отдельные значения n. Другим классическим хаком было использование аргумента по умолчанию, и частичное применение of operator.add - более удобный функциональный стиль. 

4
Yann Vernier

Решение:

from types import FunctionType
from copy import copy

def copy_function(fn, name):
    return FunctionType(
    copy(fn.func_code),
    copy(fn.func_globals),
    name=name,
    argdefs=copy(fn.func_defaults),
    closure=copy(fn.func_closure)
)

for i in range(10):
    name = 'add' + str(i)
    def _add(x):
        return x + (i+1)
    globals()[name] = copy_function(_add, name)


print add1(2) # 4
print add3(8) # 12 

Использование функции копирования с https://stackoverflow.com/a/34796018/7529716

2
Yassine Faris

это помогает?

def createFunc(i):
  def func(x):
    return x + (i+1)
  return func

Затем просто создайте функции и сохраните их в массиве:

add = [createFunc(i) for i in range(10)]
print add[0](1)  # 1+(0+1) = 2
print add[0](2)  # 2+(0+1) = 3
print add[2](10) # 10+(2+1) = 13
print add[2](11) # 11+(2+1) = 14
1
r3v3r53

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

>>> def f(x, i):
...     return x + i + 1
... 
>>> from functools import partial
>>> for i in range(10):
...     globals()['add%s' % i] = partial(f, i=i)
... 
>>> add8(5)
14
>>> add3(5)
9

functools.partial реализует curry в Python для создания копии одного определения функции, где каждая копия "жестко кодирует" один или несколько аргументов функции.

1
Erik Cederstrand