gpt4 book ai didi

Python使用装饰器实现上下文管理器

转载 作者:太空宇宙 更新时间:2023-11-03 23:56:05 29 4
gpt4 key购买 nike

我正在尝试制作两个带参数的装饰器。 首先 创建一个包含元素xlist 并调用funcsecond 只是通过从字典传递参数来调用 first

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 函数只是修改传入的列表。我想通过简单地调用 third() 使下面四个装饰器中的任何一个成为可能。我应该如何修改我的代码?

##@second
##@second({'x':100})
##@first
##@first(x=10)
def third(l):
l.append(-1)

third()

例如:

## 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].

上面的代码是我的问题的抽象。我真正的问题是我想要一个装饰器来为我处理打开和关闭连接,这样我只需要编写处理连接的代码。

并且连接需要参数,这是first。我希望以不同的方式传递参数,这是第二种third 是我要对连接执行的操作。我希望 third 像普通函数一样被调用,它还使用装饰器处理打开和关闭连接。对不起,如果装饰器不应该这样使用,但我真的很想练习使用它。

---更新---

我想实现的基本上是这样的:

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

我想让这四个装饰器中的任何一个成为可能,并且仍然能够以类似于 execute() 的方式调用 execute

最佳答案

看来您可能只需要了解一下什么是装饰器。装饰器是一个函数,它接受一个函数作为它唯一的参数,并在它的位置返回一个函数。它们通常采用以下形式:

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

这让你可以做类似的事情:

@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)

并期待这样的结果:

>>> print(my_increment(3))
Inside the wrapped function
Calculating...
Exiting the wrapped function
4

值得注意的是:my_increment 成为运行时的装饰函数,不是在调用时。如果没有装饰器功能,您将无法调用 my_increment


您尝试做的事情看起来与您使用装饰器的目的完全不同。这对我来说像是函数链接。

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]

并这样调用它:

# 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]

还要注意,装饰器可以接受参数,但是你正在谈论(请耐心等待...)一个接受参数的函数,该函数返回一个函数,该函数接受一个函数并返回一个函数.你只是再抽象一层。想象一下:

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

现在你的代码可以是

@decorator_abstracted("a decorator around my_increment")
def my_increment(x):
print('Calculating...')
return x + 1

关于Python使用装饰器实现上下文管理器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57668758/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com