Trong python, có nhiều chức năng hoạt động như cả chức năng chuẩn và trình quản lý ngữ cảnh. Ví dụ open()
có thể được gọi là một trong hai như:Python: chức năng chuẩn và trình quản lý ngữ cảnh?
my_file=open(filename,'w')
hoặc
with open(filename,'w') as my_file:
Cả hai đem lại cho bạn một đối tượng my_file
có thể được sử dụng để làm bất cứ điều gì bạn cần. Nói chung sau này là thích hợp hơn, nhưng có những lúc người ta có thể muốn làm như cũ là tốt.
tôi đã có thể tìm ra cách để viết một trình quản lý nội dung, hoặc bằng cách tạo ra một lớp học với __enter__
và __exit__
chức năng hoặc bằng @contextlib.contextmanager
trang trí trên một hàm và yield
hơn return
. Tuy nhiên, khi tôi làm điều này tôi không còn có thể sử dụng chức năng thẳng - bằng cách sử dụng trang trí, ví dụ, tôi nhận được một đối tượng _GeneratorContextManager
trở lại chứ không phải là kết quả mong muốn. Tất nhiên, nếu tôi làm nó như một lớp, tôi sẽ chỉ nhận được một thể hiện của lớp máy phát điện, mà tôi cho rằng cơ bản là giống nhau.
Vậy làm cách nào tôi có thể thiết kế một hàm (hoặc lớp) hoạt động như một hàm, trả về một đối tượng hoặc trình quản lý ngữ cảnh, trả lại _GeneratorContextManager
hoặc tương tự?
chỉnh sửa:
Ví dụ, nói rằng tôi có một chức năng như sau (đây là RẤT đơn giản):
def my_func(arg_1,arg_2):
result=arg_1+arg_2
return my_class(result)
Vì vậy, các chức năng có một số tranh cãi, không thứ với họ, và sử dụng kết quả của công cụ đó để khởi tạo một lớp, sau đó nó sẽ trả về. Kết quả cuối cùng là tôi có một thể hiện của my_class
, giống như tôi sẽ có một đối tượng file
nếu tôi đã gọi là open
. Nếu tôi muốn để có thể sử dụng chức năng này như một người quản lý bối cảnh, tôi có thể sửa đổi nó như vậy:
@contextlib.contextmanager
def my_func(arg_1,arg_2):
result=arg_1+arg_2 # This is roughly equivalent to the __enter__ function
yield my_class(result)
<do some other stuff here> # This is roughly equivalent to the __exit__function
nào chỉ hoạt động tốt khi gọi như một người quản lý bối cảnh, nhưng tôi không còn nhận được một thể hiện của my_class
khi gọi là hàm thẳng. Có lẽ tôi chỉ đang làm điều gì đó sai?
Chỉnh sửa 2:
Lưu ý rằng tôi có toàn quyền kiểm soát my_class
, bao gồm cả khả năng thêm chức năng với nó. Từ câu trả lời được chấp nhận dưới đây, tôi có thể suy ra rằng khó khăn của tôi bắt nguồn từ một sự hiểu lầm cơ bản: Tôi đã nghĩ rằng bất cứ điều gì tôi gọi (my_func
trong ví dụ trên) cần có các chức năng __exit__
và __enter__
. Điều này LAF không đúng. Trên thực tế, chỉ có chức năng trả về (my_class
trong ví dụ trên) cần có các chức năng để hoạt động như một trình quản lý ngữ cảnh.
'open' là một hàm trả về một cá thể của một lớp. Cho dù bạn sử dụng 'myfile = open (tên tệp)' hay 'với tên tệp mở (open) như myfile', nó vẫn sẽ là một cá thể của cùng một lớp. Không có gì thay đổi. – zondo
@zondo Đúng, như hàm tôi đang cố viết. Tuy nhiên, khi tôi bọc hàm trong trình trang trí '@ contextlib.contextmanager', và gọi nó là hàm chuẩn, lớp tôi lấy lại không phải là lớp tôi" sinh ra "từ hàm. Chỉ khi tôi gọi nó là người quản lý ngữ cảnh thì tôi mới có được lớp đó. Tôi sẽ thêm một ví dụ đơn giản. – ibrewster
Xác định phương thức '__call__' trong lớp học của bạn. –