Skip to content

Commit c24f29b

Browse files
committed
py: implement filter
1 parent 6e9db42 commit c24f29b

File tree

3 files changed

+140
-3
lines changed

3 files changed

+140
-3
lines changed

py/filter.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright 2023 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+
package py
6+
7+
// A python Filter object
8+
type Filter struct {
9+
it Object
10+
fun Object
11+
}
12+
13+
var FilterType = NewTypeX("filter", `filter(function or None, iterable) --> filter object
14+
15+
Return an iterator yielding those items of iterable for which function(item)
16+
is true. If function is None, return the items that are true.`,
17+
FilterTypeNew, nil)
18+
19+
// Type of this object
20+
func (f *Filter) Type() *Type {
21+
return FilterType
22+
}
23+
24+
// FilterTypeNew
25+
func FilterTypeNew(metatype *Type, args Tuple, kwargs StringDict) (res Object, err error) {
26+
var fun, seq Object
27+
var it Object
28+
err = UnpackTuple(args, kwargs, "filter", 2, 2, &fun, &seq)
29+
if err != nil {
30+
return nil, err
31+
}
32+
it, err = Iter(seq)
33+
if err != nil {
34+
return nil, err
35+
}
36+
return &Filter{it: it, fun: fun}, nil
37+
}
38+
39+
func (f *Filter) M__iter__() (Object, error) {
40+
return f, nil
41+
}
42+
43+
func (f *Filter) M__next__() (Object, error) {
44+
var ok bool
45+
for {
46+
item, err := Next(f.it)
47+
if err != nil {
48+
return nil, err
49+
}
50+
// if (lz->func == Py_None || lz->func == (PyObject *)&PyBool_Type)
51+
if _, _ok := f.fun.(Bool); _ok || f.fun == None {
52+
ok, err = ObjectIsTrue(item)
53+
} else {
54+
var good Object
55+
good, err = Call(f.fun, Tuple{item}, nil)
56+
if err != nil {
57+
return nil, err
58+
}
59+
ok, err = ObjectIsTrue(good)
60+
}
61+
if ok {
62+
return item, nil
63+
}
64+
if err != nil {
65+
return nil, err
66+
}
67+
}
68+
}
69+
70+
// Check interface is satisfied
71+
var _ I__iter__ = (*Filter)(nil)
72+
var _ I__next__ = (*Filter)(nil)

py/tests/filter.py

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# test_builtin.py:BuiltinTest.test_filter()
2+
from libtest import assertRaises
3+
4+
doc="filter"
5+
class T0:
6+
def __bool__(self):
7+
return True
8+
class T1:
9+
def __len__(self):
10+
return 1
11+
class T2:
12+
def __bool__(self):
13+
return False
14+
class T3:
15+
pass
16+
t0, t1, t2, t3 = T0(), T1(), T2(), T3()
17+
assert list(filter(None, [t0, t1, t2, t3])) == [t0, t1, t3]
18+
assert list(filter(None, [1, [], 2, ''])) == [1, 2]
19+
20+
class T3:
21+
def __len__(self):
22+
raise ValueError
23+
t3 = T3()
24+
assertRaises(ValueError, list, filter(None, [t3]))
25+
26+
class Squares:
27+
def __init__(self, max):
28+
self.max = max
29+
self.sofar = []
30+
31+
def __len__(self): return len(self.sofar)
32+
33+
def __getitem__(self, i):
34+
if not 0 <= i < self.max: raise IndexError
35+
n = len(self.sofar)
36+
while n <= i:
37+
self.sofar.append(n*n)
38+
n += 1
39+
return self.sofar[i]
40+
41+
assert list(filter(lambda c: 'a' <= c <= 'z', 'Hello World')) == list('elloorld')
42+
assert list(filter(None, [1, 'hello', [], [3], '', None, 9, 0])) == [1, 'hello', [3], 9]
43+
assert list(filter(lambda x: x > 0, [1, -3, 9, 0, 2])) == [1, 9, 2]
44+
assert list(filter(None, Squares(10))) == [1, 4, 9, 16, 25, 36, 49, 64, 81]
45+
assert list(filter(lambda x: x%2, Squares(10))) == [1, 9, 25, 49, 81]
46+
def identity(item):
47+
return 1
48+
filter(identity, Squares(5))
49+
assertRaises(TypeError, filter)
50+
class BadSeq(object):
51+
def __getitem__(self, index):
52+
if index<4:
53+
return 42
54+
raise ValueError
55+
assertRaises(ValueError, list, filter(lambda x: x, BadSeq()))
56+
def badfunc():
57+
pass
58+
assertRaises(TypeError, list, filter(badfunc, range(5)))
59+
60+
# test bltinmodule.c::filtertuple()
61+
assert list(filter(None, (1, 2))) == [1, 2]
62+
assert list(filter(lambda x: x>=3, (1, 2, 3, 4))) == [3, 4]
63+
assertRaises(TypeError, list, filter(42, (1, 2)))
64+
65+
doc="finished"

stdlib/builtin/builtin.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ func init() {
7777
"complex": py.ComplexType,
7878
"dict": py.StringDictType, // FIXME
7979
"enumerate": py.EnumerateType,
80-
// "filter": py.FilterType,
81-
"float": py.FloatType,
82-
"frozenset": py.FrozenSetType,
80+
"filter": py.FilterType,
81+
"float": py.FloatType,
82+
"frozenset": py.FrozenSetType,
8383
// "property": py.PropertyType,
8484
"int": py.IntType, // FIXME LongType?
8585
"list": py.ListType,

0 commit comments

Comments
 (0)