What's the difference between locals() and globals() - python

I don't understand what's wrong with in this code.
Please let me know how I write to solve this problem.
I'd thought that this might had been good, but it caused the error.
>>> def L():
... for i in range(3):
... locals()["str" + str(i)] = 1
... print str0
...
>>> L()
If I execute it, the following error happened.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in a
NameError: global name 'str0' is not defined
However, if I use globals(), the error didn't happen(like the following)
>>> def G():
... for i in range(3):
... globals()["str" + str(i)] = 1
... print str0
...
>>> G()
1
But!!! If I don't use for statement, I can write like this and works well.
>>> def LL():
... locals()["str" + str(0)] = 1
... print str0
...
>>> LL()
1
I want to get the result by using variables set in the method after the above code was executed.
>>> str0
1
>>> str1
1
>>> str2
1

From the documentation of locals()
Note:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.

Related

Python AST exec "... is not defined" error on recursive function

I came across this error
def test_rec():
import ast
exec(compile(ast.fix_missing_locations(ast.parse("""
def fact(n):
return 1 if n == 0 else n * fact(n - 1)
print(fact(5))
"""), "<string>", "exec")))
This yield this error, which is weird
Traceback (most recent call last):
File "/Users/gecko/.pyenv/versions/3.9.0/envs/lampy/lib/python3.9/site-packages/nose/case.py", line 198, in runTest
self.test(*self.arg)
File "/Users/gecko/code/lampycode/tests/test_let_lang.py", line 6, in test_rec
exec(compile(ast.fix_missing_locations(ast.parse("""
File "<string>", line 4, in <module>
File "<string>", line 3, in fact
NameError: name 'fact' is not defined
If I copy and paste the same code in REPL it works fine
>>> def fact(n):
... return 1 if n == 0 else n * fact(n - 1)
...
>>> print(fact(5))
120
>>>
Any ideas?
I could reduce the problem further here is the minimal exempla, this would overflow the stack but it gives me the same not defined error
def test_rec3():
exec("""
def f():
f()
f()
""")
--
Second edit, going even further, this only happens inside functions
This works
exec("""
def f(n):
print("end") if n == 1 else f(n-1)
f(10)""")
But this gives me the same error as above
def foo():
exec("""
def f(n):
print("end") if n == 1 else f(n-1)
f(10)""")
foo()
If you use exec with the default locals, then binding local variables is undefined behavior. That includes def, which binds the new function to a local variable.
Also, functions defined inside exec can't access closure variables, which fact would be.
The best way to avoid these problems is to not use exec. The second best way is to provide an explicit namespace:
namespace = {}
exec(whatever, namespace)

How does del interact with object attributes? [duplicate]

This question already has answers here:
What does "del" do exactly?
(1 answer)
Variable scopes in Python classes
(4 answers)
Closed 5 years ago.
I'm new to Python and saw this code snippet:
class C:
abc = 2
c1 = C()
print c1.abc
c1.abc = 3
print c1.abc
del c1.abc
print c1.abc
I understand why the first and the second print statements print 2, respectively 3. Coming from a Java background however, I don't understand what happens in the line 'del c1.abc' and why the last print statement prints 2 and not some kind of an error. Can someone explain? If possible by comparing to Java?
The sticky issue to a Python beginner here is that abc is a class variable (i.e. a "static" variable), and when you do c1.abc = 3, you shadow the class variable with an instance variable. When you do del c1.abc the del applies to the instance variable, so calling c1.abc now returns the class variable.
The following interactive session should clear some things up:
>>> class C:
... abc = 2
...
>>> c1 = C()
>>> c2 = C()
>>> c1.abc = 3
>>> c1.abc
3
>>> c2.abc
2
>>> C.abc # class "static" variable
2
>>> del c1.abc
>>> c1.abc
2
>>> c2.abc
2
>>> C.abc
2
>>> del c2.abc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: C instance has no attribute 'abc'
>>> del C.abc
>>> c1.abc
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: C instance has no attribute 'abc'
>>>
It is del.<someattribute> always deletes the instance attribute. It won't delete a class-level attribute if applied to an instance, instead, you have to apply it to the class!
In Python, everything written inside a class block is always at the class level. In this sense, it is simpler than Java. To define an instance variable, you need to assign directly to an instance, outisde a method (c1.abc = 3) or inside a method, using the first parameter passed to that method (by convention this is called self but could be banana if you wanted):
>>> class C:
... def some_method(banana, x): # by convention you should use `self` instead of `banana`
... banana.x = x
...
>>> c = C()
>>> c.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: C instance has no attribute 'x'
>>> c.some_method(5)
>>> c.x
5

difference between F(x) and F x in Python

In Python it is possible to call either del x or del (x) . I know how to define a function called F(x) , but I do not know how to define a function that cal be called like del, without a tuple as parameters.
What is the difference between F x and F(x), and how can I define a function that can be called without parenthesis ?
>>> a = 10
>>> a
10
>>> del a <------------ can be called without parenthesis
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> a = 1
>>> del (a)
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> def f(x): 1
...
>>> f (10)
>>> print f (10)
None
>>> def f(x): return 1
...
>>> print f (10)
1
>>> f 1 <------ cannot be called so
File "<stdin>", line 1
f 1
^
SyntaxError: invalid syntax
>>>
The main reason is that del is actually a statement and therefore has special behavior in Python. Therefore you cannot actually define these (and this behavior) yourself* - it is a built-in part of the language for a set of reserved keywords.
**I guess you could potentially edit the source of Python itself and build your own in, but I don't think that is what you're after :)*

forgetting to declare variables

If inside a loop, is it possible to instantiate objects to be manipulated during subsequent iterations of the loop, and still available when the scope of the loop has been left?
Here is a simple example of what I thought might work:
>>> for i in range(2):
... r = [] if r is None else r
... r.append[i]
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'r' is not defined
And here's my second attempt using a NameError exception:
>>> for i in range(2):
... try:
... r = r
... except NameError:
... r = []
... r.append(i)
...
>>>
I suspect that what I have been trying to do is actually prohibited, but I don't understand why it would be.
Can someone throw some light on this for me please?
Edit:
So the second way works, but it's very long winded. Is there a quick way?
It's not prohibited, but it is actively discouraged. NameError should never be caught barring extreme circumstances; always bind the name outside the loop even if to None.
You can find out if the name is in your locals like this: name in locals() Regarding your question:
>>> 'r' in locals()
False
>>> for i in range(2):
if 'r' not in locals(): r = []
r.append(i)
>>> r
[0, 1]
>>>
I agree with Ignacio Vazquez-Abrams; this is not good style. Please do what you need to before looping.

Can we access inner function outside its scope of outer function in python using outer function?

Just for the sake of curiosity I wanna know this..
I know scope of inner function is limited to outer function body only, but still is there any way so that we can access the inner function variable outside its scope or call the inner function outside its scope ?
In [7]: def main():
...: def sub():
...: a=5
...: print a
...:
In [8]: main()
In [9]: main.sub()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/dubizzle/webapps/django/dubizzle/<ipython-input-9-3920726955bd> in <module>()
----> 1 main.sub()
AttributeError: 'function' object has no attribute 'sub'
In [10]:
>>> def main():
... def sub():
... a=5
... print a
...
>>> main.__code__.co_consts
(None, <code object sub at 0x2111ad0, file "<stdin>", line 2>)
>>> exec main.__code__.co_consts[1]
5
You can if you return the inner function as a value
>>> def main():
... def sub():
... a = 5
... print a
... return sub
...
>>> inner = main()
>>> inner()
5
or you can attach it to main as a property (functions are objects after all):
>>> def main():
... def sub():
... a = 5
... print a
... main.mysub = sub
...
>>> main()
>>> main.mysub()
5
but you better document your very good reason for doing this, since it will almost certainly surprise anyone reading your code :-)
No, you can't. The inner function is not an attribute of the outer function.
The inner function only exists after its def statement is executed (while the outer function is executed), and it stops to exist when the function exits.
You could return the inner function, of course.
A function is just another object in Python and can be introspected.
You can get the outer function body at runtime and parse/eval it to make the function available in the current namespace.
>>> import inspect
>>> def outer():
def inner():
print "hello!"
>>> inspect.getsourcelines(outer)
([u'def outer():\n', u' def inner():\n', u' print "hello!"\n'], 1)
Not really the same thing as calling outer.inner(), but if you are not making the inner function explicitly available outside the scope of the outer function, I guess it is the the only possibility.
For example, a very naive eval attempt could be:
>>> exec('\n'.join([ line[4:] for line in inspect.getsourcelines(outer)[0][1:] ]))
>>> inner()
hello!
An inner function is just a local variable like any other so the same rules apply. If you want to access it you have to return it.

Categories

Resources