Class variable in `for`...`if` expression fails in python [duplicate] - python

This question already has answers here:
Accessing class variables from a list comprehension in the class definition
(8 answers)
Closed 3 years ago.
Take this simple code:
class A(object):
numbers = [1, 2, 3]
numberscopy = numbers[:]
print(*(a for a in numberscopy))
print(*(a for a in numberscopy if a in numbers))
I define the numbers variable inside the class. I can then use it to do other things, like make a copy, iterate over it, and print its contents.
But the last line, with the for-if statement, fails with NameError: global name 'numbers' is not defined. Not numberscopy, just numbers.
I tried on both python 2.7.14+ (with print_function imported) and 3.7.0, with the same result.
Why does this happen? Is it intended to work this way?

The code inside class-bodies is somewhat messed in Python. It is not so much a bug, but an "implementation problem that got weird".
The problem being that: code usually runs at module level, or inside functions - when inside functions, there are well-defined "local" variables.
Code inside class bodies also run with a "local" scope - but if one creates functions that are run while the class body is being processed, these do not
"see" the outer-level variables. And generator expressions, as do comprehensions (in Python 3, Python 2 is another language, which is on its way out, let's not complicate stuff). The expression used to create the iterator to the for inside the generator is run in a scope where it "sees" the outer variables. The main expression and if expressions themselves are inside the generator, and can't "see" those variables.
So, a workaround, if comprehensions are needed inside a class body is to have an intermediary function inside the class body, just to generate the values and variables you need, and have line to call that and update the class's own variables with the local namespace of that inner function:
class A:
def create_vals():
numbers = [1, 2, 3]
numbers_copy = numbers[:]
values = list(a for a in numbers if a in numbers_copy)
return locals()
locals().update(create_vals())
del create_vals
So, inside the temporary create_vals function (it is not a method), usual scope-nesting rules apply - and with the last two lines we copy the created variables to the class itself, and remove the temporary function.

Related

Iterating Through a List of Functions in Python [duplicate]

This question already has answers here:
Creating a list of methods to be executed in Python
(4 answers)
Closed 4 months ago.
Let's say I have the following code:
string = "XxXxXx"
print(string.lower())
print(string.upper())
How could I use a list instead along the lines of:
string = "XxXxXx"
list = [lower(), upper()]
for i in list:
print(string.i)
Obviously the code above does not work at all and the problem I'm working on is way more complicated. But if I could make the example above work, it would really take care of my problem!
Functions (and methods) are first class objects in python. You can therefore store them in a list just like you would anything else.
If you want to be able to apply the functions to arbitrary strings, use the unbound function objects in the class:
string = "XxXxXx"
func_list = [str.lower, str.upper]
for i in func_list:
print(i(string))
If you want to only apply the functions to your special string, you can store the bound methods in a list instead:
string = "XxXxXx"
func_list = [string.lower, string.upper]
for i in func_list:
print(i())
In both cases, the () operator is what calls the function. The function name by itself is a reference to the object. In the first case, the . operator does not do anything surprising. In the second case, since you invoke it on an instance of a class, it binds the function object in the class to the instance, creating a bound method that has an implicit self argument.

Using a list comprehension and string formatting on class properties [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 10 months ago.
Here is the basic class code:
class test:
for i in range(10):
exec(f'a{i}={i+1}')
My first attempt to create the list a_all was to do the following:
exec(f'a_all=[test.ak for k in range(0,10,2)]')
However, this doesn't work as exec does not 'unstring' ak the way I want it to. Other attempts failed because the exec function returns None. I'm not even confident anymore that exec could actually work.
Your non-listcomp code works as written (kinda surprised by that), defining attributes of test, so just use that if it's what you need (it's almost certainly a bad idea, but you do you).
This doesn't work in your listcomp code because:
test doesn't exist until the class definition completes (after you dedent at the end), so test.ANYTHING doesn't work inside the definition of test (you assign to top-level names, and they become attributes of test when the class finishes being defined, but they're just scoped names without test. qualification before then)
Omitting test doesn't work in Python 3 because listcomps have their own scope in Python 3; even if you fake it out to assign to each of your names in turn, the iteration variables don't leak to outer scope on Python 3.
In any event, what you're doing is nonsensical:
Your plain for loop code works, but
It's a bad idea; just have a single class attribute of the list and have users index it as needed. There's basically never a good reason to have a programmatically generated list of numbered variable names. That's reinventing lists, badly.
So just use:
class test:
a = range(0, 10, 2) # Or list(range(0, 10, 2)) if it must be mutable
and user's can do test.a[0], test.a[3], whatever they need.
You can use setattr and getattr to set class attributes.
class test:
def __init__(self):
for i in range(10):
setattr(self, f"a{i}", i + 1)
t = test()
for i in range(10):
print(f"{t.a1=} a{i}={getattr(t, f'a{i}')=}")

Python variable inheritance not working (as expected) [duplicate]

This question already has answers here:
How to create dynamical scoped variables in Python?
(4 answers)
Closed 2 years ago.
Why, in this code, can't I access db or file from inside do_more()?
def do_stuff(queue):
db = getDbConn()
while True:
file = queue.get() #DirEntry object
...
do_more(otherObject)
q.task_done()
I'm aware I could pass db and file as arguments to do_more(), but I feel like those variables should just be available in functions called from other functions. It works that way from main to first level functions. What am I missing here?
In the code you provided, you don't even attempt using the variables from do_stuff.
But as a general rule, you should be able to use variables from a parent function inside a child function, either by passing them as variables or by using them when initializing the child function, like this:
def foo():
foo2 = "foo"
def bar():
print(foo2)
bar()
foo()
If i did not answer your question let me know.
no , you cant access those variables , I know what you think , which is wrong.
you can access variables inside loops and if statements, not here.
imagine you have a function which is used in many different places, in that case you have access from this function to many variables which makes things complicated.
functions should be stand-alone objects which take some arguments do stuff and return something.so inside a function scope you can only see variables which are defined there and the arguments passed from the parent function using parenthesis.

What is masking here [duplicate]

This question already has answers here:
masking the built-in variable with its magic behavior?
(2 answers)
Closed 6 years ago.
In the python tutorial:
In interactive mode, the last printed expression is assigned to the variable _. This means that when you are using Python as a desk calculator, it is somewhat easier to continue calculations, for example:
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06
This variable should be treated as read-only by the user. Don’t explicitly assign a value to it — you would create an independent local variable with the same name masking the built-in variable with its magic behavior.
What is masking here?
In general what is meant by masking or mask variable in python?
THanks
A variable is masked if some other variable with the same name exists, which is preferred. An example is having a global variable x. If you're in a function which also has a local variable x, then the global won't be accessible, without special measures the local variable is preferred whenever you use identifier x inside the function.
It's as if you have two kids in your classroom both called Mary, one of which is closer, and will hear your voice earlier, so always gives the quickest answer. How to give the other girl a chance?
Overwriting/reassigning a previously named identifier in a new scope
let's look at this code for example
def f():
return 3
def g():
f = 5
f()
try:
print(g())
except TypeError:
print(f())
within the scope of g, the identifier f has been reassigned from a function that returns an integer, to just an integer. so when you try calling f inside of g you should get a type error because you can't call an int. however outside of g, f is still a function that returns 3
the interpreter has its own scope so when you assign _ to another value, it forgets it's previous functionality in replace of the new value, until you restart the interpreter, or in this special case delete it with the del keyword
The _ is built-in to the interpreter, it has special meaning. It only acts like a read-only variable. When you read from it, the interpreter replaces it with the last calculated value. If you do something like
_ = 1 + 1
You are actually creating a new variable named _ in the current namespace (try running locals()function before and after creating the variable). Since there is now a variable with the same name as the interpreter built-in _ that variable is accessed first when you do subsequent reads, thus hiding the meaning of the built-in, or masking it.
You can also do what you're doing with Python built-ins as well, such as defining a function parameter namedint. In the the local function namespace, if you tried to call theint() function on a value, it would attempt to use your parameterint as a callable because there is a local variable with that name masking the built-in function int. Some IDEs will warn you when you try to do something like this because in practice it is generally a bad idea to mask the name of a built-in like that because you're eliminating the behavior of that what that symbol is intended for.
Where making comes in its if you do something like
val = 20
def do_stuff(val):
# parameter masks the value defined in outer scope
print('Value of a inside function: {}'.f format(val))
do_stuff(10) # prints 10
This assigns a variable val a value of 20, but when the function do_stuff is called it had it's own local variable namedval. Accessingval from within the function will give you the value passed in, 10 in this case, not 20 from the outer variable because thea within the function masks the one in the outer scope.

How can one create new scopes in python

In many languages (and places) there is a nice practice of creating local scopes by creating a block like this.
void foo()
{
... Do some stuff ...
if(TRUE)
{
char a;
int b;
... Do some more stuff ...
}
... Do even more stuff ...
}
How can I implement this in python without getting the unexpected indent error and without using some sort of if True: tricks
Why do you want to create new scopes in python anyway?
The normal reason for doing it in other languages is variable scoping, but that doesn't happen in python.
if True:
a = 10
print a
In Python, scoping is of three types : global, local and class. You can create specialized 'scope' dictionaries to pass to exec / eval(). In addition you can use nested scopes
(defining a function within another). I found these to be sufficient in all my code.
As Douglas Leeder said already, the main reason to use it in other languages is variable scoping and that doesn't really happen in Python. In addition, Python is the most readable language I have ever used. It would go against the grain of readability to do something like if-true tricks (Which you say you want to avoid). In that case, I think the best bet is to refactor your code into multiple functions, or use a single scope. I think that the available scopes in Python are sufficient to cover every eventuality, so local scoping shouldn't really be necessary.
If you just want to create temp variables and let them be garbage collected right after using them, you can use
del varname
when you don't want them anymore.
If its just for aesthetics, you could use comments or extra newlines, no extra indentation, though.
Python has exactly two scopes, local and global. Variables that are used in a function are in local scope no matter what indentation level they were created at. Calling a nested function will have the effect that you're looking for.
def foo():
a = 1
def bar():
b = 2
print a, b #will print "1 2"
bar()
Still like everyone else, I have to ask you why you want to create a limited scope inside a function.
variables in list comprehension (Python 3+) and generators are local:
>>> i = 0
>>> [i+1 for i in range(10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> i
0
but why exactly do you need this?
A scope is a textual region of a
Python program where a namespace is
directly accessible. “Directly
accessible” here means that an
unqualified reference to a name
attempts to find the name in the
namespace...
Please, read the documentation and clarify your question.
btw, you don't need if(TRUE){} in C, a simple {} is sufficient.
As mentioned in the other answers, there is no analogous functionality in Python to creating a new scope with a block, but when writing a script or a Jupyter Notebook, I often (ab)use classes to introduce new namespaces for similar effect. For example, in a notebook where you might have a model "Foo", "Bar" etc. and related variables you might want to create a new scope to avoid having to reuse names like
model = FooModel()
optimizer = FooOptimizer()
...
model = BarModel()
optimizer = BarOptimizer()
or suffix names like
model_foo = ...
optimizer_foo = ...
model_bar = ...
optimizer_bar= ...
Instead you can introduce new namespaces with
class Foo:
model = ...
optimizer = ...
loss = ....
class Bar:
model = ...
optimizer = ...
loss = ...
and then access the variables as
Foo.model
Bar.optimizer
...
I find that using namespaces this way to create new scopes makes code more readable and less error-prone.
While the leaking scope is indeed a feature that is often useful,
I have created a package to simulate block scoping (with selective leaking of your choice, typically to get the results out) anyway.
from scoping import scoping
a = 2
with scoping():
assert(2 == a)
a = 3
b = 4
scoping.keep('b')
assert(3 == a)
assert(2 == a)
assert(4 == b)
https://pypi.org/project/scoping/
I would see this as a clear sign that it's time to create a new function and refactor the code. I can see no reason to create a new scope like that. Any reason in mind?
def a():
def b():
pass
b()
If I just want some extra indentation or am debugging, I'll use if True:
Like so, for arbitrary name t:
### at top of function / script / outer scope (maybe just big jupyter cell)
try: t
except NameError:
class t
pass
else:
raise NameError('please `del t` first')
#### Cut here -- you only need 1x of the above -- example usage below ###
t.tempone = 5 # make new temporary variable that definitely doesn't bother anything else.
# block of calls here...
t.temptwo = 'bar' # another one...
del t.tempone # you can have overlapping scopes this way
# more calls
t.tempthree = t.temptwo; del t.temptwo # done with that now too
print(t.tempthree)
# etc, etc -- any number of variables will fit into t.
### At end of outer scope, to return `t` to being 'unused'
del t
All the above could be in a function def, or just anyplace outside defs along a script.
You can add or del new elements to an arbitrary-named class like that at any point. You really only need one of these -- then manage your 'temporary' namespace as you like.
The del t statement isn't necessary if this is in a function body, but if you include it, then you can copy/paste chunks of code far apart from each other and have them work how you expect (with different uses of 't' being entirely separate, each use starting with the that try: t... block, and ending with del t).
This way if t had been used as a variable already, you'll find out, and it doesn't clobber t so you can find out what it was.
This is less error prone then using a series of random=named functions just to call them once -- since it avoids having to deal with their names, or remembering to call them after their definition, especially if you have to reorder long code.
This basically does exactly what you want: Make a temporary place to put things you know for sure won't collide with anything else, and which you are responsible for cleaning up inside as you go.
Yes, it's ugly, and probably discouraged -- you will be directed to decompose your work into a set of smaller, more reusable functions.
As others have suggested, the python way to execute code without polluting the enclosing namespace is to put it in a class or function. This presents a slight and usually harmless problem: defining the function puts its name in the enclosing namespace. If this causes harm to you, you can name your function using Python's conventional temporary variable "_":
def _():
polluting_variable = foo()
...
_() # Run the code before something overwrites the variable.
This can be done recursively as each local definition masks the definition from the enclosing scope.
This sort of thing should only be needed in very specific circumstances. An example where it is useful is when using Databricks' %run magic, which executes the contents of another notebook in the current notebook's global scope. Wrapping the child notebook's commands in temporary functions prevents them from polluting the global namespace.

Categories