I am trying to make two decorators with parameters. First
creates a list
with element x
and calls func
. second
is simply calling the first
by passing a parameter from a dict.
def first(x=1):
def wrapped(func):
l = [x]
func(l)
print(l)
return wrapped
def second(d={'x':10}):
return first(x=d['x'])
third
function simply modifies the list passed in.
I want to make any of the four decorators below possible by simply calling third()
. How should I modify my code?
##@second
##@second({'x':100})
##@first
##@first(x=10)
def third(l):
l.append(-1)
third()
For example:
## With @first,
## I am expecting to get [1, -1].
## With @first(x=10),
## I am expecting to get [10, -1].
## With @second,
## I am expecting to get [10, -1].
## With @second({x:100}),
## I am expecting to get [100, -1].
The upper code is an abstraction of my problem. My real problem is that I want a decorator that handles opening and closing connection for me, so that I only need to write code for handling the connection.
And the connection needs parameters, which is first
. I want the parameters to be passed in a different way, which is the second
. third
is what I am gonna do with the connection. I want third
to be called like a normal function, and it also handles the opening and closing connection using a decorator. Sorry if decorator should not be used this way, but I really want to practice using it.
---Update---
What I want to achieve is basically the following:
def context_manager(username='user', password='password'):
conn = OpenConnection()
func(conn)
CloseConnection()
def context_manager2(d={'username': 'user', 'password': 'password'}):
content_manager(username=d['username'], password=d['password'])
# @context_manager
# @context_manager('username', '123456')
# @context_manager2
# @context_manager2(d={'username': 'username', 'password': '123456'})
def execute(conn):
pass
I want to make any of the four decorators possible and still be able to call execute
in a way like execute()
Looks like you maybe just need a primer on what a decorator is. A decorator is a function that accepts a function as its only argument, and returns a function in its place. They often take the form of:
def decorator(f):
def wrapped(*args, **kwargs):
# it's important to accept any arguments to wrapped, thus *args and **kwargs
# because then you can wrap _any_ function and simply pass its arguments on.
print("Inside the wrapped function")
retval = f(*args, **kwargs) # pass the arguments through to the decorated function
print("Exiting the wrapped function")
return retval
return wrapped
This lets you do something like:
@decorator
def my_increment(x):
print("Calculating...")
return x + 1
# actually equivalent to
def my_increment(x):
print("Calculating...")
return x + 1
my_increment = decorator(my_increment)
and expect results like:
>>> print(my_increment(3))
Inside the wrapped function
Calculating...
Exiting the wrapped function
4
Notably: my_increment
becomes the decorated function at runtime, not at call time. You can't call my_increment
without the decorator functionality.
What you're attempting to do doesn't look anything like what you'd use a decorator for. This looks like function chaining to me.
def first(x=1):
return [x]
def second(d=None):
if d is None:
d = {'x':10} # why do this? https://stackoverflow.com/q/1132941/3058609
return first(d['x'])
def third(lst):
return lst + [-1]
and call it like:
# With @first,
# I am expecting to get [1, -1].
third(first()) # [1, -1]
# With @first(x=10),
# I am expecting to get [10, -1].
third(first(10)) # [10, -1]
# With @second,
# I am expecting to get [10, -1].
third(second()) # [10, -1]
# With @second({x:100}),
# I am expecting to get [100, -1].
third(second({'x':100})) # [100, -1]
Note also that decorators can take parameters, but then you're talking about (bear with me...) a function that takes parameters that returns a function which takes a function and returns a function. You're just abstracting one more layer. Imagine:
def decorator_abstracted(msg):
"""Takes a message and returns a decorator"""
# the below is almost the exact same code as my first example
def decorator(f):
def wrapped(*args, **kwargs):
print(msg)
retval = f(*args, **kwargs)
print("exiting " + msg)
return retval
return wrapped
return decorator
Now your code could be
@decorator_abstracted("a decorator around my_increment")
def my_increment(x):
print('Calculating...')
return x + 1