2012-05-24 28 views
5

Một số nền: Tôi làm việc trong ngân hàng lớn và tôi đang cố gắng sử dụng lại một số mô-đun Python mà tôi không thể thay đổi, chỉ nhập. Tôi cũng không có tùy chọn cài đặt bất kỳ tiện ích/chức năng mới nào vv (chạy Python 2.6 trên Linux).Python thiếu phương thức __exit__

Tôi đã có này có mặt tại địa chỉ:

Trong mô-đun của tôi:

from common.databaseHelper import BacktestingDatabaseHelper 

class mfReportProcess(testingResource): 
    def __init__(self): 
     self.db = BacktestingDatabaseHelper.fromConfig('db_name') 

Một trong những phương pháp được gọi là trong lớp 'testingResource' có này:

with self.db as handler: 

rơi với điều này:

with self.db as handler: 
AttributeError: 'BacktestingDatabaseHelper' object has no attribute '__exit__' 

và, thực sự, không có phương pháp __exit__ trong lớp 'BacktestingDatabaseHelper', một lớp mà tôi không thể thay đổi.

Tuy nhiên, mã này tôi đang cố gắng sử dụng lại hoạt động hoàn hảo cho các ứng dụng khác - có ai biết tại sao tôi gặp lỗi này và không ai khác không? Có cách nào để xác định __exit__ tại địa phương không?

Rất cám ơn trước.

Edited thêm:

Tôi đã cố gắng để thêm class của riêng tôi thiết lập truy cập DB nhưng không thể lấy nó để làm việc - thêm này để mô-đun của tôi:

class myDB(BacktestingDatabaseHelper): 
    def __enter__(self): 
     self.db = fromConfig('db_name') 
    def __exit__(self): 
     self.db.close() 

và nói thêm:

self.db = myDB 

vào tôi init thuộc tính cho lớp học chính của tôi, nhưng tôi nhận được lỗi này:

with self.db as handler: 
TypeError: unbound method __enter__() must be called with myDB instance as first argument (got nothing instead) 

Bất kỳ đề xuất nào về cách thực hiện điều này đúng cách?

+3

Họ đang sử dụng phiên bản khác của mô-đun hoặc họ không sử dụng 'BacktestingDatabaseHelper' làm người quản lý ngữ cảnh –

+2

Bạn sẽ phải biết thực '__enter__' và' __exit__' làm, và làm tương tự. Nếu cùng một mã hoạt động cho những người khác trong công ty của bạn, tôi thực sự khuyên bạn nên kiểm tra phiên bản và nội dung của từng mô-đun chung. –

Trả lời

4

Lỗi có nghĩa là BacktestingDatabaseHelper không được thiết kế để sử dụng trong tuyên bố with. Âm thanh như các lớp học testingResourceBacktestingDatabaseHelper không tương thích với nhau (có thể phiên bản common.databaseHelper của bạn đã lỗi thời).

+0

Tôi đến với ý tưởng rằng phiên bản của tôi là sai/cũ nhưng chờ đợi một thành viên của nhóm dev để tư vấn. – Nelmo

+2

Aaggh - anh chàng nhà phát triển nói với tôi rằng anh ta đã cài đặt gói sai cho tôi !! Rất tiếc cho tất cả và cảm ơn rất nhiều cho tất cả các câu trả lời của bạn. – Nelmo

+1

@ user996166; vì vậy hãy đặt như ** EDIT: '** trong dòng đầu tiên của câu hỏi của bạn !! – smci

11

Sử dụng giao thức with giả định rằng đối tượng được sử dụng trong with triển khai context manager protocol.

Về cơ bản, điều này có nghĩa là định nghĩa lớp phải có các phương thức __enter__()__exit__() được xác định. Nếu bạn sử dụng một đối tượng không có, python sẽ ném một số AttributeError phàn nàn về thuộc tính thiếu __exit__.

2

Các 'với' từ khóa cơ bản là một shortcut để viết ra:

try: 
    // Do something 
finally: 
    hander.__exit__() 

đó là hữu ích nếu đối tượng handler bạn đang sử dụng tài nguyên (như, ví dụ, một dòng tập tin mở). Nó đảm bảo rằng không có vấn đề gì xảy ra trong phần 'làm điều gì đó', tài nguyên được giải phóng một cách rõ ràng.

Trong trường hợp của bạn, đối tượng xử lý của bạn không có phương thức __exit__ và do đó with không thành công. Tôi cho rằng những người khác có thể sử dụng BacktestingDatabaseHelper vì họ không sử dụng with.

Đối với những gì bạn có thể làm bây giờ, tôi khuyên bạn nên quên with và sử dụng try ... finally thay vì thay vì cố thêm phiên bản __exit__ của riêng bạn vào đối tượng. Bạn sẽ phải đảm bảo rằng bạn giải phóng trình xử lý đúng cách (cách bạn thực hiện điều này sẽ phụ thuộc vào cách BacktestingDatabaseHelper được cho là được sử dụng), ví dụ:

try: 
    handler = self.db 
    // do stuff 
finally: 
    handler.close() 

Sửa: Vì bạn không thể thay đổi nó, bạn nên làm một cái gì đó giống như @Daniel Roseman suggests quấn BacktestingDatabaseHelper. Tùy thuộc vào cách tốt nhất để làm sạch BacktestingDatabaseHelper (như trên), bạn có thể viết một cái gì đó như:

from contextlib import contextmanager 

@contextmanager 
def closing(thing): 
    try: 
     yield thing 
    finally: 
     thing.close() 

và sử dụng như:

class mfReportProcess(testingResource): 
    def __init__(self): 
     self.db = closing(BacktestingDatabaseHelper.fromConfig('db_name')) 

(đây là trực tiếp từ documentation).

+0

Thật không may, rằng 'với' dòng là một phần của mã phổ biến mà tôi không thể thay đổi, vì vậy tôi phải sử dụng nó. – Nelmo

+0

(Câu trả lời của tôi quá dài để nhận xét, vì vậy tôi đã chỉnh sửa câu trả lời của mình.) – karaken12

+0

Bên cạnh đó, tôi không chắc liệu nó có đóng được trình quản lý ngữ cảnh hay không. quản lý, vv) – glglgl

2

Bạn có thể muốn thử trình trang trí contextlib.contextmanager để bọc đối tượng của mình để nó hỗ trợ giao thức quản lý ngữ cảnh.

3

Vì bạn không thể thay đổi câu lệnh with, bạn phải thêm lớp bắt nguồn từ BacktestingDatabaseHelper, thêm các hàm __enter__()__exit__() phù hợp và sử dụng hàm này thay thế.

Dưới đây là một ví dụ mà cố gắng để được càng gần với bản gốc càng tốt:

class myDB(BacktestingDatabaseHelper): 
    def __enter__(self): 
     return self 
    def __exit__(self): 
     self.db.close() 
    def fromConfig(self, name): 
     x = super(myDB, self).fromConfig(name) 
     assert isinstance(x, BacktestingDatabaseHelper) 
     x.__class__ = myDB # not sure if that really works 
[...] 
self.db=myDB.fromConfig('tpbp') 

Vấn đề là, tuy nhiên, tôi không chắc chắn những gì __enter__ có nghĩa vụ phải trả. Ví dụ: nếu bạn lấy MySQLdb, trình quản lý ngữ cảnh của kết nối sẽ tạo con trỏ biểu thị một giao dịch. Nếu đó là trường hợp ở đây là tốt, bạn phải làm việc khác ...

+0

** Xem bit đã chỉnh sửa trong OP *** – Nelmo

+0

@ user996166 Tôi đã thêm một ví dụ về cách hoạt động của nó - có thể. 'self.db = myDB' chỉ gán lớp. Có lẽ bạn cũng có thể thử với 'self.db = myDB()', mặc dù tôi nghi ngờ nếu nó hoạt động. – glglgl

+0

Thật không may, tôi phải sử dụng phiên bản phổ biến của 'fromConfig' (mà tôi không thể thay đổi) vì nó có các tham số/biến quan trọng để thiết lập. – Nelmo

Các vấn đề liên quan