Can i get the instance method

Can I use the yield statement in an instance method of a class? For example,

# Similar to itertools.islice
class Nth(object):
    def __init__(self, n):
        self.n = n
        self.i = 0
        self.nout = 0

    def itervalues(self, x):
        for xi in x:
            self.i += 1
            if self.i == self.n:
                self.i = 0
                self.nout += 1
                yield self.nout, xi

Python doesn't complain about this, and simple cases seem to work. However, I only saw examples with exiting regular functions.

I am having problems when I try to use it with itertools functions. For example, suppose I have two large data streams X and Y that are stored in several files, and I want to calculate their sum and difference with only one data cycle. I could use itertools.teeand itertools.izip, as in the following diagram

data stream

In the code, it will be something like this (sorry, this is a long time)

from itertools import izip_longest, izip, tee
import random

def add(x,y):
    for xi,yi in izip(x,y):
        yield xi + yi

def sub(x,y):
    for xi,yi in izip(x,y):
        yield xi - yi

class NthSumDiff(object):
    def __init__(self, n):
        self.nthsum = Nth(n)
        self.nthdiff = Nth(n)

    def itervalues(self, x, y):
        xadd, xsub = tee(x)
        yadd, ysub = tee(y)
        gen_sum = self.nthsum.itervalues(add(xadd, yadd))
        gen_diff = self.nthdiff.itervalues(sub(xsub, ysub))
        # Have to use izip_longest here, but why?
        #for (i,nthsum), (j,nthdiff) in izip_longest(gen_sum, gen_diff):
        for (i,nthsum), (j,nthdiff) in izip(gen_sum, gen_diff):
            assert i==j, "sum row %d != diff row %d" % (i,j)
            yield nthsum, nthdiff

nskip = 12
ns = Nth(nskip)
nd = Nth(nskip)
nsd = NthSumDiff(nskip)
nfiles = 10
for i in range(nfiles):
    # Generate some data.
    # If the block length is a multiple of nskip there no problem.
    #n = random.randint(5000, 10000) * nskip
    n = random.randint(50000, 100000)
    print 'file %d n=%d' % (i, n)
    x = range(n)
    y = range(100,n+100)
    # Independent processing is no problem but requires two loops.
    for i, nthsum in ns.itervalues(add(x,y)):
        pass
    for j, nthdiff in nd.itervalues(sub(x,y)):
        pass
    assert i==j
    # Trying to do both with one loops causes problems.
    for nthsum, nthdiff in nsd.itervalues(x,y):
        # If izip_longest is necessary, why don't I ever get a fillvalue?
        assert nthsum is not None
        assert nthdiff is not None
    # After each block of data the two iterators should have the same state.
    assert nsd.nthsum.nout == nsd.nthdiff.nout, \
           "sum nout %d != diff nout %d" % (nsd.nthsum.nout, nsd.nthdiff.nout)

, itertools.izip out itertools.izip_longest, . assert, ,

file 0 n=58581
file 1 n=87978
Traceback (most recent call last):
  File "test.py", line 71, in <module>
    "sum nout %d != diff nout %d" % (nsd.nthsum.nout, nsd.nthdiff.nout)
AssertionError: sum nout 12213 != diff nout 12212 

. , , , X Y ( ). , . , Nth

>>> x1 = range(0,10)
>>> x2 = range(10,20)
>>> (x1 + x2)[::3]
[0, 3, 6, 9, 12, 15, 18]

>>> x1[::3] + x2[::3]
[0, 3, 6, 9, 10, 13, 16, 19]

itertools.chain, , Nth.itervalues, , Nth ( , , Nth/add/subtract).

, Nth , . , izip

>>> [''.join(x) for x in izip('ABCD','abcd')]
['Aa', 'Bb', 'Cc', 'Dd']

; Nth.itervalues, , next(), ?

+4
2

, yield per se. izip, yield, izip next() , .

from itertools import izip

class Three(object):
    def __init__(self):
        self.status = 'init'

    def run(self):
        self.status = 'running'
        yield 1
        yield 2
        yield 3
        self.status = 'done'
        raise StopIteration()

it = Three()
for x in it.run():
    assert it.status == 'running'
assert it.status == 'done'

it1, it2 = Three(), Three()
for x, y in izip(it1.run(), it2.run()):
    pass
assert it1.status == 'done'
assert it2.status == 'done', "Expected status=done, got status=%s." % it2.status

,

AssertionError: Expected status=done, got status=running.

Nth yield, izip. izip_longest , . , .

+1

Gist |

reset self.i self.nout class Nth. , - :

# Similar to itertools.islice
class Nth(object):
    def __init__(self, n):
        self.n = n

    def itervalues(self, x):
        for a,b in enumerate(islice(x, self.n - 1, None, self.n)):
            self.nout = a
            yield a,b

nout, :

def Nth(iterable, step):
    return enumerate(itertools.islice(iterable, step - 1, None, step)) 

, NthSumDiff.itervalues ​​():

for (i,nthsum), (j,nthdiff) in izip(gen_sum, gen_diff):

gen_sum gen_diff, , gen_diff nout . , izip() gen_sum gen_diff. gen_sum StopIteration , gen_diff .

, , N , N% step == 7. self.i N- 0. self.i gen_sum 7, x . StopIteration. gen_diff self.i, 0.

self.i = 0 self.nout = 0 Nth.itervalues ​​(), .

, , Pythonic. , , ( Python), , . C, , , , Python.

, ...

from itertools import izip, islice
import random

def sumdiff(x,y,step):
    # filter for the Nth values of x and y now
    x = islice(x, step-1, None, step)
    y = islice(y, step-1, None, step)
    return ((xi + yi, xi - yi) for xi, yi in izip(x,y))

nskip = 12
nfiles = 10
for i in range(nfiles):
    # Generate some data.
    n = random.randint(50000, 100000)
    print 'file %d n=%d' % (i, n)
    x = range(n)
    y = range(100,n+100)
    for nthsum, nthdiff in sumdiff(x,y,nskip):
        assert nthsum is not None
        assert nthdiff is not None
    assert len(list(sumdiff(x,y,nskip))) == n/nskip

:

. nout . X, . , ( , itertools.chain). , ; . StopIteration. izip ('ABCD', 'abcd') → Aa Bb Cc Dd, , ? - Hawkins 6

, , . . -, , itervalues(x).

# Similar to itertools.islice
class Nth(object):
    def __init__(self, n):
        self.n = n
        self.i = 0
        self.nout = 0

    def itervalues(self, x):
        for xi in x:
            # We increment self.i by self.n on every next()
            # call to this generator method unless the
            # number of objects remaining in x is less than
            # self.n. In that case, we increment by that amount
            # before the for loop exits normally.
            self.i += 1
            if self.i == self.n:
                self.i = 0
                self.nout += 1
                # We're yielding, so we're a generator
                yield self.nout, xi
        # Python helpfully raises StopIteration to fulfill the 
        # contract of an iterable. That how for loops and
        # others know when to stop.

itervalues(x) , next() self.i self.n, , self.i , x, (itervalues ​​() , ). itervalues ​​() , Python StopIteration.

, class Nth, N, self.i itervalues(x) :

self.i = value_of_self_i_before_itervalues(X) + len(X) % N

, izip(Nth_1, Nth_2), - :

def izip(A, B):
    try:
        while True:
            a = A.next()
            b = B.next()
            yield a,b
    except StopIteration:
        pass

, N=10 len(X)=13. next() izip(), A, B self.i==0 . A.next() , self.i += 3, X, for, , Python StopIteration. izip() , B.next() . , A.i==3 B.i==0 .

( )

, . , , . , PyCon '14 . , 100% .

from itertools import izip, islice
import random

def sumdiff(data):
    return ((x + y, x - y) for x, y in data)

def combined_file_data(files):
    for i,n in files:
        # Generate some data.
        x = range(n)
        y = range(100,n+100)
        for data in izip(x,y):
            yield data

def filelist(nfiles):
    for i in range(nfiles):
        # Generate some data.
        n = random.randint(50000, 100000)
        print 'file %d n=%d' % (i, n)
        yield i, n

def Nth(iterable, step):
    return islice(iterable, step-1, None, step)

nskip = 12
nfiles = 10
filedata = combined_file_data(filelist(nfiles))
nth_data = Nth(filedata, nskip)
for nthsum, nthdiff in sumdiff(nth_data):
    assert nthsum is not None
    assert nthdiff is not None
+2

Source: https://habr.com/ru/post/1616667/


All Articles