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

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*)

Related

Python: cache a local function variable for subsequent calls

In C/C++, a function can declare a local variable as static. When doing so, the value remains in memory and is available to subsequent calls to the function (this variable is no longer local, but that's besides the point).
Is there a way to do something similar in Python, without having to declare any global variable outside of the function?
Use case: a function that (among other things) uses a regex to extract a value from an input string. I want to pre-compile the pattern (re.compile()), without having to declare the variable outside of the function scope.
I can inject a variable directly into globals():
globals()['my_pattern'] = re.compile(...)
But it doesn't look like a good idea.
You could use a function attribute. In Python, functions are first-class objects, so you can abuse of this feature to simulate a static variable:
import re
def find_some_pattern(b):
if getattr(find_some_pattern, 'a', None) is None:
find_some_pattern.a = re.compile(r'^[A-Z]+\_(\d{1,2})$')
m = find_some_pattern.a.match(b)
if m is not None:
return m.groups()[0]
return 'NO MATCH'
Now, you ca try it:
try:
print(find_some_pattern.a)
except AttributeError:
print('No attribute a yet!')
for s in ('AAAA_1', 'aaa_1', 'BBBB_3', 'BB_333'):
print(find_some_pattern(s))
print(find_some_pattern.a)
This is the output:
No attribute a yet!
initialize a!
1
NO MATCH
3
NO MATCH
re.compile('^[A-Z]+\\_(\\d{1,2})$')
It is not the best approach (wrappers or callables are way more elegant, and I suggest you use one of them), but I thought this clearly explains the meaning of:
In Python, functions are first-class objects.

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

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.

python beginner craps: global name not defined - naming variables [duplicate]

Suppose I have a function like:
def foo():
x = 'hello world'
How do I get the function to return x, in such a way that I can use it as the input for another function or use the variable within the body of a program? I tried using return and then using the x variable in another function, but I get a NameError that way.
For the specific case of communicating information between methods in the same class, it is often best to store the information in self. See Passing variables between methods in Python? for details.
def foo():
x = 'hello world'
return x # return 'hello world' would do, too
foo()
print(x) # NameError - x is not defined outside the function
y = foo()
print(y) # this works
x = foo()
print(x) # this also works, and it's a completely different x than that inside
# foo()
z = bar(x) # of course, now you can use x as you want
z = bar(foo()) # but you don't have to
Effectively, there are two ways: directly and indirectly.
The direct way is to return a value from the function, as you tried, and let the calling code use that value. This is normally what you want. The natural, simple, direct, explicit way to get information back from a function is to return it. Broadly speaking, the purpose of a function is to compute a value, and return signifies "this is the value we computed; we are done here".
Directly using return
The main trick here is that return returns a value, not a variable. So return x does not enable the calling code to use x after calling the function, and does not modify any existing value that x had in the context of the call. (That's presumably why you got a NameError.)
After we use return in the function:
def example():
x = 'hello world'
return x
we need to write the calling code to use the return value:
result = example()
print(result)
The other key point here is that a call to a function is an expression, so we can use it the same way that we use, say, the result of an addition. Just as we may say result = 'hello ' + 'world', we may say result = foo(). After that, result is our own, local name for that string, and we can do whatever we want with it.
We can use the same name, x, if we want. Or we can use a different name. The calling code doesn't have to know anything about how the function is written, or what names it uses for things.1
We can use the value directly to call another function: for example, print(foo()).2 We can return the value directly: simply return 'hello world', without assigning to x. (Again: we are returning a value, not a variable.)
The function can only return once each time it is called. return terminates the function - again, we just determined the result of the calculation, so there is no reason to calculate any further. If we want to return multiple pieces of information, therefore, we will need to come up with a single object (in Python, "value" and "object" are effectively synonyms; this doesn't work out so well for some other languages.)
We can make a tuple right on the return line; or we can use a dictionary, a namedtuple (Python 2.6+), a types.simpleNamespace (Python 3.3+), a dataclass (Python 3.7+), or some other class (perhaps even one we write ourselves) to associate names with the values that are being returned; or we can accumulate values from a loop in a list; etc. etc. The possibilities are endless..
On the other hand, the function returns whether you like it or not (unless an exception is raised). If it reaches the end, it will implicitly return the special value None. You may or may not want to do it explicitly instead.
Indirect methods
Other than returning the result back to the caller directly, we can communicate it by modifying some existing object that the caller knows about. There are many ways to do that, but they're all variations on that same theme.
If you want the code to communicate information back this way, please just let it return None - don't also use the return value for something meaningful. That's how the built-in functionality works.
In order to modify that object, the called function also has to know about it, of course. That means, having a name for the object that can be looked up in a current scope. So, let's go through those in order:
Local scope: Modifying a passed-in argument
If one of our parameters is mutable, we can just mutate it, and rely on the caller to examine the change. This is usually not a great idea, because it can be hard to reason about the code. It looks like:
def called(mutable):
mutable.append('world')
def caller():
my_value = ['hello'] # a list with just that string
called(my_value)
# now it contains both strings
If the value is an instance of our own class, we could also assign to an attribute:
class Test:
def __init__(self, value):
self.value = value
def called(mutable):
mutable.value = 'world'
def caller():
test = Test('hello')
called(test)
# now test.value has changed
Assigning to an attribute does not work for built-in types, including object; and it might not work for some classes that explicitly prevent you from doing it.
Local scope: Modifying self, in a method
We already have an example of this above: setting self.value in the Test.__init__ code. This is a special case of modifying a passed-in argument; but it's part of how classes work in Python, and something we're expected to do. Normally, when we do this, the calling won't actually check for changes to self - it will just use the modified object in the next step of the logic. That's what makes it appropriate to write code this way: we're still presenting an interface, so the caller doesn't have to worry about the details.
class Example:
def __init__(self):
self._words = ['hello']
def add_word(self):
self._words.append('world')
def display(self):
print(*self.words)
x = Example()
x.add_word()
x.display()
In the example, calling add_word gave information back to the top-level code - but instead of looking for it, we just go ahead and call display.3
See also: Passing variables between methods in Python?
Enclosing scope
This is a rare special case when using nested functions. There isn't a lot to say here - it works the same way as with the global scope, just using the nonlocal keyword rather than global.4
Global scope: Modifying a global
Generally speaking, it is a bad idea to change anything in the global scope after setting it up in the first place. It makes code harder to reason about, because anything that uses that global (aside from whatever was responsible for the change) now has a "hidden" source of input.
If you still want to do it, the syntax is straightforward:
words = ['hello']
def add_global_word():
words.append('world')
add_global_word() # `words` is changed
Global scope: Assigning to a new or existing global
This is actually a special case of modifying a global. I don't mean that assignment is a kind of modification (it isn't). I mean that when you assign a global name, Python automatically updates a dict that represents the global namespace. You can get that dict with globals(), and you can modify that dict and it will actually impact what global variables exist. (I.e., the return from globals() is the dictionary itself, not a copy.)5
But please don't. That's even worse of an idea than the previous one. If you really need to get the result from your function by assigning to a global variable, use the global keyword to tell Python that the name should be looked up in the global scope:
words = ['hello']
def replace_global_words():
global words
words = ['hello', 'world']
replace_global_words() # `words` is a new list with both words
Global scope: Assigning to or modifying an attribute of the function itself
This is a rare special case, but now that you've seen the other examples, the theory should be clear. In Python, functions are mutable (i.e. you can set attributes on them); and if we define a function at top level, it's in the global namespace. So this is really just modifying a global:
def set_own_words():
set_own_words.words = ['hello', 'world']
set_own_words()
print(*set_own_words.words)
We shouldn't really use this to send information to the caller. It has all the usual problems with globals, and it's even harder to understand. But it can be useful to set a function's attributes from within the function, in order for the function to remember something in between calls. (It's similar to how methods remember things in between calls by modifying self.) The functools standard library does this, for example in the cache implementation.
Builtin scope
This doesn't work. The builtin namespace doesn't contain any mutable objects, and you can't assign new builtin names (they'll go into the global namespace instead).
Some approaches that don't work in Python
Just calculating something before the function ends
In some other programming languages, there is some kind of hidden variable that automatically picks up the result of the last calculation, every time something is calculated; and if you reach the end of a function without returning anything, it gets returned. That doesn't work in Python. If you reach the end without returning anything, your function returns None.
Assigning to the function's name
In some other programming languages, you are allowed (or expected) to assign to a variable with the same name as the function; and at the end of the function, that value is returned. That still doesn't work in Python. If you reach the end without returning anything, your function still returns None.
def broken():
broken = 1
broken()
print(broken + 1) # causes a `TypeError`
It might seem like you can at least use the value that way, if you use the global keyword:
def subtly_broken():
global subtly_broken
subtly_broken = 1
subtly_broken()
print(subtly_broken + 1) # 2
But this, of course, is just a special case of assigning to a global. And there's a big problem with it - the same name can't refer to two things at once. By doing this, the function replaced its own name. So it will fail next time:
def subtly_broken():
global subtly_broken
subtly_broken = 1
subtly_broken()
subtly_broken() # causes a `TypeError`
Assigning to a parameter
Sometimes people expect to be able to assign to one of the function's parameters, and have it affect a variable that was used for the corresponding argument. However, this does not work:
def broken(words):
words = ['hello', 'world']
data = ['hello']
broken(data) # `data` does not change
Just like how Python returns values, not variables, it also passes values, not variables. words is a local name; by definition the calling code doesn't know anything about that namespace.
One of the working methods that we saw is to modify the passed-in list. That works because if the list itself changes, then it changes - it doesn't matter what name is used for it, or what part of the code uses that name. However, assigning a new list to words does not cause the existing list to change. It just makes words start being a name for a different list.
For more information, see How do I pass a variable by reference?.
1 At least, not for getting the value back. If you want to use keyword arguments, you need to know what the keyword names are. But generally, the point of functions is that they're an abstraction; you only need to know about their interface, and you don't need to think about what they're doing internally.
2 In 2.x, print is a statement rather than a function, so this doesn't make an example of calling another function directly. However, print foo() still works with 2.x's print statement, and so does print(foo()) (in this case, the extra parentheses are just ordinary grouping parentheses). Aside from that, 2.7 (the last 2.x version) has been unsupported since the beginning of 2020 - which was nearly a 5 year extension of the normal schedule. But then, this question was originally asked in 2010.
3Again: if the purpose of a method is to update the object, don't also return a value. Some people like to return self so that you can "chain" method calls; but in Python this is considered poor style. If you want that kind of "fluent" interface, then instead of writing methods that update self, write methods that create a new, modified instance of the class.
4 Except, of course, that if we're modifying a value rather than assigning, we don't need either keyword.
5 There's also a locals() that gives you a dict of local variables. However, this cannot be used to make new local variables - the behaviour is undefined in 2.x, and in 3.x the dict is created on the fly and assigning to it has no effect. Some of Python's optimizations depend on the local variables for a function being known ahead of time.
>>> def foo():
return 'hello world'
>>> x = foo()
>>> x
'hello world'
You can use global statement and then achieve what you want without returning value from
the function. For example you can do something like below:
def foo():
global x
x = "hello world"
foo()
print x
The above code will print "hello world".
But please be warned that usage of "global" is not a good idea at all and it is better to avoid usage that is shown in my example.
Also check this related discussion on about usage of global statement in Python.

Adding variables "by name" to local namespace

I know that I can add a variable to the global namespace "by name" with something like:
def getNewVar(name,val):
globals()[name]=val
The things is, I would like to do this in a local namespace. I have already tried and failed in using locals() instead of globals(). Someone probably wants to know why I would do something like this. OK, in my use case, the argument to the function is actually a dictionary, and I would like to do something like:
def processDictEntries(dict):
for varname in dict.keys():
locals()[varname]=dict[varname] # won't work, of course
This way, further down in the function, I won't have to keep typing
result1=dict['var1']+5.
result2=dict['var2']*dict['var7']
over and over again. I can just type
result1=var1+5
result2=var2*var7
And, if there is a way to do this in a small loop like I have written, then I don't have to do:
var1=dict['var1']
var2=dict['var2'] etc.
either. I'm really just looking for economy of code; it's a big dictionary.
BTW, the entries of the dictionary are never altered; it is strictly input. And, yes, I know that if the input dictionary lacks one of the variables the function needs, I will be in touble, but I think that can be dealt with. Thanks!
If you can change how you call the function:
def processDictEntries(var1=None,var2=None,**kwargs):
#do stuff with var1,var2 ...
And then call the function as:
processDictEntries(**dict)
and of course, if you can't do that, you can always use processDictEntries as a wrapper:
def _processDictEntries(var1=None,var2=None,**kwargs):
...
def processDictEntries(d):
return _processDictEntries(**d)
As a side note, it's not a good idea to name a variable dict as then you shadow the builtin function

How do I create a function that will create a global (and assign it a value) with a name that contains the name of the argument given to it?

I'm using Python and am trying to create a function that will look at the name of the object that is given as an argument and (among other things) create some globals that contain this name,
for example:
object1=someclass(args,kwds) #the object is an instance of a class that is given a certain name (e.g.object1)
def somefunc(some_argument):
global tau_some_argument
global ron_some_argument #e.t.c. for other variables (I also would like to assign some variables etc)
tau_some_argument=some_value1
ron_some_argument=some_value2
print ron_some_argument
print tau_some_argument
now what I want to happen if I call this function is as follows:
when I call
somefunc(object1)
I would like it to create some globals named tau_object1, ron_object1 and assign them values (the print statements are irrelevant), similarly if i called
somefunc(object2)
where object2 is another instance of a class I would like it to create globals: tau_object2, ron_object2, at the moment the function simply creates globals named tau_some_argument (as is obvious from the code).
Now I read somewhere that the names of python objects are immutable, unless they are a class or function so I don't know how to do this, from reading I get the feeling that I may need to use meta-classes but this feels like it's an overly complicated way of doing something that should be relatively easy.
Thanks in advance.
It sounds like a terrible idea...
def func(prefix):
g = globals()
g[prefix + '_tomato'] = 123
g[prefix + '_broccoli'] = 456
Whatever you are doing, it can probably be done with dictionaries, arrays, and other objects in a way that isn't fragile like the above method.
I'm not so sure about python but can't you just declare a global array and simply create the object indexed by the name of the object as a string?
tau_some_argument['object1'] = some_value1
ron_some_argument['object1'] = some_value2

Categories

Resources