Переименование функций с сохранением обратной совместимости

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

Простой пример, старый код:

def helloFunc(name):
    print 'hello %s' % name

Новое:

def hello_func(name):
    print 'hello %s' % name

Но обе функции должны работать:

>>hello_func('Alex')
>>'hello Alex'
>>helloFunc('Alf')
>>'hello Alf'

Я думаю о:

def helloFunc(name):
    hello_func(name)

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

Каков наилучший способ сделать это (исключая дублирование источника)? Возможно ли создание какого-то универсального декоратора?

Спасибо.

Ответ 1

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

def helloFunc():
    pass

hello_func = helloFunc

Конечно, было бы немного более чистым, если бы вы изменили имя фактической функции на hello_func, а затем создали псевдоним как:

helloFunc = hello_func

Это все еще немного беспорядочно, потому что он излишне загромождает пространство имен модулей. Чтобы обойти это, вы также можете иметь подмодуль, который предоставляет эти "псевдонимы". Тогда для ваших пользователей это будет так же просто, как изменить import module на import module.submodule as module, но вы не загромождаете пространство имен вашего модуля.

Возможно, вы даже можете использовать inspect, чтобы сделать что-то вроде этого автоматически (непроверено):

import inspect
import re
def underscore_to_camel(modinput,modadd):
    """
       Find all functions in modinput and add them to modadd.  
       In modadd, all the functions will be converted from name_with_underscore
       to camelCase
    """
    functions = inspect.getmembers(modinput,inspect.isfunction)
    for f in functions:
        camel_name = re.sub(r'_.',lambda x: x.group()[1].upper(),f.__name__)
        setattr(modadd,camel_name,f)

Ответ 2

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

def func_new(a):
    do_stuff()

def funcOld(a):
    import warnings
    warnings.warn("funcOld should not be called any longer.")
    return func_new(a)

Ответ 3

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

def funcOld(a):
    return a

func_new = funcOld

Ответ 4

Как ваш вопрос звучит очень похоже на усталость или подобное, я бы настоятельно рекомендовал использовать декораторы для более чистого кода. Фактически, кто-то из другого потока уже создал это для вас.