簡體   English   中英

Python使用裝飾器實現上下文管理器

[英]Python use decorator to implement context manager

我試圖用參數制作兩個裝飾器。 First使用元素x創建一個list ,然后調用func second是簡單地通過傳遞dict中的參數來調用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 我希望以另一種方式傳遞參數,這是second 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM