What's the advantage of using yield in __iter__()?

有些话、适合烂在心里 提交于 2019-11-28 04:35:10

问题


What is the advantage of using an generator(yield) inside an __iter__() function? After reading through Python Cookbook I understand "If you want a generator to expose extra state to the user, don’t forget that you can easily implement it as a class, putting the generator function code in the __iter__() method."

import io

class playyield:
    def __init__(self,fp):
        self.completefp = fp

    def __iter__(self):
        for line in self.completefp:
            if 'python' in line:
                yield line

if __name__ =='__main__':
    with io.open(r'K:\Data\somefile.txt','r') as fp:
        playyieldobj = playyield(fp)
        for i in playyieldobj:
            print I

Questions:

  1. What does extra state means here?
  2. What is the advantage of using yield inside __iter__ () instead of using a separate function for yield?

回答1:


Without generator functions, you would have to implement something like this, if you want to follow best practices:

In [7]: class IterableContainer:
   ...:     def __init__(self, data=(1,2,3,4,5)):
   ...:         self.data = data
   ...:     def __iter__(self):
   ...:         return IterableContainerIterator(self.data)
   ...:

In [8]: class IterableContainerIterator:
   ...:     def __init__(self, data):
   ...:         self.data = data
   ...:         self._pos = 0
   ...:     def __iter__(self):
   ...:         return self
   ...:     def __next__(self):
   ...:         try:
   ...:              item = self.data[self._pos]
   ...:         except IndexError:
   ...:             raise StopIteration
   ...:         self._pos += 1
   ...:         return item
   ...:

In [9]: container = IterableContainer()

In [10]: for x in container:
    ...:     print(x)
    ...:
1
2
3
4
5

Of course, the above example is contrived, but hopefully you get the point. With generators, this can simply be:

In [11]: class IterableContainer:
    ...:     def __init__(self, data=(1,2,3,4,5)):
    ...:         self.data = data
    ...:     def __iter__(self):
    ...:         for x in self.data:
    ...:             yield x
    ...:
    ...:

In [12]: list(IterableContainer())
Out[12]: [1, 2, 3, 4, 5]

As for state, well, it's exactly that - objects can have state, e.g. attributes. You can manipulate that state at runtime. You could do something like the following, although, I would say it is highly inadvisable:

In [19]: class IterableContainerIterator:
    ...:     def __init__(self, data):
    ...:         self.data = data
    ...:         self._pos = 0
    ...:     def __iter__(self):
    ...:         return self
    ...:     def __next__(self):
    ...:         try:
    ...:              item = self.data[self._pos]
    ...:         except IndexError:
    ...:             raise StopIteration
    ...:         self._pos += 1
    ...:         return item
    ...:     def rewind(self):
    ...:         self._pos = min(0, self._pos - 1)
    ...:

In [20]: class IterableContainer:
    ...:     def __init__(self, data=(1,2,3,4,5)):
    ...:         self.data = data
    ...:     def __iter__(self):
    ...:         return IterableContainerIterator(self.data)
    ...:

In [21]: container = IterableContainer()

In [22]: it = iter(container)

In [23]: next(it)
Out[23]: 1

In [24]: next(it)
Out[24]: 2

In [25]: it.rewind()

In [26]: next(it)
Out[26]: 1

In [27]: next(it)
Out[27]: 2

In [28]: next(it)
Out[28]: 3

In [29]: next(it)
Out[29]: 4

In [30]: next(it)
Out[30]: 5

In [31]: it.rewind()

In [32]: next(it)
Out[32]: 1



回答2:


import json
import urllib

serviceurl = 'http://www.py4e.com/code3/geojson.py'

while True:
    address = input("Enter location:")
    if len(address) <1: break

    url = serviceurl+ urllib.urlencode ({"sensor": "false,", "address":address})
    print ("retrieving", url)
    uh = urllib.urlopen(url)
    data = uh.read()
    print ("retrieved", len(data), "characters")
    try: js=json.loads(str(data))
    except: js= None
    if "status" not in js or js['status'] != "OK":
        print ("=== failure to retrieve ===")
        print (data)
        continue

    print (json.dumps(js, indent = 4))

    lat = js["results"] [0] ["geometry"] ["location"]["lat"]
    lng = js["results"] [0] ["geometry"] ["location"]["lng"]
    print ("lat", lat, "lng", lng)
    location = js["results"][0] ["formatted_address"]
    print (location)




来源:https://stackoverflow.com/questions/45685538/whats-the-advantage-of-using-yield-in-iter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!