2012-07-11 37 views
11

Tôi đang cố gắng viết trình quản lý ngữ cảnh sử dụng các trình quản lý ngữ cảnh khác, vì vậy khách hàng không cần biết toàn bộ công thức, chỉ giao diện tôi đang trình bày. Tôi không thể thực hiện việc này bằng cách sử dụng @contextmanager - mã sau khi cuộc gọi yield không được thực thi nếu bạn bị gián đoạn bởi một ngoại lệ, vì vậy tôi cần sử dụng trình quản lý dựa trên lớp học.Viết trình quản lý ngữ cảnh bằng Python tự sử dụng câu lệnh

Dưới đây là một ví dụ nhỏ kịch bản:

from contextlib import contextmanager 
import pprint 

d = {} 

@contextmanager 
def simple(arg, val): 
    print "enter", arg 
    d[arg] = val 
    yield 
    print "exit", arg 
    del d[arg] 

class compl(object): 
    def __init__(self, arg, val): 
     self.arg=arg 
     self.val=val 

    def __enter__(self): 
     with simple("one",1): 
      with simple("two",2): 
       print "enter complex", self.arg 
       d[self.arg] = self.val 

    def __exit__(self,*args): 
     print "exit complex", self.arg 
     del d[self.arg] 

print "before" 
print d 
print "" 

with compl("three",3): 
    print d 
    print "" 

print "after" 
print d 
print "" 

Đó kết quả đầu ra này:

before 
{} 

enter one 
enter two 
enter complex three 
exit two 
exit one 
{'three': 3} 

exit complex three 
after 
{} 

Tôi muốn nó kết quả này:

before 
{} 

enter one 
enter two 
enter complex three 
{'one': 1, 'three': 3, 'two': 2} 

exit complex three 
exit two 
exit one 
after 
{} 

Có cách nào để kể một lớp quản lý ngữ cảnh dựa trên để tự bọc chính nó với các trình quản lý ngữ cảnh khác?

+2

Nó muốn được hữu ích để xác định phiên bản Python. –

+0

Xin lỗi câu hỏi, nhưng tại sao bạn muốn làm điều này? Có vẻ như chỉ tự nhiên với tôi rằng trình quản lý ngữ cảnh dựa trên lớp nên thoát cuối cùng, sau khi nó dọn dẹp các phụ thuộc của nó. –

+0

Nhắm mục tiêu python 2.7, xin lỗi –

Trả lời

12
@contextmanager 
def compl(arg, val): 
   with simple("one",1): 
        with simple("two",2): 
      print "enter complex", arg 
      try: 
                d[arg] = val 
       yield 
      finally: 
          del d[arg] 
          print "exit complex", arg 
+3

Bạn có thể xác định/giải thích vấn đề trong mã của người hỏi để hiểu nhanh hơn những gì đang xảy ra? :) – n611x007

+1

@naxa: xem xét hai ví dụ đầu ra cuối cùng trong câu hỏi. Mã trong câu hỏi tạo ra đầu ra đầu tiên, mã của tôi trong câu trả lời tạo ra câu lệnh thứ hai (câu lệnh mong muốn). Tóm lại: người quản lý ngữ cảnh lồng nhau nhất nên thoát sớm nhất. – jfs

1

Vấn đề với những gì bạn đang làm, đó là trong việc sử dụng with trong __enter__ cuộc gọi của bạn, khi bạn nhập quản lý gói hoàn cảnh của bạn, bạn có cả nhập và sau đó rời khỏi nhà quản lý bối cảnh quấn. Nếu bạn muốn viết trình quản lý ngữ cảnh của riêng bạn đi vào trình quản lý ngữ cảnh được bao bọc khi bạn nhập trình bao bọc, sau đó thoát chúng khi bạn rời khỏi, bạn sẽ phải tự gọi các hàm quản lý ngữ cảnh được bao bọc. Có thể bạn cũng sẽ phải lo lắng về sự an toàn ngoại lệ.

2

Bạn viết, "Tôi không thể làm điều đó bằng cách sử dụng @contextmanager - mã sau khi gọi năng suất không được thực thi nếu bạn bị gián đoạn bởi một ngoại lệ." Nếu bạn có mã phải chạy, bạn có thể đặt mã trong khối try/finally.

import contextlib 

@contextlib.contextmanager 
def internal_cm(): 
    try: 
     print "Entering internal_cm" 
     yield None 
     print "Exiting cleanly from internal_cm" 
    finally: 
     print "Finally internal_cm" 

@contextlib.contextmanager 
def external_cm(): 
    with internal_cm() as c: 
     try: 
      print "In external_cm_f" 
      yield [c] 
      print "Exiting cleanly from external_cm_f" 
     finally: 
      print "Finally external_cm_f" 

if "__main__" == __name__: 
    with external_cm() as foo1: 
     print "Location A" 
    print 
    with external_cm() as foo2: 
     print "Location B" 
     raise Exception("Some exception occurs!!") 

Output:

Entering internal_cm 
In external_cm_f 
Location A 
Exiting cleanly from external_cm_f 
Finally external_cm_f 
Exiting cleanly from internal_cm 
Finally internal_cm 

Entering internal_cm 
In external_cm_f 
Location B 
Finally external_cm_f 
Finally internal_cm 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "C:\Anaconda\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 540, in runfile 
    execfile(filename, namespace) 
    File "C:\untitled0.py", line 35, in <module> 
    raise Exception("Some exception occurs!!") 
Exception: Some exception occurs!! 
Các vấn đề liên quan