subexprs = ["target"]
child_attrs = ["loop", "append"]
- # different behaviour in Py2 and Py3: leak loop variables or not?
- has_local_scope = False # Py2 behaviour as default
+ # leak loop variables or not? non-leaking Py3 behaviour is
+ # default, except for list comprehensions where the behaviour
+ # differs in Py2 and Py3 (see Parsing.py)
+ has_local_scope = True
def infer_type(self, env):
return self.target.infer_type(env)
loop = p_comp_for(s, append)
s.expect(']')
return ExprNodes.ComprehensionNode(
- pos, loop=loop, append=append, target=target)
+ pos, loop=loop, append=append, target=target,
+ # list comprehensions leak their loop variable in Py2
+ has_local_scope = s.context.language_level > 2)
else:
if s.sy == ',':
s.next()
# cython: language_level=3
+try:
+ sorted
+except NameError:
+ def sorted(seq):
+ seq = list(seq)
+ seq.sort()
+ return seq
+
def print_function(*args):
"""
>>> print_function(1,2,3)
"""
print(isinstance(ustring, unicode) or type(ustring))
return ustring
+
+def list_comp():
+ """
+ >>> list_comp()
+ [0, 4, 8]
+ """
+ x = 'abc'
+ result = [x*2 for x in range(5) if x % 2 == 0]
+ assert x == 'abc' # don't leak in Py3 code
+ return result
+
+def set_comp():
+ """
+ >>> sorted(set_comp())
+ [0, 4, 8]
+ """
+ x = 'abc'
+ result = {x*2 for x in range(5) if x % 2 == 0}
+ assert x == 'abc' # don't leak
+ return result
+
+def dict_comp():
+ """
+ >>> sorted(dict_comp().items())
+ [(0, 0), (2, 4), (4, 8)]
+ """
+ x = 'abc'
+ result = {x:x*2 for x in range(5) if x % 2 == 0}
+ assert x == 'abc' # don't leak
+ return result
result = { x+2:x*2
for x in range(5)
if x % 2 == 0 }
- assert x != 'abc'
+ assert x == 'abc' # do not leak!
return result
@cython.test_fail_if_path_exists(
>>> sorted(setcomp())
[0, 4, 8]
"""
- return { x*2
+ x = 'abc'
+ result = { x*2
for x in range(5)
if x % 2 == 0 }
+ assert x == 'abc' # do not leak
+ return result
@cython.test_fail_if_path_exists(
"//GeneratorExpressionNode",
>>> sorted(genexp_set())
[0, 4, 8]
"""
- return set( x*2
- for x in range(5)
- if x % 2 == 0 )
+ x = 'abc'
+ result = set( x*2
+ for x in range(5)
+ if x % 2 == 0 )
+ assert x == 'abc' # do not leak
+ return result
cdef class A:
def __repr__(self): return u"A"