阅读SSeclient 源码发现
from __future__ import unicode_literals
import codecs
import re
import time
import warnings
import six
import requests
__version__ = '0.0.27'
# Technically, we should support streams that mix line endings. This regex,
# however, assumes that a system will provide consistent line endings.
end_of_field = re.compile(r'\r\n\r\n|\r\r|\n\n')
class SSEClient(object):
def __init__(self, url, last_id=None, retry=3000, session=None, chunk_size=1024, **kwargs):
self.url = url
self.last_id = last_id
self.retry = retry
self.chunk_size = chunk_size
# Optional support for passing in a requests.Session()
self.session = session
# Any extra kwargs will be fed into the requests.get call later.
self.requests_kwargs = kwargs
# The SSE spec requires making requests with Cache-Control: nocache
if 'headers' not in self.requests_kwargs:
self.requests_kwargs['headers'] = {}
self.requests_kwargs['headers']['Cache-Control'] = 'no-cache'
# The 'Accept' header is not required, but explicit > implicit
self.requests_kwargs['headers']['Accept'] = 'text/event-stream'
# Keep data here as it streams in
self.buf = ''
self._connect()
def _connect(self):
if self.last_id:
self.requests_kwargs['headers']['Last-Event-ID'] = self.last_id
# Use session if set. Otherwise fall back to requests module.
requester = self.session or requests
self.resp = requester.get(self.url, stream=True, **self.requests_kwargs)
self.resp_iterator = self.iter_content()
encoding = self.resp.encoding or self.resp.apparent_encoding
# print(encoding)
#查找encoding对应解码,encoding=utf8
self.decoder = codecs.getincrementaldecoder(encoding)(errors='replace')
# TODO: Ensure we're handling redirects. Might also stick the 'origin'
# attribute on Events like the Javascript spec requires.
self.resp.raise_for_status()
def iter_content(self):
def generate():
while True:
if hasattr(self.resp.raw, '_fp') and \
hasattr(self.resp.raw._fp, 'fp') and \
hasattr(self.resp.raw._fp.fp, 'read1'):
chunk = self.resp.raw._fp.fp.read1(self.chunk_size)
# print(chunk)
else:
# _fp is not available, this means that we cannot use short
# reads and this will block until the full chunk size is
# actually read
chunk = self.resp.raw.read(self.chunk_size)
if not chunk:
break
yield chunk
return generate()
self.resp 属性没有在init初始化里,但是 def iter_content(self) 的方法可以调用self.resp
我尝试简单实现下,报错
class A(object):
def __init__(self,name):
self.name = name
self.list = []
self._add()
def _add(self):
self.b= 1
self.resp = "haha"
while b<10:
yield self.b
self.b+=1
def p(self):
chunk = self.resp
print(chunk)
运行结果及报错内容
a = A("a")
a.p()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 a.p()
Input In [1], in A.p(self)
13 def p(self):
---> 14 chunk = self.resp
15 print(chunk)
AttributeError: 'A' object has no attribute 'resp'