Skip to content

Commit 29323cf

Browse files
committed
builtin: Implement builtin_iter
1 parent 05fb6f3 commit 29323cf

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

builtin/builtin.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func init() {
4444
// py.MustNewMethod("input", builtin_input, 0, input_doc),
4545
// py.MustNewMethod("isinstance", builtin_isinstance, 0, isinstance_doc),
4646
// py.MustNewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
47-
// py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
47+
py.MustNewMethod("iter", builtin_iter, 0, iter_doc),
4848
py.MustNewMethod("len", builtin_len, 0, len_doc),
4949
py.MustNewMethod("locals", py.InternalMethodLocals, 0, locals_doc),
5050
py.MustNewMethod("max", builtin_max, 0, max_doc),
@@ -762,6 +762,39 @@ object.
762762
The globals and locals are dictionaries, defaulting to the current
763763
globals and locals. If only globals is given, locals defaults to it.`
764764

765+
const iter_doc = `iter(iterable) -> iterator
766+
iter(callable, sentinel) -> iterator
767+
768+
Get an iterator from an object. In the first form, the argument must
769+
supply its own iterator, or be a sequence.
770+
In the second form, the callable is called until it returns the sentinel.
771+
`
772+
773+
func builtin_iter(self py.Object, args py.Tuple) (py.Object, error) {
774+
nArgs := len(args)
775+
if nArgs < 1 {
776+
return nil, py.ExceptionNewf(py.TypeError,
777+
"iter expected at least 1 arguments, got %d",
778+
nArgs)
779+
} else if nArgs > 2 {
780+
return nil, py.ExceptionNewf(py.TypeError,
781+
"iter expected at most 2 arguments, got %d",
782+
nArgs)
783+
}
784+
785+
v := args[0]
786+
if nArgs == 1 {
787+
return py.Iter(v)
788+
}
789+
_, ok := v.(*py.Function)
790+
sentinel := args[1]
791+
if !ok {
792+
return nil, py.ExceptionNewf(py.TypeError,
793+
"iter(v, w): v must be callable")
794+
}
795+
return py.NewCallIterator(v, sentinel), nil
796+
}
797+
765798
// For code see vm/builtin.go
766799

767800
const len_doc = `len(object) -> integer

builtin/tests/builtin.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ def func(p):
132132
ok = True
133133
assert ok, "ValueError not raised"
134134

135+
doc="iter"
136+
cnt = 0
137+
def f():
138+
global cnt
139+
cnt += 1
140+
return cnt
141+
142+
l = list(iter(f,20))
143+
assert len(l) == 19
144+
for idx, v in enumerate(l):
145+
assert idx + 1 == v
146+
147+
words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n']
148+
words2 = list(iter(words1))
149+
for w1, w2 in zip(words1, words2):
150+
assert w1 == w2
151+
152+
ok = False
153+
try:
154+
iter()
155+
except TypeError:
156+
ok = True
157+
finally:
158+
assert ok, "TypeError not raised"
159+
ok = False
160+
161+
try:
162+
l = [1, 2, 3]
163+
iter(l, 2)
164+
except TypeError:
165+
ok = True
166+
finally:
167+
assert ok, "TypeError not raised"
168+
ok = False
169+
170+
try:
171+
iter(f, 2, 3)
172+
except TypeError:
173+
ok = True
174+
finally:
175+
assert ok, "TypeError not raised"
176+
ok = False
177+
178+
135179
doc="next no default"
136180
def gen():
137181
yield 1

py/call_iterator.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2019 The go-python Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// CallIterator objects
6+
7+
package py
8+
9+
// A python CallIterator object
10+
type CallIterator struct {
11+
callable Object
12+
sentinel Object
13+
}
14+
15+
var CallIteratorType = NewType("callable_iterator", "callable_iterator type")
16+
17+
// Type of this object
18+
func (o *CallIterator) Type() *Type {
19+
return CallIteratorType
20+
}
21+
22+
func (cit *CallIterator) M__iter__() (Object, error) {
23+
return cit, nil
24+
}
25+
26+
// Get next one from the iteration
27+
func (cit *CallIterator) M__next__() (Object, error) {
28+
f, ok := cit.callable.(*Function)
29+
if !ok {
30+
return nil, ExceptionNewf(TypeError, "'%s' object is not callable", f.Type())
31+
}
32+
value, err := Call(f, nil, nil)
33+
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
if value == cit.sentinel {
39+
return nil, StopIteration
40+
}
41+
42+
return value, nil
43+
}
44+
45+
// Define a new CallIterator
46+
func NewCallIterator(callable Object, sentinel Object) *CallIterator {
47+
c := &CallIterator{
48+
callable: callable,
49+
sentinel: sentinel,
50+
}
51+
return c
52+
}
53+
54+
// Check interface is satisfied
55+
var _ I_iterator = (*CallIterator)(nil)

py/tests/iter.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright 2019 The go-python Authors. All rights reserved.
2+
# Use of this source code is governed by a BSD-style
3+
# license that can be found in the LICENSE file.
4+
5+
doc="iter"
6+
cnt = 0
7+
def f():
8+
global cnt
9+
cnt += 1
10+
return cnt
11+
12+
l = list(iter(f,20))
13+
assert len(l) == 19
14+
for idx, v in enumerate(l):
15+
assert idx + 1 == v
16+
17+
words1 = ['g', 'p', 'y', 't', 'h', 'o', 'n']
18+
words2 = list(iter(words1))
19+
for w1, w2 in zip(words1, words2):
20+
assert w1 == w2
21+
doc="finished"

0 commit comments

Comments
 (0)
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