Используя того же декоратора (с аргументами) с функциями и методами

Я использую ленивое размонтирование: umount -l (это - нижний регистр L)

Ленивое размонтирование. Отсоедините файловую систему от иерархии файловой системы теперь и очистку все ссылки на файловую систему, как только это больше не занято. (Требует ядра 2.4.11 или позже.)

14
задан Matthew Schinckel 17 August 2009 в 15:08
поделиться

4 ответа

Чтобы расширить подход __ получить __ . Это можно обобщить до декоратора-декоратора.

class _MethodDecoratorAdaptor(object):
    def __init__(self, decorator, func):
        self.decorator = decorator
        self.func = func
    def __call__(self, *args, **kwargs):
        return self.decorator(self.func)(*args, **kwargs)
    def __get__(self, instance, owner):
        return self.decorator(self.func.__get__(instance, owner))

def auto_adapt_to_methods(decorator):
    """Allows you to use the same decorator on methods and functions,
    hiding the self argument from the decorator."""
    def adapt(func):
        return _MethodDecoratorAdaptor(decorator, func)
    return adapt

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

def allowed(*allowed_methods):
    @auto_adapt_to_methods
    def wrapper(func):
        def wrapped(request):
            if request not in allowed_methods:
                raise ValueError("Invalid method %s" % request)
            return func(request)
        return wrapped
    return wrapper

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

Использование декоратора:

class Foo(object):
    @allowed('GET', 'POST')
    def do(self, request):
        print "Request %s on %s" % (request, self)

@allowed('GET')
def do(request):
    print "Plain request %s" % request

Foo().do('GET')  # Works
Foo().do('POST') # Raises
17
ответ дан 1 December 2019 в 09:13
поделиться

Декоратор всегда применяется к функциональному объекту - пусть декоратор напечатает тип его аргумент, и вы сможете это подтвердить; и обычно он также должен возвращать объект функции (который уже является декоратором с правильным __ get __ ! -), хотя для последнего есть исключения.

Т.е. в коде:

class X(object):

  @deco
  def f(self): pass

deco (f) вызывается в теле класса, и пока вы все еще там, f - это функция, а не экземпляр типа метода. (Метод создается и возвращается в f s __ get __ , когда позже f обращается как атрибут X или его экземпляр ).

Может быть, вы лучше объясните одну игрушку, которую вы хотите использовать для своего декоратора, чтобы мы могли больше помочь ...?

Изменить : это также относится и к декораторам с аргументами, т.е.

class X(object):

  @deco(23)
  def f(self): pass

тогда это deco (23) (f) , который вызывается в теле класса,

5
ответ дан 1 December 2019 в 09:13
поделиться

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

Итак, этот класс будет делать то, что я хочу:

class methods(object):
    def __init__(self, *_methods):
        self.methods = _methods

    def __call__(self, func): 
        @wraps(func)
        def inner(*args, **kwargs):
            try:
                if args[0].method in self.methods:
                    return func(*args, **kwargs)
            except AttributeError:
                if args[1].method in self.methods:
                    return func(*args, **kwargs)
            return HttpResponseMethodNotAllowed(self.methods)
        return inner

Вот два варианта использования: украшение функции:

@methods("GET")
def view_func(request, *args, **kwargs):
    pass

и украшение методов класса:

class ViewContainer(object):
    # ...

    @methods("GET", "PUT")
    def object(self, request, pk, *args, **kwargs):
        # stuff that needs a reference to self...
        pass

Есть ли лучшее решение, чем использование обработки исключений?

2
ответ дан 1 December 2019 в 09:13
поделиться

Поскольку вы уже определяете __ get __ для использования декоратора в связанном методе, вы можете передать ему флаг, указывающий, используется ли он в методе или функции.

class methods(object):
    def __init__(self, *_methods, called_on_method=False):
        self.methods = _methods
        self.called_on_method

    def __call__(self, func):
        if self.called_on_method:
            def inner(self, request, *args, **kwargs):
                print request
                return func(request, *args, **kwargs)
        else:
            def inner(request, *args, **kwargs):
                print request
                return func(request, *args, **kwargs)
        return inner

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        new_func = self.func.__get__(obj, type)
        return self.__class__(new_func, called_on_method=True)
5
ответ дан 1 December 2019 в 09:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: