Запрос функций Python по подписи - PullRequest
2 голосов
/ 26 января 2011

Как лучше всего документировать / декорировать ваши функции / методы Python, чтобы вы могли легко запрашивать их по сигнатуре (например, количество аргументов, тип аргумента и тип возвращаемого значения)?

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

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

@validate(args=((int, range(1,10), (float, range(1,10)), (bool,)), returns=(int,range(-10,10))
def myfunc(a, b, c):
    result = do_stuff
    return result

и затем сможете запрашивать похожие функции, выполняя что-то вроде:

similar_functions = find_functions(like=myfunc)

Существуют ли какие-либо стандартные инструменты или библиотеки по этой линии?

Ответы [ 3 ]

2 голосов
/ 26 января 2011

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

>>> import collections
>>> tags = collections.defaultdict(set)
>>>
>>> def tag(tag):
...     def decorator(func):
...             tags[tag].add(func)
...             func.tag = tag
...             return func
...     return decorator
...
>>> @tag("foo")
... def a(): pass
...
>>> @tag("foo")
... def b(): pass
...
>>> tags['foo']
{<function b at 0x0000000002BF2448>, <function a at 0x0000000002BD5A48>}

similar тривиально:

def similar(func):
    return signatures[func.sig]
2 голосов
/ 26 января 2011

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

Декораторы, подобные показанному вами, кажутся лучшим решением для 2.x, если вам нужна информация о типе.Но я бы, вероятно, сделал их синтаксис немного менее круглым:

@validate(a=(int, 1, 10), b=(float, 1, 10), c=bool, returns=(int, -10, 10))
def foo(a, b, c): ...

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

Обратите внимание, что вам понадобится специальная обработка для *arg и **kwarg: это гораздо сложнее, чтобы предоставить информацию о типе дляи я не знаю, насколько f1(int, int, int) похож на f2(int, *ints), не говоря уже о f3(int, **kwargs).

0 голосов
/ 26 января 2011

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

Просто сделайте это.

all_functions_of_some_sig = [
    myfunc, myfunc2, myotherfunc, ... 
]

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


Возможно, это проще

def myfunc( a, b, c ):
    return something
myfunc.args= ((int, range(1,10), (float, range(1,10)), (bool,))
myfunc.returns= (int,range(-10,10))

patterns= collections.defaultdict( list )
for f in __all__:
    patterns[f.args,f.returns]= f

Это то, что вам нужно?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...