What is the difference between dictionaries created from vars() and dict={}? - python

After reading about vars(), I am still a little confused on what it is actually doing. In looking at the Python documentation, "The vars() function returns the __ dict __ attribute of the given object if the object has __ dict __ attribute." So, it returns a dictionary object? Here are the questions I am really getting at:
1) What is vars() actually doing in the below code?
dict = {}
dict['H'] = atom
vars()[dict['H']] = 20
2) Why is the vars() necessary in front of the dictionary I created and could I leave it out? (I know the code fails if I leave it out, but what would be a different way of accomplishing the same task?)
dict = {}
dict['H'] = atom
dict['H'] = 20

What is vars() actually doing in the below code?
It does what it always does: it retrieves all local variables as a dictionary. That's how it works when calling vars without arguments.
Why is the vars() necessary in front of the dictionary I created and could I leave it out?
It seems that someone is doing shenanigans with the local scope. It's just that it is wrapped with dict['H'] which is just some variable (possibly atom is a string). In other words he's trying to retrieve a variable by dynamic name. For example
>>> test = 15
>>> x = 'test'
>>> vars()[x]
15
This should be avoided at all costs. Forget you even know about the existance of vars(). I do not know a single case when you have to use vars() instead of a dict or some other "normal" (and in this context safe) structure. The code you are looking at is insanely difficult to maintain, error prone and has serious security issues.

1) What is vars() doing in the below code
Honestly, it's hard to tell. vars() (without an argument) returns the local namespace as a dictionary. In other words, it does the same thing as locals(). In your code, you then look up a name (dict['H']) in the locals dict and set an item in there. Setting an item in the dict returned by locals() does nothing if you are in a function... If you are in the global namespace, it adds an attribute.
2) Why is the vars() necessary in front of the dictionary I created and could I leave it out?
It probably isn't necessary and you probably should leave it out. Normally dynamically setting attributes on the global namespace is a really bad idea. You should generally pass around a dictionary of the data that you need instead. In other words, you can do:
v = 'foo'
globals()[v] = 'bar'
# ...
value = globals()[v] # 'bar'
But you shouldn't. It's much better to just pass a dictionary around:
v = 'foo'
dct = {v: 'bar'}
# ...
value = dct[v]

First, you shouldn't overwrite __builtin__ functions. dict is a reserved name for a function used to create dictionary objects.
Second, var gives you access to name declarations within the current running scope.

Related

Is it considered 'defined behavior' to add a new key value pair to the globals() dictionary in python?

If I do this in python 3.8.3:
globals()['any_new_variable_name'] = 'any_value_or_object_here'
print(any_new_variable_name)
It works like assignment.
Is this considered 'defined' behavior? Is variable assignment simply in a sense syntactic sugar for adding keys to the dictionary object we can access with globals()?
Yes, it is. Globals is a special dictionary in python that stores all the created global variables. But don't use this way to assign a value to a variable! It is a bad code practice. Use traditional method instead:
variable = "value"

Python3: Cannot change variables of locals() dictionary inside a function

Seems like when I pass a variable into a function, I can change it in the globals() dict but not in the locals() dict. Is there a reason for this? So this code
def test(a, dim):
locals()['dim'] = a
print(locals()['dim'])
globals()['dim'] = a
print(globals()['dim'])
dim = 1
test(4,dim)
gives me
4
1
I'd be very curious to hear why it is how it is and whether you know a way to change locals() variables inside a function.
According to the documentation, the locals() dictionary cannot be used to modify variables.
https://docs.python.org/3/library/functions.html#locals
The contents of this dictionary should not be modified; changes may
not affect the values of local and free variables used by the
interpreter.
You can edit the globals() dictionary, but this is considered nonstandard.

Why in some Python built-in functions we using variables like string

For example
class c:
var = 15
getattr(c, 'var')
or
i = 0
globals()['i'] = 25
why here our variable writing like string type.
I saw this in some built-in functions and in Django and i think this make code much difficulty for understanding isn't it?
globals() returns a dictionary, so you have to use the variable name as string for looking at it. In globals()['var'], 'var' is just a key in globals() returned dict, so it must be given as string.
getattr(c, 'var') looks for attribute "var" in c.__dict__.
Remember: Python makes a heavy us of dicts.
If you know the variable names beforehand, and they are constant, then you can do both these things in a different way:
getattr(c, 'var')
This is a shorthand for:
try:
return c.var
except AttributeError:
if have_default: # hand-wavey "more to this" for a later lesson
return default
raise
and
globals()['i'] = 25
is a nasty way of doing
global i
i = 25
The method you've given is essentially reaching into the internals and fiddling around with them. using the global keyword is the better way to declare that you are use a variable in the global scope, because when the function is interpreted python knows that the variable is from a different scope at that point.
However if you don't know the name of the variable beforehand, then you'd be forced to do it the way in your examples. (but please, please think twice before using the globals one. Putting arbitrary variables in a module's global namespace at runtime? *shudders*)

Python: Using vars() to assign a string to a variable

I find it very useful to be able to create new variables during runtime and create a dictionary of the results for processing later, i.e. writing to a file:
myDict = {}
for i in range (1,10):
temp = "variable"+str(i)
vars()[temp] = myFunctionThatReturnsData() # variable1= data1, variable2 = data2,etc.
myDict[temp] = vars(temp)
which creates the dictionary entry [result1:data1] which i can call with myDict[result1]. I have been using vars() without really understanding what I'm doing. I take it vars() returns a dictionary with the local variables(?), and
vars()[x] = y
creates a new dictionary entry of [x:y] ?
I have a script where I pass in a dictionary prepared with {input1:data1,input2:data2}, and i use this method to iterate through all the values, store all the results, and output it to a file. This bit of code is inside a function within a class, and is working.
My source of confusion is that I have read various posts on how locals() shouldn't be messed with, and how vars() is equivalent(?) to locals(), or globals()..
So my question is (at least) two-fold:
1.What exactly does vars(),or in particular, vars()[x] = y do,
2.What the scope of this dictionary is (what I need to keep in mind as I write bigger programs
3.Whether this is good programming practice.
Thanks in advance!
The pythonic way to create a sequence of variables
If you want a sequence of variables, create a sequence. Instead of trying to create independent variables like:
variable0
variable1
variable2
variable3
You should look at creating a list. This is similar to what S.Lott is suggesting (S.Lott usually has good advice), but maps more neatly onto your for loop:
sequence = []
for _ in xrange(10):
sequence.append(function_that_returns_data())
(Notice that we discard the loop variable (_). We're just trying to get 10 passes.)
Then your data will be available as:
sequence[0]
sequence[1]
sequence[2]
sequence[3]
[...]
sequence[9]
As an added bonus, you can do:
for datum in sequence:
process_data(datum)
At first, you may twitch at having your sequence start at 0. You can go through various contortions to have your actual data start at 1, but it's more pain than it's worth. I recommend just getting used to having zero-based lists. Everything is built around them, and they start to feel natural pretty quickly.
vars() and locals()
Now, to answer another part of your question. vars() (or locals()) provides low level access to variables created by python. Thus the following two lines are equivalent.
locals()['x'] = 4
x = 4
The scope of vars()['x'] is exactly the same as the scope of x. One problem with locals() (or vars()) is that it will let you put stuff in the namespace that you can't get out of the namespace by normal means. So you can do something like this: locals()[4] = 'An integer', but you can't get that back out without using locals again, because the local namespace (as with all python namespaces) is only meant to hold strings.
>>> x = 5
>>> dir()
['__builtins__', '__doc__', '__name__', 'x']
>>> locals()[4] = 'An integer'
>>> dir()
[4, '__builtins__', '__doc__', '__name__', 'x']
>>> x
5
>>> 4
4
>>> locals()[4]
'An integer'
Note that 4 does not return the same thing as locals()[4]. This can lead to some unexpected, difficult to debug problems. This is one reason to avoid using locals(). Another is that it's generally a lot of complication just to do things that python provides simpler, less error prone ways of doing (like creating a sequence of variables).
Do this instead. It's simpler.
myDict = {}
for i in range (1,10):
temp = "variable"+str(i)
myDict[temp] = myFunctionThatReturnsData() # variable1= data1, variable2 = data2,etc.
That's all you ever need to do.
The results will be myDict['variable1'] through myDict['variable9']
You rarely need vars() or locals(). Just stop using them and use ordinary variables and ordinary dictionaries. Try to avoid things you don't understand and stick to the simple, obvious stuff.
From the help for vars,
vars(...)
vars([object]) -> dictionary
Without arguments, equivalent to locals().
With an argument, equivalent to object.__dict__.
You are using it without vars, so let's look at the help for locals()
locals(...)
locals() -> dictionary
Update and return a dictionary containing the current scope's local
variables.
So this answers you first two questions. vars() returns a dictionary to the local variables that is indexed by the name of the variable as a string. The scope is local.
I'm not sure about the third question, but it does seem like kind of a hack which isn't a good sign. I guess if you're careful about using this only in the correct scope you can get by with it.
jcdyer explains the concepts very well and Justin Peel clearly states what vars() and locals() do. But a small example always speeds up understanding.
class Bull(object):
def __init__(self):
self.x = 1
self.y = "this"
def __repr__(self):
return "Bull()"
def test1(self):
z = 5
return vars()
def test2(self):
y = "that"
return vars(self)
def test3(self):
return locals()
def test4(self):
y = 1
return locals()
if __name__ == "__main__":
b = Bull()
print b.test1()
print b.test2()
print b.test3()
print b.test4()
print vars(b).get("y")
Which results in:
{'self': Bull(), 'z': 5}
{'y': 'this', 'x': 1}
{'self': Bull()}
{'y': 1, 'self': Bull()}
this
I can answer number 3: this isn't good programming practice. I don't exactly see what you are trying to accomplish, but I am sure there is a more elegant way of doing it without using locals() (which is the same as vars() according to help(vars) in the interactive Python shell).
Using vars / locals or globals in this way is (a) poor practice and (b) doesn't work in all cases. See Dynamically set local variable for more details. Bottom line: just use dicts -- that's what they're for.
I also search for this answer at many places. The best one I see so far is:
var_list = ["Var_Name{}".format(i) for i in range(1,100)]

How to maintain lists and dictionaries between function calls in Python?

I have a function. Inside that I'm maintainfing a dictionary of values.
I want that dictionary to be maintained between different function calls
Suppose the dic is :
a = {'a':1,'b':2,'c':3}
At first call,say,I changed a[a] to 100
Dict becomes a = {'a':100,'b':2,'c':3}
At another call,i changed a[b] to 200
I want that dic to be a = {'a':100,'b':200,'c':3}
But in my code a[a] doesn't remain 100.It changes to initial value 1.
I need an answer ASAP....I m already late...Please help me friends...
You might be talking about a callable object.
class MyFunction( object ):
def __init__( self ):
self.rememberThis= dict()
def __call__( self, arg1, arg2 ):
# do something
rememberThis['a'] = arg1
return someValue
myFunction= MyFunction()
From then on, use myFunction as a simple function. You can access the rememberThis dictionary using myFunction.rememberThis.
You could use a static variable:
def foo(k, v):
foo.a[k] = v
foo.a = {'a': 1, 'b': 2, 'c': 3}
foo('a', 100)
foo('b', 200)
print foo.a
Rather than forcing globals on the code base (that can be the decision of the caller) I prefer the idea of keeping the state related to an instance of the function. A class is good for this but doesn't communicate well what you are trying to accomplish and can be a bit verbose. Taking advantage of closures is, in my opinion, a lot cleaner.
def function_the_world_sees():
a = {'a':1,'b':2,'c':3}
def actual_function(arg0, arg1):
a[arg0] = arg1
return a
return actual_function
stateful_function = function_the_world_sees()
stateful_function("b", 100)
stateful_function("b", 200)
The main caution to keep in mind is that when you make assignments in "actual_function", they occur within "actual_function". This means you can't reassign a to a different variable. The work arounds I use are to put all of my variables I plan to reassign into either into a single element list per variable or a dictionary.
If 'a' is being created inside the function. It is going out of scope. Simply create it outside the function(and before the function is called). By doing this the list/hash will not be deleted after the program leaves the function.
a = {'a':1,'b':2,'c':3}
# call you funciton here
This question doesn't have an elegant answer, in my opinion. The options are callable objects, default values, and attribute hacks. Callable objects are the right answer, but they bring in a lot of structure for what would be a single "static" declaration in another language. Default values are a minor change to the code, but it's kludgy and can be confusing to a new python programmer looking at your code. I don't like them because their existence isn't hidden from anyone who might be looking at your API.
I generally go with an attribute hack. My preferred method is:
def myfunct():
if not hasattr(myfunct, 'state'): myfunct.state = list()
# access myfunct.state in the body however you want
This keeps the declaration of the state in the first line of the function where it belongs, as well as keeping myfunct as a function. The downside is you do the attribute check every time you call the function. This is almost certainly not going to be a bottleneck in most code.
You can 'cheat' using Python's behavior for default arguments. Default arguments are only evaluated once; they get reused for every call of the function.
>>> def testFunction(persistent_dict={'a': 0}):
... persistent_dict['a'] += 1
... print persistent_dict['a']
...
>>> testFunction()
1
>>> testFunction()
2
This isn't the most elegant solution; if someone calls the function and passes in a parameter it will override the default, which probably isn't what you want.
If you just want a quick and dirty way to get the results, that will work. If you're doing something more complicated it might be better to factor it out into a class like S. Lott mentioned.
EDIT: Renamed the dictionary so it wouldn't hide the builtin dict as per the comment below.
Personally, I like the idea of the global statement. It doesn't introduce a global variable but states that a local identifier actually refers to one in the global namespace.
d = dict()
l = list()
def foo(bar, baz):
global d
global l
l.append(bar, baz)
d[bar] = baz
In python 3.0 there is also a "nonlocal" statement.

Categories

Resources