发电机可以多次使用吗?

时间:2017-07-30 12:51:43

标签: python generator yield-keyword

这是我的一段代码,定义了两个生成器:

let imagePicker: UIImagePickerController! = UIImagePickerController()
let saveFileName = "/test.mp4"

             if (UIImagePickerController.isSourceTypeAvailable(.camera)) {
        if UIImagePickerController.availableCaptureModes(for: .rear) != nil {

            //if the camera is available, and if the rear camera is available, the let the image picker do this
            imagePicker.sourceType = .camera
            imagePicker.mediaTypes = [kUTTypeMovie as String]
            imagePicker.allowsEditing = false
            imagePicker.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
            imagePicker.videoMaximumDuration = 60
            imagePicker.videoQuality = .typeIFrame1280x720
            present(imagePicker, animated: true, completion: nil)
        } else {
            postAlert("Rear camera doesn't exist", message: "Application cannot access the camera.")
        }
    } else {
        postAlert("Camera inaccessable", message: "Application cannot access the camera.")
    }
}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    print(123)
    imagePickerController(imagePicker, didFinishPickingMediaWithInfo: [saveFileName : kUTTypeMovie])

    let videoURL = info[UIImagePickerControllerReferenceURL] as? NSURL
    print("\(String(describing: videoURL))" )
    guard let path = videoURL?.path else { return }
    let videoName = path.lastPathComponent
    let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
    let documentDirectory = paths.first as String!
    let localPath = documentDirectory! + "/" + videoName
    guard  let imageData = NSData(contentsOfFile: localPath) else { return }
    let image = UIImage(data: imageData as Data)

    picker.dismiss(animated: true, completion: nil)
}
override func viewDidLoad() {
    super.viewDidLoad()
    self.imagePicker.delegate = self 
}

执行时:

one_line_gen = (x for x in range(3))

def three_line_gen():
    yield 0
    yield 1
    yield 2

结果如预期:

for x in one_line_gen:
    print x

for x in one_line_gen:
    print x

但是,如果我执行:

0
1
2

结果是:

for x in three_line_gen():
    print x

for x in three_line_gen():
    print x

为什么呢?我以为任何发电机只能使用一次。

5 个答案:

答案 0 :(得分:12)

XElement不是生成器,它是一个函数。当你打电话给它时它返回的是一个发电机,每次调用它时都是一个全新的发电机。每次你像这样放括号:

var comments = xml.Root.NodesAfterSelf().OfType<XComment>();

这是一个值得迭代的全新生成器。但是,如果你是第一次做

three_line_gen

并迭代three_line_gen() 两次,第二次将按预期失败。

答案 1 :(得分:3)

不,你不能两次迭代生成器。迭代后,生成器会耗尽。您可以使用tee创建一个生成器的副本:

from itertools import tee

one_line_gen = (x for x in range(3))
gen1, gen2 = tee(one_line_gen)
# or: 
# gen1, gen2 = tee(x for x in range(3))

for item in gen1:
    print(item)

for item in gen2:
    print(item)

其他问题请参阅Ofer Sadan's answer

答案 2 :(得分:1)

  

为什么呢?我以为任何发电机只能使用一次。

因为每次调用 three_line_gen()都会创建一个新的生成器。

否则,你是正确的,发电机只能向前运行直到用尽。

  

发电机可以多次使用吗?

是的,如果结果在发生器外缓冲,则可能。一种简单的方法是使用itertools.tee()

>>> from itertools import tee
>>> def three_line_gen():
        yield 0
        yield 1
        yield 2

>>> t1, t2 = tee(three_line_gen())
>>> next(t1)
0
>>> next(t2)
0
>>> list(t1)
[1, 2]
>>> list(t2)
[1, 2]

答案 3 :(得分:0)

因为在一个班轮中是mygen = three_line_gen() 对象而三个班轮是mygen。 他们的意思不同。

这两个是相似的。

Generator

答案 4 :(得分:0)

是的,发电机只能使用一次。但你有两个生成器对象。

# Python 3


def three_line_gen():
    yield 0
    yield 1
    yield 2

iterator = three_line_gen()
print(iterator)
for x in iterator:
    print(id(iterator), x)

iterator2 = three_line_gen()
print(iterator2)
for x in iterator2:
    print(id(iterator2), x)

结果是:

<generator object three_line_gen at 0x1020401b0>
4328784304 0
4328784304 1
4328784304 2
<generator object three_line_gen at 0x1020401f8>
4328784376 0
4328784376 1
4328784376 2