Доступ к аргументам функции из декоратора - PullRequest
8 голосов
/ 24 июня 2011

У меня есть обработчик запросов и декоратор, я бы хотел работать с собственным объектом внутри декоратора

class MyHandler(webapp.RequestHandler):

    @myDecorator
        def get(self):
            #code

Обновление: обратите внимание на разницу между первым и вторым я

class myDecorator(object):

    def __init__(self, f):
        self.f = f

    def __call__(self):
        #work with self
  1. MyHandler> get (функция)> self (аргумент)
  2. myDecorator> __call__ (функция)> self (аргумент)

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

Привет, могу ли я получить собственный аргумент MyHandlers из функции get внутри декоратора?

Обновление 2: я хочу реализовать декоратор для работы с пользовательским логином в google app engine:

У меня есть класс (requestHandler):

class SomeHandler(webapp.RequestHandler):
    @only_registered_users
    def get(self):
        #do stuff here

И я хочу украсить функцию get, чтобы проверить, вошел ли пользователь в систему:

from util.sessions import Session
import logging

class only_registered_users(object):

    def __init__(self, f):
        self.f = f

    def __call__(self):
        def decorated_get(self):
        logging.debug("request object:", self.request)
        session = Session()

        if hasattr(session, 'user_key'):
            return self.f(self)
        else:
            self.request.redirect("/login")


    return decorated_get

Я знаю, если пользователь вошел в систему, если имеет свойство 'user_key' в объекте сеанса.

В этом конкретном случае меня интересует основная цель

Дайте мне знать ваши предложения / мнения, если я делаю что-то не так!

Спасибо!

Ответы [ 5 ]

9 голосов
/ 24 июня 2011

Мне не совсем понятно, что вы хотите, но если вы просто хотите использовать аргументы декорированной функции, то это именно то, что делает основной декоратор.Таким образом, чтобы получить доступ, скажем, self.request из декоратора, вы можете сделать:

def log_request(fn):
    def decorated_get(self):
        logging.debug("request object:", self.request)
        return fn(self)
    return decorated_get

class MyHandler(webapp. RequestHandler):
    @log_request
    def get(self):
        self.response.out.write('hello world')

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

import inspect

def class_printer(fn):
    cls = inspect.getouterframes(inspect.currentframe())[1][3]
    def decorated_fn(self, msg):
        fn(self,cls+" says: "+msg)
    return decorated_fn

class MyClass():
    @class_printer
    def say(self, msg):
        print msg

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

>>> MyClass().say('hello')
MyClass says: hello
1 голос
/ 06 сентября 2016

источник

def p_decorate(func):
   def func_wrapper(name):
       return "<p>{0}</p>".format(func(name))
   return func_wrapper

@p_decorate
def get_text(name):
   return "lorem ipsum, {0} dolor sit amet".format(name)

print get_text("John")

# Outputs <p>lorem ipsum, John dolor sit amet</p>
1 голос
/ 27 июня 2011
import random

#decorator to the get function in order to check out if the user is logged in or not
def only_registered_users(func):
    def wrapper(handler):
        print 'Checking if user is logged in'
        if random.randint(0, 1):
            print 'User is logged in. Calling the original function.'
            func(handler)
        else:
            print 'User is NOT logged in. Redirecting...'
            # redirect code here
    return wrapper


class MyHandler(object):

    @only_registered_users
    def get(self):
        print 'Get function called'



m = MyHandler()
m.get()
1 голос
/ 24 июня 2011

Попробуйте этот подход: Может ли Python-декоратор метода экземпляра получить доступ к классу?

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

0 голосов
/ 27 июня 2011

Аргумент self для __call__ будет заполнен экземпляром, для которого вызывается декорированный метод. Отсюда нет способа получить доступ к объекту декоратора - __call__ - это связанный метод, и то, что вы запрашиваете, потребует, чтобы он был «дважды связан». Python не поддерживает это, поэтому экземпляр декоратора заменяется первым аргументом оформленной функции.

Самый простой способ обойти это - использовать вложенные функции, как рекомендует @Chris.

...