views:

68

answers:

3

I'm trying to define variable inside function. vars() shows variable is created, but gives me NameError: exception. What am I doing wrong?

def a(str1):
    vars() [str1] =  1
    print vars()
    print b


a('b')

output:

{'str1': 'b', 'b': 1}

exception:

NameError: global name 'b' is not defined
+2  A: 

Your code works for me. Perhaps you should try an alternative approach:

exec(str1 + '=1')

This will execute b=1

orangeoctopus
strange, i tried on mac py 2.6.4 and on linux py 2.5.4, doesn't work..
damir
exec() inside a function scope will work within that function local scope.
msw
+1  A: 

If you don't understand why a construct doesn't work, neither will the next person who has to read your code. If you mean

b = 1   

you should say that. In this case vars() gives you access to the function local dictionary so your code is equivalent to

def a():
   b = 1

where b is local to a and evaporates when it goes out of scope upon exit from a.

premature optimization is the root of many people's attempt to second-guess Python

from itertools import izip
import timeit

import msw.wordlist

def zip_list(p):
    """construct a dictionary of length 100 from a list of strings"""
    return dict(zip(p[:100], p[100:]))

def izip_list(p):
    """as zip_list but avoids creating a new list to feed to dict()"""
    return dict(izip(p[:100], p[100:]))

def pass_list(p):
    """take 100 elements of a list and do nothing"""
    for i in p[:100]:
        pass

def exec_pass_list(p):
    """exec() a no-op 100 times"""
    for i in xrange(100):
        exec('pass')


# returns a list of 64'000 unique lowercase dictionary words for tests
words = msw.wordlist.Wordlist()
words.shuffle()
words = words[:200]
print 'words', words[:5], '...'

for func in ['zip_list', 'izip_list', 'pass_list', 'exec_pass_list']:
    t = timeit.Timer('%s(words)' % func,
            'from __main__ import words, %s' % func)
    print func, t.repeat(number=10**5)

which yields:

words ['concatenated', 'predicament', 'shtick', 'imagine', 'stationing'] ...
zip_list [1.8603439331054688, 1.8597819805145264, 1.8571949005126953]
izip_list [1.5500969886779785, 1.5501470565795898, 1.5536530017852783]
pass_list [0.26778006553649902, 0.26837801933288574, 0.26767921447753906]
exec_pass_list [74.459679126739502, 75.221366882324219, 77.538936853408813]

I didn't bother trying implement whatever the OP was trying to do because being 50 times slower to not construct a dictionary sort makes further testing kinda stupid.

msw
I think the point is he wants the variable name to be dynamic.
orangeoctopus
And I explicitly didn't answer that implied aspect of the question, because a hand-out solution to someone who can't even articulate the question will likely not be well used. Yes, that is a pedagogic stance, but SO is about pedagogy.
msw
ok this is supposed to be as fast as it can be, so instead of making dictionary of 100 predefined keys:values i just generate var from string. That's why.
damir
@damir: measure it then, you'll find that the `exec` approach is probably the slowest of all your possible alternatives.
msw
@damir: I'm pretty sure you aren't going to be "as fast as it can be".
msw
thats why I started coding some parts in C and using ctypes :)
damir
Because it takes 15 microseconds to create a hundred pair dictionary in pure Python? Yeah, I'm kind of impatient like that, too. Don't worry though, your ctypes code will probably be free of defects the first time.
msw
+4  A: 

You're invoking undefined behaviour. From the documentation of vars():

Note The returned dictionary should not be modified: the effects on the corresponding symbol table are undefined.

Other answers give possible solutions.

Thomas