From 6b0f6b1a0b8de643dc3dc83d850901721361134f Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 13 Feb 2019 22:25:40 +0900 Subject: [PATCH] builtin: Implement builtin_iter --- builtin/builtin.go | 35 ++++++++++++++++++++++++++- builtin/tests/builtin.py | 44 ++++++++++++++++++++++++++++++++++ py/call_iterator.go | 51 ++++++++++++++++++++++++++++++++++++++++ py/tests/iter.py | 21 +++++++++++++++++ 4 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 py/call_iterator.go create mode 100644 py/tests/iter.py diff --git a/builtin/builtin.go b/builtin/builtin.go index 218f8744..af47833f 100644 --- a/builtin/builtin.go +++ b/builtin/builtin.go @@ -44,7 +44,7 @@ func init() { // py.MustNewMethod("input", builtin_input, 0, input_doc), // py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc), // py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc), - // py.MustNewMethod("iter", builtin_iter, 0, iter_doc), + py.MustNewMethod("iter", builtin_iter, 0, iter_doc), py.MustNewMethod("len", builtin_len, 0, len_doc), py.MustNewMethod("locals", py.InternalMethodLocals, 0, locals_doc), py.MustNewMethod("max", builtin_max, 0, max_doc), @@ -762,6 +762,39 @@ object. The globals and locals are dictionaries, defaulting to the current globals and locals. If only globals is given, locals defaults to it.` +const iter_doc = `iter(iterable) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel. +` + +func builtin_iter(self py.Object, args py.Tuple) (py.Object, error) { + nArgs := len(args) + if nArgs < 1 { + return nil, py.ExceptionNewf(py.TypeError, + "iter expected at least 1 arguments, got %d", + nArgs) + } else if nArgs > 2 { + return nil, py.ExceptionNewf(py.TypeError, + "iter expected at most 2 arguments, got %d", + nArgs) + } + + v := args[0] + if nArgs == 1 { + return py.Iter(v) + } + _, ok := v.(*py.Function) + sentinel := args[1] + if !ok { + return nil, py.ExceptionNewf(py.TypeError, + "iter(v, w): v must be callable") + } + return py.NewCallIterator(v, sentinel), nil +} + // For code see vm/builtin.go const len_doc = `len(object) -> integer diff --git a/builtin/tests/builtin.py b/builtin/tests/builtin.py index 4bb01106..ac3f7dc1 100644 --- a/builtin/tests/builtin.py +++ b/builtin/tests/builtin.py @@ -132,6 +132,50 @@ def func(p): ok = True assert ok, "ValueError not raised" +doc="iter" +cnt = 0 +def f(): + global cnt + cnt += 1 + return cnt + +l = list(iter(f,20)) +assert len(l) == 19 +for idx, v in enumerate(l): + assert idx + 1 == v + +words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n'] +words2 = list(iter(words1)) +for w1, w2 in zip(words1, words2): + assert w1 == w2 + +ok = False +try: + iter() +except TypeError: + ok = True +finally: + assert ok, "TypeError not raised" + ok = False + +try: + l = [1, 2, 3] + iter(l, 2) +except TypeError: + ok = True +finally: + assert ok, "TypeError not raised" + ok = False + +try: + iter(f, 2, 3) +except TypeError: + ok = True +finally: + assert ok, "TypeError not raised" + ok = False + + doc="next no default" def gen(): yield 1 diff --git a/py/call_iterator.go b/py/call_iterator.go new file mode 100644 index 00000000..36e85a79 --- /dev/null +++ b/py/call_iterator.go @@ -0,0 +1,51 @@ +// Copyright 2019 The go-python Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CallIterator objects + +package py + +// A python CallIterator object +type CallIterator struct { + callable Object + sentinel Object +} + +var CallIteratorType = NewType("callable_iterator", "callable_iterator type") + +// Type of this object +func (o *CallIterator) Type() *Type { + return CallIteratorType +} + +func (cit *CallIterator) M__iter__() (Object, error) { + return cit, nil +} + +// Get next one from the iteration +func (cit *CallIterator) M__next__() (Object, error) { + value, err := Call(cit.callable, nil, nil) + + if err != nil { + return nil, err + } + + if value == cit.sentinel { + return nil, StopIteration + } + + return value, nil +} + +// Define a new CallIterator +func NewCallIterator(callable Object, sentinel Object) *CallIterator { + c := &CallIterator{ + callable: callable, + sentinel: sentinel, + } + return c +} + +// Check interface is satisfied +var _ I_iterator = (*CallIterator)(nil) diff --git a/py/tests/iter.py b/py/tests/iter.py new file mode 100644 index 00000000..53422b79 --- /dev/null +++ b/py/tests/iter.py @@ -0,0 +1,21 @@ +# Copyright 2019 The go-python Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +doc="iter" +cnt = 0 +def f(): + global cnt + cnt += 1 + return cnt + +l = list(iter(f,20)) +assert len(l) == 19 +for idx, v in enumerate(l): + assert idx + 1 == v + +words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n'] +words2 = list(iter(words1)) +for w1, w2 in zip(words1, words2): + assert w1 == w2 +doc="finished" \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy