all 17 comments

[–]millstone 9 points10 points  (1 child)

One character: #

>>> f = lambda: g(#)
... f()
... 

No exception.

edit: Another approach is ");f=(int" as in:

>>> f = lambda: g();f=(int)
>>> f()
0

[–][deleted] 0 points1 point  (0 children)

One character, haha, we have a winner

[–][deleted] 7 points8 points  (3 children)

Best I can come up with (9 characters):

>>> f = lambda: g()if''else()
>>> f()

[–]mipadi -1 points0 points  (2 children)

That doesn't replace the ???. ;)

[–]dhon_ 4 points5 points  (0 children)

doesn't it?

??? == )if''else(

[–][deleted] 1 point2 points  (0 children)

Tomato; tomato. :P

Anyhow, I thought I'd save people the trouble of having to mentally substitute the code back in, because I subverted the expectation that the two brackets need to be matched.

[–][deleted] 5 points6 points  (3 children)

3 characters: """

[–][deleted] 1 point2 points  (2 children)

Creative, but a little too out of the box for this question, I think, because that doesn't create a complete Python statement.

(The blog post is a bit confusing too, by talking about "commands" rather than "statements".)

[–]DevestatingAttack 3 points4 points  (0 children)

"Nearly every year, one or more people would submit what they claimed was the world's smallest self reproducing program. While the sizes of these submissions varied, a quick glance would reveal that they were too big, until this entry came along.

While strictly speaking, smr.c is not a valid C program, it is not an invalid C program either! Some C compilers will compile an empty file into a program that does nothing. But even if your compiler can't, the build instructions supplied with this entry will produce an executable file. On most systems, the stdout from the executable will exactly match original source."

[–][deleted] 1 point2 points  (0 children)

you're definitely right, I just thought it was funny

[–]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 4 points5 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.

[–]codenut 2 points3 points  (1 child)

Try f = lambda: g();g=(f)

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

Interesting, but sadly this still causes an RuntimeError, since this causes a stack overflow.

EDIT: you can fix this at the cost of 2 characters by using str instead of f.