10
\$\begingroup\$

Write a few lines of Python code, X, that does not reference any global variables, such that

def method():
    X
    print(a)

method()

prints 1 but

def method():
    X
    X
    print(a)

method()

prints 2.


So, I hate to be a stickler, but it seems like vars and locals are actually global variables in Python:

def test_global_1():
    global vars, locals
    vars = lambda: 2
    locals = lambda: 3

def test_global_2():
    print(vars())
    print(locals())

test_global_1()
test_global_2()

Also, it looks like people would like to see objective winning criteria for puzzles like this. Code length doesn't really feel right here so perhaps we could make a system of brownie points for various novel features of the code? I'm not sure exactly what these could be but here's a start:

  • +1 for really truly no globals (no vars or locals)
  • +1 for being the first to post a particular technique
  • +1 for the shortest solution posted
  • +1 for a solution involving only a single Python statement
  • +1 for interesting "hacks" like joining at lexical non-boundaries
  • +1 for not using exceptions

And if you can think of more you could edit this question to add to the list.

Can this problem be solved without using exceptions and without using globals like vars and locals? I suspect it can, though I haven't figured out exactly how yet...

\$\endgroup\$
11
  • \$\begingroup\$ Good puzzle! I made sure not to scroll down so I could solve it myself without seeing anyone's answers. :D \$\endgroup\$
    – mbomb007
    Jul 30, 2015 at 21:36
  • 1
    \$\begingroup\$ Thanks for the puzzles Owen, and welcome to the site. There is a rule on the site that all questions must have an objective winning condition, so you should probably add one. One possibility is shortest length of X, but there are other options. \$\endgroup\$
    – isaacg
    Jul 31, 2015 at 8:25
  • 3
    \$\begingroup\$ "all questions must have an objective winning condition" - Stupid rule imho. Who cares about a "winner" when we all actually most enjoy the puzzling and learning from the different answers. \$\endgroup\$
    – JimmyB
    Jul 31, 2015 at 11:34
  • 2
    \$\begingroup\$ Please add a code-golf or popularity-contest tag, depending on whether you want people to optimize for shortness code or for general popularity. I imagine code-golf is better for this challenge (popularity-contest is encouraged only for challenges that cannot be easily classified otherwise), but it's up to you. \$\endgroup\$
    – apsillers
    Jul 31, 2015 at 13:18
  • 2
    \$\begingroup\$ You've added a scoring system, but also added the popularity contest tag, which means that a winner is decided by votes. What do you mean here? Perhaps you want votes just as a tiebreak? \$\endgroup\$
    – xnor
    Aug 2, 2015 at 2:13

7 Answers 7

12
\$\begingroup\$
def method():
    if 'a' not in vars():a=0
    a+=1
    if 'a' not in vars():a=0
    a+=1
    print(a)

Initializes the variable a to 0 only if it's not already initialized in the variables table. Then, increments it.

More briefly (thanks to histocrat for len):

def method():
    a=len(vars())+1
    a=len(vars())+1
    print(a)

If the two copies of X could be on the same line, we could do

a=0;a+=1;a

which doubles to

a=0;a+=1;aa=0;a+=1;a

with the "sacrificial lamb" aa eating up the second variable assignment.

\$\endgroup\$
3
  • 3
    \$\begingroup\$ I don't want to be a spoilsport posting this so fast, so how about we try for shortest code? \$\endgroup\$
    – xnor
    Jul 30, 2015 at 20:03
  • 3
    \$\begingroup\$ Slightly shorter variant: a=len(vars())+1 \$\endgroup\$
    – histocrat
    Jul 30, 2015 at 20:50
  • \$\begingroup\$ @histocrat Nice one, thanks! \$\endgroup\$
    – xnor
    Jul 30, 2015 at 21:03
9
\$\begingroup\$

Python

Thought of this solution, since try and except was the first way I thought of to determine if a variable existed yet or not.

def method():
    try:a+=1
    except:a=1
    print(a)
\$\endgroup\$
5
\$\begingroup\$

Python 2

def method():
    exec'';locals()['a']=locals().get('a',0)+1
    exec'';locals()['a']=locals().get('a',0)+1
    print a

method()

Basically, when exec is encountered in Python 2, it causes a special flag (0x01) to be removed from method.func_code.co_flags, which makes locals assignments have an effect. I exploited this to implement nonlocal support in Python 2 (see line 43 for the xor that modifies the flag).

\$\endgroup\$
4
  • \$\begingroup\$ Why not a = locals().get('a', 0) + 1? \$\endgroup\$
    – Vincent
    Jul 31, 2015 at 13:15
  • \$\begingroup\$ @Vincent I was tiree. :O Fixed. \$\endgroup\$ Jul 31, 2015 at 14:15
  • \$\begingroup\$ In that case you don't need exec'' any more ;) \$\endgroup\$
    – Vincent
    Jul 31, 2015 at 14:20
  • \$\begingroup\$ @Vincent Eh, maybe I should just stick with the longer version. It felt more creative. Now it just seems a lot like a clone of the top-voted answer... :/ \$\endgroup\$ Jul 31, 2015 at 14:23
2
\$\begingroup\$

My first idea (and then smooshing it) was:

def method():
    a=2if'a'in vars()else 1 
    a=2if'a'in vars()else 1 
    print(a)

But histocrat's answer seems optimal.

\$\endgroup\$
1
\$\begingroup\$

My attempt. Uses the math module to track if X is run once or twice.

def module():
  import sys
  if 'math' in sys.modules:
    a+=1
  else:
    a=1
  import math

  import sys
  if 'math' in sys.modules:
    a+=1
  else:
    a=1
  import math

  print(a)

module()
\$\endgroup\$
0
\$\begingroup\$
def method():
    #### X-block
    try:a
    except NameError:a=1
    else:a=2
    ####
    print(a)

The try block checks if the variable a is defined.
If variable not defined,(this is only when X-block is present once) then NameError Exception is raised.
If variable is defined, (this is when X-block is present twice) then else will be entered .

\$\endgroup\$
2
  • \$\begingroup\$ Yeah, that's the solution I found by searching Google. Then I created my current solution, which is shorter. \$\endgroup\$
    – mbomb007
    Jul 30, 2015 at 21:46
  • \$\begingroup\$ @mbomb007 Yeah :P. Your way is shorter than using else \$\endgroup\$
    – Kamehameha
    Jul 30, 2015 at 21:50
0
\$\begingroup\$
def method(a=[]):  
  a.append(a)  
  print len(a)

Edited in response to comment: a is a list of empty lists of length n, where n is the number of time you've called method. Calling this method twice prints 1 then 2.

\$\endgroup\$
3
  • 7
    \$\begingroup\$ Putting a=[] as a parameter is outside the parameters for this challenge. \$\endgroup\$
    – mbomb007
    Jul 31, 2015 at 2:57
  • \$\begingroup\$ Sorry, this is my answer, and it's not very good. This is (arguably) a surprisingly non-idempotent operation in python, but there's no way to slot it into the format provided for the challenge without also making the challenge trivial. \$\endgroup\$ Jul 31, 2015 at 17:29
  • \$\begingroup\$ Also, the challenge asks to print 1 or 2, not just two different things. \$\endgroup\$
    – xnor
    Jul 31, 2015 at 22:52

Not the answer you're looking for? Browse other questions tagged or ask your own question.