Вызов функции, имя которой совпадает с аргументом локальной функции

#python

Вопрос:

Предположим , я пишу модуль , который содержит вызываемую функцию normalize() и другую функцию double() , у которой также есть параметр с именем normalize . Изнутри double() я хочу , чтобы он вызывался normalize() , но это проблема, потому что параметр имеет то же имя, что и функция.

 def normalize(x):
    return x * 100

def double(n, normalize = True):
    n = n * 2
    if (normalize):
        n = normalize(n)
    return n
 

Это не работает, потому что вызов normalize(n) пытается использовать локальную переменную normalize вместо внешней функции с тем же именем.

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

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

 __all__ = ['normalize', 'double']

def normalize(x):
    return x * 100

normalize_copy = normalize

def double(n, normalize = True):
    n = n * 2
    if (normalize):
        n = normalize_copy(n)
    return n
 

Есть ли более простой способ сделать это?

Комментарии:

1. Может normalize_function = globals()['normalize'] быть ?

2. почему бы не изменить имя переменной на should_normalize , поскольку это еще более значимо

3. Честно говоря, ты слишком много об этом думаешь. У вас есть конфликт имен, поэтому два очевидных решения: (1) использовать пространства имен (т. Е. Импортировать модуль, содержащий функцию, или поместить его в класс) или (2) переименовать один из них ( 1 по should_normalize предложению @JoranBeasley).

4. @Selcuk или даже, используя a types.SimpleNamespace .

5. Смотрите Дзен Python : Simple is better than complex , [...] practicality beats purity , и Namespaces are one honking great idea -- let's do more of those!

Ответ №1:

Вот своего рода глупый обходной путь, но вы могли бы сделать это; он повторно normalize() связывает функцию с новым именем в списке параметров.

 def double(n, norm_func=normalize, normalize=True):
    n = n * 2
    if normalize:
        n = norm_func(n)
    return n
 

Комментарии:

1. Это действительно круто, так как оно полностью инкапсулировано.

Ответ №2:

Я настоятельно рекомендую вам изменить имя аргумента на should_normalize , так как это еще более значимо, чем normalize в данном контексте.

Если по какой-либо причине это не является для вас хорошим решением, я поддержу предложение из комментариев использовать инкапсуляцию пространства имен:

 import types

def normalize(x):
    return x * 100

NS = types.SimpleNamespace(normalize=normalize)

def double(n,normalize):
    n = n * 2
    if normalize:
        n = NS.normalize(n)
    return n
 

Ответ №3:

Вы можете достичь этого, если захотите немного изменить API, как показано ниже. Аргумент normalize теперь содержит значение функции, а не логическое значение.

 def normalize(x):
    return x * 100

def double(n, normalize = None):
    n = n * 2
    if (normalize):
        n = normalize(n)
    return n

print(double(10, normalize))
 

@tdelaney, мы можем инвертировать normalize аргумент, как показано ниже, если действие по умолчанию должно быть всегда normalizing .

 def normalize(x):
    return x * 100

def double(n, normalize = normalize):
    n = n * 2
    if (normalize):
        n = normalize(n)
    return n

print(double(10))
 

Комментарии:

1. Недостатком является то, что пользователи API должны будут знать, как вызывать функцию normalize.

Ответ №4:

Для меня ваше второе решение является самым простым, но на самом деле вам не нужно использовать __all__ , просто подчеркивание.

 _normalize = normalize  # For use in "double()", which has a param "normalize"

def double(n, normalize=True):
    n = n * 2
    if normalize:
        n = _normalize(n)
    return n
 

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

Комментарии:

1. Мне это нравится-это просто и делает свою работу.

Ответ №5:

Ответ заключается в изменении имени параметра. Вы можете напрямую запросить глобальную область для объекта

 def normalize(x):
    return x * 100

def double(n, normalize = True):
    n = n * 2
    if (normalize):
        n = globals()["normalize"](n)
    return n
 

Но тогда люди будут удивляться, почему вы просто не изменили название параметра.