The decorator login_required is passed the function (hello in this case).
So what you want to do is:
def login_required(f):
# This function is what we "replace" hello with
def wrapper(*args, **kw):
args[0].client_session['test'] = True
logged_in = 0
if logged_in:
return f(*args, **kw) # Call hello
else:
return redirect(url_for('login'))
return wrapper
Answer from brian-brazil on Stack OverflowThe decorator login_required is passed the function (hello in this case).
So what you want to do is:
def login_required(f):
# This function is what we "replace" hello with
def wrapper(*args, **kw):
args[0].client_session['test'] = True
logged_in = 0
if logged_in:
return f(*args, **kw) # Call hello
else:
return redirect(url_for('login'))
return wrapper
kwargs is a dictionary containing argument as keys and values as values.
So all you need to do is check:
some_var = kw['my_property']
python - access function arguments from function decorator - Stack Overflow
How to access inner functions parameters using a Decorator?
python - Accessing function arguments from decorator - Stack Overflow
Decorators get the decorated args?
Basically I have multiple functions in a library which take in pandas Dataframe objects and perform operations on them. These include merges, or filtering.
I want to log the rows that are being filtered out due to these functions.
Every dataset has a unique identifier like an index and so I want to log the index number.
I was thinking of using a decorator for this, something like below.
Essentially what I want to do in the decorator is:
# func is the function that will be doing the merges or filters.
def log_filtered_rows(func):
# Take func's parameter - the dataframe that will be passed to it.
# run func
# compare the initial dataframe with the one that func returned and log the rows that are missing.Any help on this would be appreciated. I am new to using decorators and not sure this is even possible but if there is another way, then let me know.
I'm not entirely clear what it is you want, but if you just want to use the decorated function's arguments, then that is exactly what a basic decorator does. So to access say, self.request from a decorator you could do:
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')
If you are trying to access the class the decorated function is attached to, then it's a bit tricker and you'll have to cheat a bit using the inspect module.
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
In the example above we fetch the name of the class from the currentframe (during the execution of the decorator) and then store that in the decorated function. Here we are just prepending the class-name to whatever the msg variable is before passing it on to the original say function, but you can use your imagination to do what ever you like once you have the class name.
>>> MyClass().say('hello')
MyClass says: hello
source
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>
The syntax for decorators with arguments is a bit different - the decorator with arguments should return a function that will take a function and return another function. So it should really return a normal decorator. A bit confusing, right? What I mean is:
def decorator_factory(argument):
def decorator(function):
def wrapper(*args, **kwargs):
funny_stuff()
something_with_argument(argument)
result = function(*args, **kwargs)
more_funny_stuff()
return result
return wrapper
return decorator
Here you can read more on the subject - it's also possible to implement this using callable objects and that is also explained there.
Usage:
@decorator_factory("Some argument")
def function_to_be_decorated(args):
print(f"Do something with '{args}'.")
decorator_factory("Some argument") uses the given argument to create a standard, argumentless decorator. So the following block is functionally identical to the one above:
created_decorator = decorator_factory("Some argument")
@created_decorator
def function_to_be_decorated(args):
print(f"Do something with '{args}'.")
Edit : for an in-depth understanding of the mental model of decorators, take a look at this awesome Pycon Talk. well worth the 30 minutes.
One way of thinking about decorators with arguments is
@decorator
def foo(*args, **kwargs):
pass
translates to
foo = decorator(foo)
So if the decorator had arguments,
@decorator_with_args(arg)
def foo(*args, **kwargs):
pass
translates to
foo = decorator_with_args(arg)(foo)
decorator_with_args is a function which accepts a custom argument and which returns the actual decorator (that will be applied to the decorated function).
I use a simple trick with partials to make my decorators easy
from functools import partial
def _pseudo_decor(fun, argument):
def ret_fun(*args, **kwargs):
#do stuff here, for eg.
print ("decorator arg is %s" % str(argument))
return fun(*args, **kwargs)
return ret_fun
real_decorator = partial(_pseudo_decor, argument=arg)
@real_decorator
def foo(*args, **kwargs):
pass
Update:
Above, foo becomes real_decorator(foo)
One effect of decorating a function is that the name foo is overridden upon decorator declaration. foo is "overridden" by whatever is returned by real_decorator. In this case, a new function object.
All of foo's metadata is overridden, notably docstring and function name.
>>> print(foo)
<function _pseudo_decor.<locals>.ret_fun at 0x10666a2f0>
functools.wraps gives us a convenient method to "lift" the docstring and name to the returned function.
from functools import partial, wraps
def _pseudo_decor(fun, argument):
# magic sauce to lift the name and doc of the function
@wraps(fun)
def ret_fun(*args, **kwargs):
# pre function execution stuff here, for eg.
print("decorator argument is %s" % str(argument))
returned_value = fun(*args, **kwargs)
# post execution stuff here, for eg.
print("returned value is %s" % returned_value)
return returned_value
return ret_fun
real_decorator1 = partial(_pseudo_decor, argument="some_arg")
real_decorator2 = partial(_pseudo_decor, argument="some_other_arg")
@real_decorator1
def bar(*args, **kwargs):
pass
>>> print(bar)
<function __main__.bar(*args, **kwargs)>
>>> bar(1,2,3, k="v", x="z")
decorator argument is some_arg
returned value is None
I'm not a fan of this design. @TheBlackCat is right. Don't do this.
If you are to do this, rethink your design. A more sensible one might look like
import functools
from contextlib import suppress
def try_except_response(func):
@functools.wraps(func)
def wrapper(*args, fail_silently, **kwargs):
if fail_silently:
with suppress(Exception):
return func(*args, **kwargs)
else:
return func(*args, **kwargs)
return wrapper
The key principle here is KISS.
Note that I'm suppressing Exception, not BaseException, since catching SystemExit and KeyboardInterrupt is almost always a bad idea.
If you want to make fail_silently a default argument, just use another wrapper:
def default_fail_silently(default):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, fail_silently=default, **kwargs):
return func(*args, fail_silently=fail_silently, **kwargs)
return wrapper
return decorator
Then you can do
@default_fail_silently(False)
@try_except_response
def test(a, b, c=1)
return int(a) + c
This does mean there's more boilerplate, since it exists for each piece of functionality you add, but the logic itself is an order of magnitude simpler.
Your code looks really nice, I saw a few parts that might be improved:
if kwargs.get(parameter)== True:: binary operators are suggested, by PEP8, to have a space pre&proceeding the operator=function_args, vargs, kewords,: is that last one a misspell?if keyword == True:: If you're testing whether the variable is empty, as PEP8 says, you can useif keyword
Other than that, your code looks really nice, good work!