Python встроенный декоратор, который вызывает его аргумент? - PullRequest
0 голосов
/ 25 мая 2018

То, что я ищу, - это функция, которая вызывает свои аргументы, так что я могу использовать ее как декоратор, чтобы легко иметь дело с замыканиями.Это достаточно легко написать (если бы мне было интересно, я мог бы даже использовать *args и **kwargs):

def unclosure(f):
    return f()

@unclosure
def count():
    x = 0
    def _count():
        nonlocal x
        x += 1
        return x
    return _count

assert count() == 1
assert count() == 2

Но я чувствую, что это такая простая идея, что у этого есть быть встроенным в стандартную библиотеку python где-нибудь.Я проверил functools, но я не знаю, где еще проверить, и я не могу найти нужную вещь для ввода в Google.Кто-нибудь знает, если / где это существует?

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

То, что вы запрашиваете, идентично 1 функции apply, которая существовала в Python с 1.0 до 2.7, но устарела с 2.3. 2

Фактически, вы можете использовать его таким образом в 2.7:

@apply
def count():
    x=[0]
    def _count():
        x[0] += 1
        return x[0]
    return _count
assert count() == 1
assert count() == 2

Почему это устарело?

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

Но до 2.3Это было не совсем так.В тривиальных случаях вы можете просто написать это сами: lambda f: f() или def apply(f): return f().Но для нетривиальных примеров, перед распаковкой синтаксиса, вы не могли сделать «идеальную пересылку» для аргументов, поэтому вы не могли симулировать каждое использование apply.Вот почему это было добавлено.И, как только он больше не был нужен, он устарел.

Несколько человек жаловались, что писать его самостоятельно немного медленнее, чем встроенный C, но никто никогда не придумал сценарий использования, в котором это делалоразница, но дополнительная косвенность вызова функции уже не делала все это слишком медленным для использования в первую очередь.И если вы посмотрите на огромное количество открытого исходного кода, написанного на Python 2.3-2.6, практически ни один из них не использует apply.И никто никогда не писал и не публиковал расширение C для сохранения или apply, чтобы они могли продолжать его использовать.Никто не писал ни одного для 3.x за последнее десятилетие.

Когда обсуждался «Python 3000» (что стало 3.0), одной из первых вещей, которые пришли к устранению всех устаревших функций.Который распространился на вещи, которые не устарели, но Гвидо не видел в этом необходимости, например reduce.Вы можете прочитать архивы списков рассылки, чтобы увидеть, что люди пришли защищать некоторые функции и конструкции, обычно успешно, но я не помню и не могу найти никого, кто пытался защитить apply.Единственное обсуждение - сводка в PEP 3100 :

apply(): используйте f(*args, **kw) вместо [2]

… где ссылкауказывает на (неработающую ссылку на) Python сожаления Гвидо , аргумент которого не более, чем называть его «реликвией».


1.Или, скорее, более слабая версия apply, которая не принимает никаких аргументов.

2.IIRC (я не могу найти соответствующую документацию), это произошло до того, как у Python появилось реальное понятие «не рекомендуется».Он был помечен как «несущественный» и перемещен в конец страницы с документами, и только где-то около 2,5 или 2,6 он стал задним числом устаревшим с 2.3.

0 голосов
/ 25 мая 2018

Насколько мне известно, в стандартной библиотеке такой функции не существует.

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

@unclosure
def count():
    """docstring"""
    x = 0
    def _count():
        nonlocal x
        x += 1
        return x
    return _count

print(count)  # <function count.<locals>._count at 0x7f3282dac620>
print(count.__doc__)  # None

Что означает, что в действительности это должно быть реализовано так:

import functools

def unclosure(f):
    func = f()
    functools.update_wrapper(func, f)
    return func

@unclosure
def count():
    """docstring"""
    x = 0
    def _count():
        nonlocal x
        x += 1
        return x
    return _count

print(count)  # <function count at 0x7f3892f7c620>
print(count.__doc__)  # docstring
0 голосов
/ 25 мая 2018

Обычно это реализуется с использованием класса, а не замыкания.

class Count:
    def __init__(self):
        self.x = 0

    def __call__(self):
        self.x += 1
        return self.x

count = Count()
assert count() == 1
assert count() == 2
...