あなたが新たに毎回ジェネレータを作成している:
gen = self.proxy_handler.yield_proxy()
gen.next()
新しい発電機が起動します最初から;別々の発電機は状態を共有しません。ジェネレータをどこかに保存し、そのオブジェクトを再利用して新しい値を取得します。
あなたはおそらくself
に属性としてそのジェネレータオブジェクトを格納することができ:
proxy_generator = None
def get_response(self, url):
if not self.proxy:
if self.proxy_generator is None
self.proxy_generator = self.proxy_handler.yield_proxy()
self.proxy = next(self.proxy_generator)
proxy = self.proxy
は、私はあなたが、遅かれ早かれに切り替える必要がありますのPython 3(との上位互換性、あなたのコードを維持するためにnext()
functionを使用し、 Python 2は従来の言語です)。
次に、あなたの発電機がスローされることは決してないだろう。例外をキャッチしようとします:では
for p in self.proxies:
try:
proxy = {'http': 'http://%s:%s' % (p[0], p[1])} # Formatted to python's request lib proxy format
self.current = proxy
yield proxy
except StopIteration:
print 'Reached end of proxy list'
self.current = {}
self.get_proxies()
yield self.yield_proxy()
をごtry
アクセスされている何のジェネレータがありません。あなたはfor
ループにself.proxies
以上の仕事を、for
はすでにがループを終了するにはStopIterator
をキャッチする方法を知っています。とにかくself.proxies
はリストに過ぎません。
あなたがプロキシを介してループサイクルを作りたいと思った場合は、無限while True
ループでそれを行う:
while True:
for p in self.proxies:
proxy = {'http': 'http://%s:%s' % (p[0], p[1])} # Formatted to python's request lib proxy format
self.current = proxy
yield proxy
print 'Reached end of proxy list'
self.current = {}
self.get_proxies()
あなたがそこにself.current
をクリアする必要があり、再フェッチと思う私はなぜわからないんだけどプロキシあなたのジェネレータのタプルは変更されていないので、なぜ再フェッチするのですか?そして、ループを最初からやり直しても、現在のプロキシは有効です。私はそれらの最後の3行を削除します。
コードをさらに簡単にすることができます。発電機は長さがないので、__len__
の方法は必要ありません。せいぜい、この方法はが間違ったという情報を生成します。 self.proxies
属性は反復処理を開始するまでは空白なので、オブジェクトの長さは0から始まります。メソッドを完全に削除します。ただ、すべてのこれらの値を生成するジェネレータを取得するためにiter(self.proxy_handler)
の代わりself.proxy_handler.yield_proxy()
を使用し、
class ProxyHandler:
def __init__(self):
self.proxies = []
self.current = {}
def get_proxies(self):
""" Retrieves proxies """
def __iter__(self):
if not self.proxies:
print 'Created new proxy list'
self.get_proxies()
while True:
for p in self.proxies:
proxy = {'http': 'http://%s:%s' % (p[0], p[1])}
self.current = proxy
yield proxy
これは全体ProxyHandler
インスタンス反復可能になります:
次に、あなたのオブジェクト発電機を生産__iter__
方法を与えることができます。
最後に、ジェネレータ式をitertools.cycle()
と一緒に使用すると、イテレータを無限にすることができます。ただし、current
属性をドロップする必要がありますが、あなたのジェネレータはとにかく現在のオブジェクトが生じたとき、あなたが実際にその属性を必要としないとして、それは本当に問題ではないはずです。
from itertools import cycle
class ProxyHandler:
def __init__(self):
self.proxies = []
def get_proxies(self):
""" Retrieves proxies """
def __iter__(self):
if not self.proxies:
print 'Created new proxy list'
self.get_proxies()
return cycle({'http': 'http://%s:%s' % (p[0], p[1])} for p in self.proxies)
をジェネレータ式が生成します同じ種類のオブジェクト。
これはまだすべてiter(self.proxy_generator)
が必要です。 __iter__
return self
を返し、next()
メソッドを追加することによって、イテレータ(イテラータブルではなく)をインスタンスにすることができます。値を生成することにnext()
呼び出しに渡し、その後、最初の呼び出しの属性に上記のジェネレータ式を移動:
class ProxyHandler:
def __init__(self):
self.proxies = []
self._gen = None
def get_proxies(self):
""" Retrieves proxies """
def __iter__(self):
return self
def next(self):
if not self._gen:
self.get_proxies()
self._gen = cycle({'http': 'http://%s:%s' % (p[0], p[1])} for p in self.proxies)
return next(self._gen)
__next__ = next # Python 3 compatibility
今、あなたは `次の(self.proxy_handler)ごとに使用することができます。
def get_response(self, url):
if not self.proxy:
self.proxy = next(self.proxy_handler)
proxy = self.proxy
これを解決するには、私のメソッド外にジェネレータを作成し、必要なときに呼び出す必要がありますか? –
@galalmighty:正確に。ジェネレータは状態を保持する単一オブジェクトです。値を必要とするたびに置き換えるのではなく、代わりにそれを保持してください。 –
洞察を深め、詳細で非常にクリア。ありがとうございました!約10分で多くのことを学びました。 –