2013-06-04 31 views
21

Tôi đang tìm để đóng gói logic cho giao dịch cơ sở dữ liệu thành một khối with; gói mã trong một giao dịch và xử lý các ngoại lệ khác nhau (các vấn đề về khóa). Điều này là đơn giản, đủ, tuy nhiên tôi muốn cũng có khối đóng gói việc thử lại của khối mã sau một số trường hợp ngoại lệ. Tôi không thể nhìn thấy một cách để gói này lên gọn gàng vào trình quản lý ngữ cảnh.Encapsulating lần thử lại vào 'khối with`

Có thể lặp lại mã trong tuyên bố with không?

Tôi muốn sử dụng nó một cách đơn giản như thế này, đó là thực sự gọn gàng.

def do_work(): 
    ... 
    # This is ideal! 
    with transaction(retries=3): 
     # Atomic DB statements 
     ... 
    ... 

tôi đang xử lý này với một trang trí, nhưng tôi muốn cung cấp cho người quản lý ngữ cảnh (hoặc trên thực tế cả hai), vì vậy tôi có thể chọn để bọc một vài dòng mã trong khối with thay của một hàm nội tuyến được bọc trong một trang trí, đó là những gì tôi làm ở thời điểm hiện tại:

def do_work(): 
    ... 
    # This is not ideal! 
    @transaction(retries=3) 
    def _perform_in_transaction(): 
     # Atomic DB statements 
     ... 
    _perform_in_transaction() 
    ... 
+0

http://docs.python.org/release/2.5/whatsnew/pep-343.html có vẻ như nó có ví dụ về cách triển khai trình quản lý ngữ cảnh. – Vlad

Trả lời

4

Như trang trí chỉ là chức năng bản thân, bạn có thể làm như sau:

with transaction(_perform_in_transaction, retries=3) as _perf: 
    _perf() 

Đối các chi tiết, bạn sẽ cần phải thực hiện transaction() như một phương pháp nhà máy mà trả về một đối tượng với __callable__() thiết lập để gọi phương thức ban đầu và lặp lại nó lên đến retries số lần về thất bại; __enter__()__exit__() sẽ được định nghĩa là bình thường đối với người quản lý ngữ cảnh giao dịch cơ sở dữ liệu.

Bạn cũng có thể thiết lập transaction() sao cho chính nó thực thi phương thức đã chuyển lên đến retries số lần, có thể yêu cầu cùng một lượng công việc như triển khai trình quản lý ngữ cảnh. transaction(_perform_in_transaction, retries=3) (trên thực tế, tương đương với ví dụ về trang trí được cung cấp).

12

Có thể lặp lại mã trong tuyên bố with không?

No.

Như đã chỉ ra trước đó ở chỗ mailing list chủ đề, bạn có thể giảm một chút trùng lặp bằng cách làm cho trang trí gọi hàm truyền:

def do_work(): 
    ... 
    # This is not ideal! 
    @transaction(retries=3) 
    def _perform_in_transaction(): 
     # Atomic DB statements 
     ... 
    # called implicitly 
    ... 
+0

Ah, đáng tiếc là nó không được hỗ trợ. Cảm ơn bạn đã liên kết đến chuỗi. Tôi thích ý tưởng có cuộc gọi tiềm ẩn để làm cho nó sạch hơn. Nếu tôi muốn thiết lập/sửa đổi các vars trong '_perform_in_transaction', tôi đoán tôi sẽ phải gọi nó bằng tay và trả về những gì tôi cần để tiếp tục phần còn lại của hàm' do_work'. –

4

Cách mà xảy ra với tôi để làm điều này chỉ để thực hiện một giao dịch cơ sở dữ liệu tiêu chuẩn context manager, nhưng cho phép nó lấy một đối số retries trong hàm tạo. Sau đó, tôi chỉ quấn nó lên trong các phương pháp triển khai phương thức của bạn. Một cái gì đó như thế này:

class transaction(object): 
    def __init__(self, retries=0): 
     self.retries = retries 
    def __enter__(self): 
     return self 
    def __exit__(self, exc_type, exc_val, traceback): 
     pass 

    # Implementation... 
    def execute(self, query): 
     err = None 
     for _ in range(self.retries): 
      try: 
       return self._cursor.execute(query) 
      except Exception as e: 
       err = e # probably ought to save all errors, but hey 
     raise err 

with transaction(retries=3) as cursor: 
    cursor.execute('BLAH') 
+1

Bạn có thể xây dựng nơi '_cursor' trong' self._cursor' đến từ đâu không? –

+0

@ MikeMüller Tôi đang cố gắng vẽ một số cơ sở dữ liệu API thông thường mà không bị lún sâu vào chi tiết triển khai.'_cursor' có nghĩa là một đối tượng [' Con trỏ'] (http://www.python.org/dev/peps/pep-0249/#cursor-objects), khi thích hợp cho kết nối cơ sở dữ liệu cụ thể có liên quan. Việc triển khai đầy đủ sẽ cần tạo và chứa một đối tượng 'Connection' của một loại nào đó, để thực sự thực hiện các giao dịch cơ sở dữ liệu. –

+0

@HenryKeller Tôi đã làm một cái gì đó như thế này 'def __init __ (tự, con trỏ, retries = 0):' và bên trong '__init__' này' self._cursor = cursor '. Cách sử dụng: 'với giao dịch (con trỏ, retries = 3) là con trỏ:'. Điều này có nghĩa không? –