[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [HTCondor-users] list(ExprTree) infinite loop



> On Nov 20, 2014, at 2:27 PM, Brian Candler <b.candler@xxxxxxxxx> wrote:
> 
> On 19/11/2014 22:09, Brian Bockelman wrote:
>> It's a really interesting one; I'm not sure of the way to solve this.  Stumped the expert!
>> 
>> Basically, when you call list(classad.ExprTree("2+2")), the python starts putting together a list.  It notes that ExprTree provides "__getitem__" and begins building a list like this:
>> 
>> [classad.ExprTree("2+2")[0], classad.ExprTree("2+2")[1], ... ]
>> 
>> I think it continues to do that until an IndexError is thrown.
>> 
>> So, what's the problem here?
>> 
>> The expression tree is lazily-evaluated.  classad.ExprTree("2+2")[0] is equivalent to "(2+2)[0]".  This is a perfectly valid expression - which is obviously going to end in error when you evaluate it.  However, without evaluating it, we've got no way to know it'll end in tears.
> Hmm. It doesn't seem the __getitem__ call is lazy for all types of ExprTree, because in the case of a list ExprTree, it appears to evaluate immediately:
> 
> >>> import classad
> >>> a = classad.ExprTree('{"foo","bar"}')
> >>> a[0]
> 'foo'
> >>> a[1]
> 'bar'
> >>> type(a[0])
> <type 'str'>
> 
> It doesn't return expression {"foo","bar"}[0]
> 
> Also, 2[0] does not have any meaning:
> 
> >>> a = classad.ExprTree('2')
> >>> a[0]
> Traceback (most recent call last):
>  File "<stdin>", line 1, in <module>
> TypeError: 'long' object has no attribute '__getitem__'

Correct - in the case of a list or literal expression (boolean, string, long), the current code immediately evaluates.

Non-trivial expressions like (2+2) are lazy-evaluated.

> 
> So what is 2+(2[0]) or (2+2)[0] supposed to mean?
> 
> >>> a = classad.ExprTree('2+2')
> >>> a[0]
> 2 + 2[0]
> 
> Is the issue that + is lazy, and so a+b is also lazy?
> 

Yup, more-or-less.  "a+b" is an operand expression; as it's not list or literal, it is lazy-evaluated.  Of course, (2+2)[0] is not a very useful expression (as it evaluates to Error)!

I think the proposed semantics (subscript operator always evaluates) is the most "pythonic" way to proceed.

>>> import classad
>>> classad.ExprTree("2+2")[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: ClassAd expression is unsubscriptable.
>>> classad.ExprTree("{1,2,3}")[0]
1L
>>> classad.ExprTree('"ABC"')[0]
'A'
>>> def listAdd(a, b): return a+b
... 
>>> classad.register(listAdd)
>>> classad.ExprTree("listAdd({1,2,3}, {4,5,6})")[1]
2L

Brian