What does list[:] = process_list(list) does in python? [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between list and list[:] in python?
I am quite new in python so I bumped into a situation where I was unable to find a response for the following question.
What does this means in python?
l[:] = process_list(l)
l is type list
Basically I have a global declared list that I want to modify it(override the old values with the new ones) based on the response of the process_list method. When I try like this:
l = process_list(l)
I get this: Unresolved reference 'l'
Can you please explain what is the difference and if the first approach that I am using currently is a good one?

In a function, an assignment to a name that could be a local variable creates a local variable by that name, even if it shadows a global:
a = None
def foo():
a = 5 # local 'a' shadows global 'a'
Slice assignment is modification, not assignment, so the name continues to refer to the global:
a = [1, 2, 3]
def foo():
a[:] = [5] # modifies global 'a'
The Unresolved reference happens because by creating a local variable shadowing the global, the global can no longer be seen. Another way to do what you want could be to use global:
a = None
def foo():
global a
a = 5 # rebinds global 'a'

list[:] = whatever will change the contents of the existing list
(as opposed to replacing it with list = whatever) ... by the way list is a terrible variable name ...

Related

Use a dictionary to refer to a global variable inside a function (Python)

I'm using a dictionary to refer to a global variable in Python inside a function. I want to use the function to update the global variable. (In reality my global variables are more complicated than this.)
global_variable_A=5
global_variable_B=1
dictionary={'A':global_variable_A,'B':global_variable_B}
def f(x,glob):
global global_variable_A
dictionary[glob]+=x
f(2,'A')
print(global_variable_A)
This returns 5 rather than 7. I understand why, is there anyway to let Python know that I mean the variable dictionary[glob] to refer to the global rather than the local variable, while still referring to the variable through a dictionary?
Thanks for your time, and apologies if I've missed something completely obvious.
When you assign a value to a name name = 5, you're creating a reference to 5 that you can use the identifier name to access. Normally, if you then have some code with a narrower scope, you can either use that reference
def f():
print(name)
or create a local reference using the same identifier, potentially to an unrelated value
def g():
name = 100
print(name)
The global keyword allows you to instead manipulate the identifier as if you weren;t in the more narrow scope, allowing you to reassign the global name to a different reference:
def h():
global name
name = 100
h()
print(name) # 100
However, when you use a reference to create another reference, there isn't any relation ship between those two references. So
name = 5
l = [name]
leaves us with two references to the value 5: one from the identifier name, and one from the first position of l. Crucially, those two references are not related; we can change one without changing the other.
name = 6
print(l) # [5]
One way to accomplish what you want is to use a boxed type. That means that you create an object that points to another object. All of your references can then point to the first object (the box) and you can freely change what it points to (the thing "inside" the box), by only updating a single reference:
class Box:
def __init__(self, value):
self.value = value
box = Box(5)
l = [box]
box.value = 10
print(l[0].value) # 10
If you think you need to do this, there's a design flaw in your code. I really wouldn't recommend doing this.
global_a = 5
def add_to_global(key, value):
globals()[key] += value
add_to_global("global_a", 2)
print(global_a)
Output:
7

Can access a list declared within a function inside another function withing the first function, but not a variable without using global attribute

Class 'Test' contains function 'test_variables'.
Functions 'update_d' and 'update_a' are declared within 'test_variables()'.
Variable 'index' is initialized to 0 in 'test_variables'
List A [1,2] is initialized in 'test_variables'
'update_d' and 'update_a' updates 'index' and prints it.
I can access elements of list A without using the global attribute,
but to access 'index' I have declared'global index' within 'update_d' and 'update_a'.
Why can I not access the variable index without global but can access a list?
index=0
class Test():
def test_variables():
def update_d():
global index
index=index+1+A[0]
print(index)
def update_a():
global index
index=index+1+A[1]
print(index)
index=0
A=[1,2]
update_d()
update_a()
test_variables()
In Python, the global keyword is only needed when you are writing to a variable. Inside test_variable() you have defined a NEW variable named index, though it seems your intent was to write to the variable defined outside that scope.
When you read from a variable name, Python starts in the innermost scope and if the name isn't found, continues looking in the containing scopes.
When you write to a variable name, Python only looks locally and creates a new variable if one of that name isn't found. The global keyword tells Python that the local scope should reference that name globally on assignment.
For this reason, global variables work best as constants, and variables you need to change should probably be passed in to a function as a parameter and the new value returned.
The list A (in addition to update_a and update_b) is defined within Test, while index is not.
It's not correct way of using classes.
Code:
class Test:
A = (1, 2)
def __init__(self, index):
self.index = index
def update_d(self):
self.index += 1 + self.A[0]
print(self.index)
def update_a(self):
self.index += 1 + self.A[1]
print(self.index)
def test_variables(self):
self.update_d()
self.update_a()
idx = 0
tst = Test(idx)
tst.test_variables()
Provided code does same as yours but with correct usage of classes.

Self variable changes when the variable it's assigned to changes [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
I created the class Sorter which sets the variable self.list in the __init__ equal to a given argument. I then created a function selectionSort which should copy the value of self.list into a new variable unsortedList. That worked out, but when I then change unsortedList, the self.list variable changes as well.
Here's my code:
class Sorter:
def __init__(self, list):
self.list = list
def selectionSort(self):
unsortedList = self.list
sortedList = []
indexSmallest = 0
while len(unsortedList)>0:
for i in range(len(unsortedList)):
if unsortedList[i] <= unsortedList[indexSmallest]:
indexSmallest = i
sortedList.append(unsortedList[indexSmallest])
unsortedList.pop(indexSmallest)
indexSmallest = 0
return sortedList
sorter = Sorter([2,6,1,8,5])
print(sorter.selectionSort())
I expect self.list to be the same as before calling the selectionSort() function but the result I get is an empty self.list variable.
Use either:
#1
unsortedList = self.list.copy()
Or
#2
unsortedList = self.list[:]
Or
#3
import copy
unsortedList = copy.deepcopy(self.list)
Explanation:
When you do an assignment via =, it really is referring to the same list just that now that list has 2 different names.
To circumvent this, use #1 or #2 methods -> you would require the .copy() inbuilt function or using [:].
As for #3, this is used when shallow copying isn't enough because you might have mutable objects within the list itself.
For a greater understanding on copy vs deepcopy, visit and read here
What's happening is that when you set unsortedList = self.list, Python doesn't want to copy all the values over, because that could be expensive. Instead, it just makes both variables point to the same region of memory, so when you change one it changes the other.
To make a copy, you can do unsortedList = self.list[:]
EDIT see this thread for more information.

What are the meanings and differences between "uses" and "rebinds" a variable?

From Python in a Nutshell:
Eschew global
Never use global if the function body just uses a global
variable (including mutating the object bound to that
variable, when the object is mutable).
Use a global statement only if
the function body rebinds a global variable (generally by assigning to the variable’s name).
What are the meanings and differences between "uses" and "rebinds" a variable?
Is "mutating the object bound to a variable" "uses" or "rebinds" the variable? Why?
"Mutate" and "bind"/"rebind" are two mutually exclusive operations. Mutating changes an object, whereas binding changes a name.
This is binding:
a = []
This is mutating:
a.append(None)
"Using" means accessing the existing object bound to a name, whether for reading or for mutation.
Using a variable
When you use a variable, you are using the actually value of the variable - the object to which it refers - or mutating the object that the variable name refers to. Here is an example:
>>> var1 = 1
>>> var2 = [1]
>>>
>>> def func():
print(var1)
var2.append(2)
>>> func()
1
>>> var2
[1, 2]
>>>
In the above example, we are using var1 and var2 inside of func. We use var1 because we use it's value in our call to print. And we used var2 because we mutated the object it referred to. Notice we didn't change the object to which var2 referred, we used the already existing object and modified it. Also notice that we never tried to assign a new value to either variable.
Rebinding a variable
When you rebind a variable, you are changing the object to which the variable name refers. Here is another example to help illustrate the point:
>>> var1 = 1
>>>
>>> def func():
global var1
var1 = 2
>>> func()
>>> var1
2
>>>
In the above examples. We are rebinding var inside of func. var1 use to have a reference to the object 1, but because we rebinding var1 to 2, it now refers to the object 2.
So what's the difference?
The difference is that when we use a variable, we are simply using the object to which the variable already refers. When we rebind a variable, we change the object to which the variable refers.

Python and closed variables [duplicate]

This question already has answers here:
nonlocal keyword in Python 2.x
(10 answers)
Closed 6 months ago.
Have a look at this code:
def closure():
value = False
def method_1():
value = True
def method_2():
print 'value is:', value
method_1()
method_2()
closure()
I would expect it to print 'Value is: True' but it doesn't. Why is this and what is the solution?
This happens because method_1 gets its own local scope where it can declare variables. Python sees value = True and thinks you're creating a new variable named value, local to method_1.
The reason Python does this is to avoid polluting the outer scope's locals with variables from an inner function. (You wouldn't want assignments in regular, module-level functions to result in global variables being created!)
If you don't assign to value, then Python searches the outer scopes looking for the variable (so reading the variable works as expected, as demonstrated by your method_2).
One way to get around this is by using a mutable object instead of assigment:
result = { 'value': False }
def method_1():
result['value'] = True
In Python 3, the nonlocal statement (see also docs) was added for exactly this scenario:
def method_1():
nonlocal value
value = True # Works as expected -- assigns to `value` from outer scope
In method_1, Python assumes (quite sensibly!) that value is a local variable. Whenever you assign to a variable name inside a function, it is assumed that that variable name is a new local variable. If you want it to be global, then you have to declare it as global, and if you want it to be "nonlocal", in Python 3, you can declare it nonlocal, but in Python 2, you have to do something uglier: store the value in a container. That avoids having to reassign the variable name, and so avoids the scoping ambiguity.
def method_1_global():
global value
value = True
def method_1_nonlocal_P3():
nonlocal value
value = True
value = [False]
def method_1_nonlocal_P2():
value[0] = True
When you assign to a variable, it assumes the variable is of local scope. So the value in method_1 is not the value in closure.
If you want this to work on Python 3, add a line to method_1: nonlocal value.
On Python 2,
def closure():
value = [False]
def method_1():
value[0] = True
def method_2():
print 'value is:', value
method_1()
method_2()
closure()
is one possible work-around.
This is because you are not actually modified the closed-over variable - you are masking it with a new one that has the same name. In python 2.x there is no easy way around this, which is why the nonlocal keyword was added in python 3.
This can be worked around, however, using mutable types like list and dictionary. There is a good example in this answer.
To avoid this, you can use a list.
value = [False]
def method_1():
value[0] = True
What Python does now is searching in higher levels of the scope as value is not available in the local variables. As value is a list and Python refernces it as a global variable relative to *method_1*, you can treat value as it is, a list.

Categories

Resources