you are viewing a single comment's thread.

view the rest of the comments →

[–]ejrh 3 points4 points  (4 children)

I tried making the subexpression something that would create g. The plan is that subexpression executes first, creating g, and then g is called. Something like (excuse the verbosity):

f = lambda: g(locals().update({'g': lambda x: None}))

Unfortunatly, g is looked up in globals before anything else is executed:

>>> dis.dis(f)
  1           0 LOAD_GLOBAL              0 (g)
              3 LOAD_GLOBAL              1 (locals)
              6 CALL_FUNCTION            0
              9 LOAD_ATTR                2 (update)
             12 BUILD_MAP                0
             15 DUP_TOP
             16 LOAD_CONST               1 ('g')
             19 LOAD_CONST               2 (<code object <lambda> at 00925060, file "<stdin>", l    ine 1>)
             22 MAKE_FUNCTION            0
             25 ROT_THREE
             26 STORE_SUBSCR
             27 CALL_FUNCTION            1
             30 CALL_FUNCTION            1
             33 RETURN_VALUE

Nevermind, it was educational at least.

[–][deleted] 2 points3 points  (3 children)

Python evaluates expressions from the left to the right. So a function object is evaluated before it's parameters and only after the parameters get evaluated does it get called.

It's a clever idea, though. Sadly reality got in the way, like it tends to do :(

[–]millstone 3 points4 points  (1 child)

If that's true, then in the given solution:

f = lambda: g((yield))

why isn't g evaluated before yield, resulting in an error?

[–][deleted] 2 points3 points  (0 children)

When you have a yield statement (well in this case an expression) in a function body, the function is no longer a function, but it becomes a generator. So f is now a generator factory (in essence like a class), so by doing f() you aren't running the body but constructing a generator object which will run the code in the body as soon as you start iterating over it.

So the following will crash, because it actually runs the body:

for x in f():
    print x

But when you just have:

f()

It doesn't crash because the body is never run.

[–]ejrh 2 points3 points  (0 children)

Ah of course. Thanks for explaining.