Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 我可以从实例方法中让步吗_Python_Itertools - Fatal编程技术网

Python 我可以从实例方法中让步吗

Python 我可以从实例方法中让步吗,python,itertools,Python,Itertools,在类的实例方法中使用yield语句可以吗?比如说, # 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 i

在类的实例方法中使用yield语句可以吗?比如说,

# 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并不抱怨这一点,简单的案例似乎也能奏效。然而,我只看到了从正则函数得到收益的例子

当我尝试将它与itertools函数一起使用时,我开始遇到问题。例如,假设我有两个大数据流X和Y,它们存储在多个文件中,我只想通过数据的一个循环计算它们的和和和差。我可以像下图一样使用
itertools.tee
itertools.izip

在代码中是这样的(对不起,太长了)

但是,除非我将
itertools.izip
换成
itertools.izip\u 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 
不等于

>>> 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)

我不明白当我的
n个
实例的长度相同时,它们是如何以不同的状态结束的。例如,如果我给出两个长度相等的字符串

>>> [''.join(x) for x in izip('ABCD','abcd')]
['Aa', 'Bb', 'Cc', 'Dd']
我得到了同样长度的结果;为什么我的
n.itervalues
生成器似乎得到的
next()
调用数不相等,即使每个调用产生的结果数相同

快速回答 您从未在
第n类中重置
self.i
self.nout
。此外,您应该使用以下内容:

# 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
def izip(A, B):
    try:
        while True:
            a = A.next()
            b = B.next()
            yield a,b
    except StopIteration:
        pass
但是,由于您甚至不需要
nout
,因此您应该使用:

def Nth(iterable, step):
    return enumerate(itertools.islice(iterable, step - 1, None, step)) 
长话短说 您的代码有一股异味,这让我在NthSumDiff.itervalues()中找到了这一行:

如果您交换
gen\u sum
gen\u diff
,您将看到
gen\u diff
始终是
nout
大于1的一个。这是因为
izip()
在从
genu diff
提取之前,先从
genu sum
提取
gen_sum
在上一次迭代中尝试
gen_diff
之前引发StopIteration异常

例如,假设您选取N个样本,其中N%step==7。在每次迭代结束时,第n个实例的self.i
应等于0。但是在最后一次迭代中,
gen\u sum
中的
self.i
将增加到7,然后
x
中将不再有元素。它将引发停止迭代
gen_diff
仍然位于
self.i
等于0

如果将
self.i=0
self.nout=0
添加到n.itervalues()的开头,问题就会消失

课程 您之所以会遇到这个问题,是因为您的代码太复杂,而且不符合python。如果您发现自己在循环中使用了大量计数器和索引,那么(在Python中)退一步看看是否可以简化代码是个好兆头。我有很长的C编程历史,因此,我仍然时常发现自己在用Python做同样的事情

更简单的实现 把我的钱放在嘴边

更多关于这个问题的解释 针对Brian的评论:


这可不是一回事。不重置i和nout是错误的 故意的。我基本上有一个连续的数据流X 分割成几个文件。切片块会产生不同的效果 结果比切片连接的流(我之前评论过 可能使用itertools.chain)。而且我的实际程序更简单 比单纯的切片复杂;这只是一个有效的例子。我不 理解关于停止迭代顺序的解释。如果 izip('ABCD','ABCD')-->Aa Bb Cc Dd那么它看起来是等长的 发电机应获得相同数量的下一次呼叫,否布瑞恩 霍金斯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's how for loops and
        # others know when to stop.
在上面的
itervalues(x)
中,对于每个
next()
调用,它会在内部增加
self.i
self.n
值,然后产生或增加
self.i
中剩余的对象数,然后退出for循环,然后退出生成器(itervalues()是一个发电机,因为它会产生)。当itervalues()生成器退出时,Python会引发StopIteration异常

因此,对于用N初始化的
类N的每个实例,
self.i
在耗尽
itervalues(X)
中的所有元素后的值将为:

self.i = value_of_self_i_before_itervalues(X) + len(X) % N
现在,当您在
izip(n_1,n_2)
上迭代时,它将执行如下操作:

# 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
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
在最后

第二次尝试简化(要求正确) 下面是另一个简化版本,它将所有文件数据视为一个连续流。它使用链式、小型、可重复使用的发电机。我非常非常推荐看这个。从你的问题描述中猜测,它应该是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

把讨论浓缩起来,什么都没有
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
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.