I have
def func1(var):
if var == 0:
return
else
var = var - 1
func1(var)
PROPOSAL = 1
def func2():
func1(PROPOSAL)
print(PROPOSAL)
In the recursive calls in func1, will the variable PROPOSAL be decremented, meaning the print statement will print 0?
Edit: I should've asked, why doesn't it do this?
No, the PROPOSAL global variable will not be decremented by your code. This isn't really because of scope, but because of how Python passes arguments.
When you call a function that takes an argument, the value of the argument you pass is bound to a parameter name, just like an assignment to a variable. If the value is mutable, an in-place modification through one name will be visible through the other name, but if the variable is immutable (as ints are in Python), you'll never see a change to one variable effect another.
Here's an example that shows functions and regular assignment working the same way:
x = 1
y = x # binds the y to the same value as x
y += 1 # modify y (which will rebind it, since integers are immutable)
print(x, y) # prints "1 2"
def func(z): # z is a local variable in func
z += 1
print(x, z)
func(x) # also prints "1 2", for exactly the same reasons as the code above
X = [1]
Y = X # again, binds Y to the same list as X
Y.append(2) # this time, we modify the list in place (without rebinding)
print(X, Y) # prints "[1, 2] [1, 2]", since both names still refer to the same list
def FUNC(Z):
Z.append(3):
print(X, Z)
FUNC(X) # prints "[1, 2, 3] [1, 2, 3]"
Of course, rebinding a variable that referred to a mutable value will also cause the change not to be reflected in other references to the original value. For instance, you replaced the append() calls in the second part of the code with Y = Y + [2] and Z = Z + [3], the original X list would not be changed, since those assignment statements rebind Y and Z rather than modifying the original values in place.
The "augmented assignment" operators like +=, -=, and *= are a bit tricky. They will first try to do an in-place modification if the value on the left side supports it (and many mutable types do). If the value doesn't support in-place modification of that kind (for instance, because it's an immutable object, or because the specific operator is not allowed), it will fall back on using the regular + operator to create a new value instead (if that fails too it will raise an exception).
func1(PROPOSAL) will return NONE and it won't affect the global PROPOSAL variable because you don't assign that return value to PROPOSAL.
func2() just calls func1() and then prints the PROPOSAL variable that wasn't changed it that scope just in func1(PROPOSAL)
Related
I am learning the basic usage of python,and I'm confusing about how the variable runs in a practice question. Here are the code below:
x = 1
def change(a):
a = x + 1
print(x)
change(x)
x = 1
def change(a)
x = x + 1
print(x)
change(x)
This is how I think the process:
in the first code:change(x) means: x = x + 1 - print (x) - output:2
but in fact the result is 1.So the real process is: x(symbol in the function) = x(global variable) + 1, print(x), this x is the global variable.
is that right?
in the second code,I think still the output should be 2,but it shows me that UnboundLocalError: local variable 'x' referenced before assignment
so in the python,we can't use function to change the global variable?
Inside a function, you can read global variables but you cannot modify them without explicitly declaring them as global like this:
x = 1
def change(a):
global x # <- this is required since you're assigning a new value to x
x = x + 1
print(x)
change(x)
In the first case, with a = x + 1, the global declaration is not required since you're only reading the value of x, not modifying it. Also, the output is 1 in the first case, since you're printing x not a.
The function must return a list consisting of the numbers greater than the second number in the function
It must be able to do the following when functioning:
returnGreater([1,2,3,4,5], 3)
[4,5]
returnGreater([-8,2,-4,1,3,-5],3)
[]
Here's what I have (I've gone through a few iterations), though I get a Type Error for trying to use a ">" symbol between an int and list:
def returnGreater (x,y):
"x:list(int) , return:list(int)"
#greater: int
greater = []
for y in x:
#x: int
if x > y:
x = greater
return greater
You're using the name y for two different things in your code. It's both an argument (the number to compare against) and the loop variable. You should use a different name for one of those.
I'd strongly suggest picking meaningful names, as that will make it much clearer what each variable means, as well as making it much less likely you'll use the same name for two different things. For instance, here's how I'd name the variables (getting rid of both x and y):
def returnGreater(list_of_numbers, threshold):
greater = []
for item in list_of_numbers:
if item > threshold:
greater.append(item)
return greater
You had another issue with the line x = greater, which didn't do anything useful (it replaced the reference to the original list with a reference to the empty greater list. You should be appending the item you just compared to the greater list instead.
I recommend filter. Easy and Graceful way.
def returnGreater(x, y):
return list(filter(lambda a:a>y, x))
It means, filter each element a in list x using lambda whether a is greater than y or not.
List Comprehensions
def returnGreater(_list, value):
return [x for x in _list if x > value]
So here is the problem I am having. I am trying to iterate the makeAThing class, and then create a list for the iteration using the makeAList class. Instead of making seperate lists for each iteration of makeAThing, it is making one big global list and adding the different values to it. Is there something I am missing/don't know yet, or is this just how python behaves?
class ListMaker(object):
def __init__(self,bigList = []):
self.bigList = bigList
class makeAThing(object):
def __init__(self,name = 0, aList = []):
self.name = name
self.aList = aList
def makeAList(self):
self.aList = ListMaker()
k = []
x = 0
while x < 3:
k.append(makeAThing())
k[x].name = x
k[x].makeAList()
k[x].aList.bigList.append(x)
x += 1
for e in k:
print(e.name, e.aList.bigList)
output:
0 [0, 1, 2]
1 [0, 1, 2]
2 [0, 1, 2]
the output I am trying to achieve:
0 [0]
1 [1]
2 [2]
After which I want to be able to edit the individual lists and keep them assigned to their iterations
Your init functions are using mutable default arguments.
From the Python documentation:
Default parameter values are evaluated from left to right when the
function definition is executed. This means that the expression is
evaluated once, when the function is defined, and that the same
“pre-computed” value is used for each call. This is especially
important to understand when a default parameter is a mutable object,
such as a list or a dictionary: if the function modifies the object
(e.g. by appending an item to a list), the default value is in effect
modified. This is generally not what was intended. A way around this
is to use None as the default, and explicitly test for it in the body
of the function, e.g.:
def whats_on_the_telly(penguin=None):
if penguin is None:
penguin = []
penguin.append("property of the zoo")
return penguin
In your code, the default argument bigList = [] is evaluated once - when the function is defined - the empty list is created once. Every time the function is called, the same list is used - even though it is no longer empty.
The default argument aList = [] has the same problem, but you immediately overwrite self.aList with a call to makeAList, so it doesn't cause any problems.
To verify this with your code, try the following after your code executes:
print(k[0].aList.bigList is k[1].aList.bigList)
The objects are the same.
There are instances where this behavior can be useful (Memoization comes to mind - although there are other/better ways of doing that). Generally, avoid mutable default arguments. The empty string is fine (and frequently used) because strings are immutable. For lists, dictionaries and the sort, you'll have to add a bit of logic inside the function.
I have a list of numbers t. I want to multiply the numbers in the list with 10. Why does this not work?:
for i in t
i = i*10
Why do I have to do this?:
for i in range(len(t)):
t[i] = t[i]*10
Well, it doesn't work because that's no the correct syntax. You could, however, clean things up a bit with a list comprehension:
t = [x * 10 for x in t]
It doesn't work that way in Python.
The index variable (your i) of the for .. in construct is just a variable. At the start of each pass through the loop, Python assigns the corresponding value from the in sequence to the loop's index variable. It's as if you had a lot of copies of the loop body, and before each copy you put an assignment statement i = t[0], i = t[1], and so on. The index variable does not remember that it was assigned from the in sequence (your t). The index variable is not an equivalent name (an "alias") for the corresponding value of the in sequence. Changing the index variable does not affect the in sequence.
python -c 't = [1, 2, 3]
for i in t:
i = 1
print t'
[1, 2, 3]
But you're not wrong to wonder whether it's an alias! Another language that is frequently compared with Python does work that way (quoting manual page "perlsyn"):
If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.
So:
perl -e '#t = (1, 2, 3); foreach $i (#t) { $i = 1; } print #t'
111
n = 3
d = {'x':n}
d['x'] += 1
print(n)
When I run it, I get
3
How do I make n = 4?
You can't do this, at least, not in any simple way.
The issue is very similar when you're just dealing with two variables bound to the same object. If you rebind one of them with an assignment, you will not see the new value through the other variable:
a = 3
b = a
a += 1 # binds a to a new integer, 4, since integers are immutable
print(b) # prints 3, not 4
One exception is if you are not binding a new value to the variable, but instead modifying a mutable object in-place. For instance, if instead of 1 you has a one-element list [1], you could replace the single value without creating a new list:
a = [3]
b = a
a[0] += 1 # doesn't rebind a, just mutates the list it points to
print(b[0]) # prints 4, since b still points to the same list as a
So, for your dictionary example you could take a similar approach and have n and your dictionary value be a list or other container object that you modify in-place.
Alternatively, you could store the variable name "n" in your dictionary and then rather than replacing it in your other code, you could use for a lookup in the globals dict:
n = 3
d = {"x": "n"} # note, the dictionary value is the string "n", not the variable n's value
globals()[d["x"]] += 1
print(n) # this actually does print 4, as you wanted
This is very awkward, of course, and only works when n is a global variable (you can't use the nominally equivalent call to locals in a function, as modifying the dictionary returned by locals doesn't change the local variables). I would not recommend this approach, but I wanted to show it can be done, if only badly.
You could use a class to contain the data values to enable additions. Basically you are creating a mutable object which acts as an integer.
It is a work around, but lets you accomplish what you want.
Note, that you probably need to override a few more Python operators to get full coverage:
class MyInt(object):
val = 0
def __init__(self,val):
self.val = val
def __iadd__(self,val):
self.val = self.val + val
def __repr__(self):
return repr(self.val)
n = MyInt(3)
print(n)
d = {'x':n}
d['x'] += 1
print(n)