2009-01-13 40 views
17

Có thể sử dụng câu lệnh with trực tiếp với tệp CSV không? Có vẻ như tự nhiên để có thể làm điều gì đó như thế này:Sử dụng câu lệnh "có" cho tệp CSV bằng Python

import csv 
with csv.reader(open("myfile.csv")) as reader: 
    # do things with reader 

Nhưng csv.reader không cung cấp các phương pháp __enter____exit__, vì vậy đây không hoạt động. Tuy nhiên, tôi có thể thực hiện theo hai bước:

import csv 
with open("myfile.csv") as f: 
    reader = csv.reader(f) 
    # do things with reader 

Đây có phải là cách lý tưởng để làm điều đó không? Tại sao họ không làm cho csv.reader tương thích trực tiếp với tuyên bố với?

+0

Như đã đề cập bên dưới, điều đó thực sự không có ý nghĩa đối với người đọc csv. Nhưng nó chắc chắn cho một nhà văn! – b0fh

Trả lời

18

Việc sử dụng chính câu lệnh with là việc dọn dẹp ngoại lệ an toàn đối tượng được sử dụng trong câu lệnh. with đảm bảo rằng các tệp đã được đóng, khóa được giải phóng, các ngữ cảnh được khôi phục, v.v.

Có cần dọn dẹp các thứ gì trong trường hợp ngoại lệ không?

Tôi muốn đi với:

with open("myfile.csv") as f: 
    for row in csv.reader(f): 
     # process row 

Bạn không cần phải nộp các bản vá để sử dụng csv.readerwith tuyên bố với nhau.

import contextlib 

Trợ giúp về chức năng contextmanager trong mô-đun contextlib:

contextmanager(func) 
    @contextmanager decorator. 

sử dụng tiêu biểu:

@contextmanager 
    def some_generator(<arguments>): 
     <setup> 
     try: 
      yield <value> 
     finally: 
      <cleanup> 

này làm cho điều này:

with some_generator(<arguments>) as <variable>: 
     <body> 

tương đương như sau:

<setup> 
    try: 
     <variable> = <value> 
     <body> 
    finally: 
     <cleanup> 

Đây là ví dụ cụ thể cách tôi đã sử dụng: curses_screen.

+2

@ J.F.Sebastion: Tôi nghĩ rằng tất cả các mô-đun thư viện "Nén dữ liệu" và "Định dạng tệp" phải hỗ trợ trực tiếp. –

+0

@ S.Lott: Tôi đồng ý rằng thư viện chuẩn nên tạo chính người quản lý ngữ cảnh, nơi nó được áp dụng. Trong trường hợp của module 'csv', nó có thể là' reader = csv.open (path) 'nhưng * not *' reader = csv.reader (iterable) '. – jfs

+0

@ J.F. Sebastian +1 để giải thích chi tiết về cách người ta có thể sử dụng contextlib để thực hiện việc này, nhưng kiểm tra phản hồi từ @bluce để triển khai thực tế để sử dụng với csv. – technomalogical

3

Có. Cách thứ hai là chính xác.

Vì sao? Ai đã từng biết. Bạn nói đúng, đó có thể là một sự thay đổi dễ dàng. Nó không phải là ưu tiên cao như những thứ khác.

Bạn có thể dễ dàng tạo bộ vá lỗi của riêng mình và gửi nó.

+0

Được rồi, có lẽ tôi sẽ làm điều đó. Cảm ơn. – Kiv

+1

Tôi không chắc đây là "hành vi phạm tội có thể vá".Trình đọc CSV có nghĩa là hành động trên một đối tượng tệp mở và cung cấp một hàng có thể lặp lại - không có việc mua lại và phát hành tài nguyên thực sự đang diễn ra. Nếu bạn muốn thoát ra khỏi khối với một cách nhanh chóng, hãy làm hàng = list (csv.reader (file_)) và sử dụng các hàng bên ngoài nó. – cdleary

+0

@cdleary: Tôi nghĩ rằng phản hồi với không nhất thiết phải phản ánh việc sử dụng tài nguyên ACTUAL, mà chỉ là "tài nguyên". Tất cả các mô-đun thư viện "Nén dữ liệu" và "Định dạng tệp" phải làm điều này cho sự nhất quán đơn giản. –

0

Thật dễ dàng để tạo ra những gì bạn muốn sử dụng một chức năng máy phát điện:


import csv 
from contextlib import contextmanager 

@contextmanager 
def opencsv(path): 
    yield csv.reader(open(path)) 

with opencsv("myfile.csv") as reader: 
    # do stuff with your csvreader 
+2

Điều đó không thực sự đóng tệp trong trường hợp ngoại lệ. Nó làm cho câu lệnh 'with' hợp lệ ... nhưng đó là tất cả. – kindall

2

Vấn đề là csv.reader không thực sự quản lý một ngữ cảnh. Nó có thể chấp nhận bất kỳ iterable, không chỉ là một tập tin. Vì vậy nó không gọi gần trên đầu vào của nó (ngẫu nhiên nếu nó đã làm bạn có thể sử dụng contextlib.closing). Vì vậy, nó không rõ ràng những gì hỗ trợ ngữ cảnh cho csv.reader thực sự sẽ làm.

1
import csv 

class CSV(object): 
    def __init__(self,path,mode): 
     self.path = path 
     self.mode = mode 
     self.file = None 

    def __enter__(self): 
     self.file = open(self.path,self.mode) 
     if self.mode == 'r': 
      return csv.reader(self.file) 
     elif self.mode == 'w': 
      return csv.writer(self.file) 

    def __exit__(self, exc_type, exc_val, exc_tb): 
     self.file.close() 

with CSV('data.csv','r') as reader: 
    for row in reader: 
     print row 
Các vấn đề liên quan