2013-04-17 18 views
6

Cho một urllib.request đối tượng tiêu chuẩn, lấy ra như vậy:urllib.request: bất kỳ cách nào để đọc từ nó mà không sửa đổi đối tượng yêu cầu?

req = urllib.urlopen('http://example.com') 

Nếu tôi đọc nội dung của nó qua req.read(), sau đó các đối tượng yêu cầu sẽ được bỏ trống.

Không giống như các đối tượng giống như tệp thông thường, tuy nhiên, đối tượng yêu cầu không có phương thức seek, vì tôi chắc chắn là những lý do tuyệt vời.

Tuy nhiên, trong trường hợp của tôi, tôi có chức năng và tôi muốn xác định một yêu cầu nhất định và sau đó trả lại yêu cầu đó "không bị hấn" để có thể đọc lại.

Tôi hiểu rằng một tùy chọn là yêu cầu lại. Nhưng tôi muốn có thể tránh thực hiện nhiều yêu cầu HTTP cho cùng một url & nội dung.

Cách duy nhất khác mà tôi có thể nghĩ là có hàm trả về một bộ nội dung được trích xuất và đối tượng yêu cầu, với sự hiểu biết rằng bất cứ thứ gì gọi hàm này sẽ phải lấy nội dung theo cách này.

Đó có phải là lựa chọn duy nhất của tôi không?

+1

Không sử dụng 'urllib.urlopen' - [* Cũng lưu ý rằng hàm urllib.urlopen() đã bị loại bỏ trong Python 3 có lợi cho urllib2.urlopen() *] (http: //docs.python. org/2/library/urllib.html) –

+0

Cảm ơn bạn đã cho tôi biết, mặc dù trong trường hợp này, hành vi từ 'urllib2.urlopen' là như nhau. –

Trả lời

3

khâm bộ nhớ đệm cho một đối tượng StringIO (mã không dự thi, chỉ để cung cấp cho các ý tưởng):

import urllib 
from io import StringIO 


class CachedRequest(object): 
    def __init__(self, url): 
     self._request = urllib.urlopen(url) 
     self._content = None 

    def __getattr__(self, attr): 
     # if attr is not defined in CachedRequest, then get it from 
     # the request object. 
     return getattr(self._request, attr) 

    def read(self): 
     if self._content is None: 
      content = self._request.read() 
      self._content = StringIO() 
      self._content.write(content) 
      self._content.seek(0) 
      return content 
     else: 
      return self._content.read() 

    def seek(self, i): 
     self._content.seek(i) 

Nếu mã thực sự hy vọng một đối tượng thực Request (tức là gọi isinstance để kiểm tra các loại) sau đó lớp con Request và bạn thậm chí không phải triển khai __getattr__. Lưu ý rằng có thể chức năng sẽ kiểm tra chính xác lớp (và trong trường hợp này bạn không thể làm gì) hoặc, nếu nó được viết bằng C, hãy gọi phương thức bằng cách sử dụng các cuộc gọi C/API (trong trường hợp này, hãy gọi hàm này bằng cách sử dụng C/API). phương thức ghi đè sẽ không được gọi).

+0

Bạn không cần phải thiết lập 'self._content' thành một cái gì đó như' StringIO' thay vì 'None'? Khá chắc chắn bạn sẽ chạy vào một 'AttributeError' khi gọi' write'. –

+1

@JordanReiter Xin lỗi. Lúc đầu, tôi đã viết 'self._content = StringIO()', sau đó tôi đã thay đổi ý định của mình và quên sửa mã bit giả định 'self._content' đã được khởi tạo. – Bakuriu

2

Tạo một lớp con của urllib2.Request sử dụng số cStringIO.StringIO để giữ bất kỳ thứ gì được đọc. Sau đó, bạn có thể triển khai seek và v.v. Trên thực tế bạn chỉ có thể sử dụng một chuỗi, nhưng đó sẽ là công việc nhiều hơn nữa.

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