Using arguments as variable names: Why does it solve this problem? - python

I'm going through some material about functions and I'm writing Python code to make some sense of the pseudocode examples.
The goal is printing the variables after I call the function, then check the new values.
def my_sum(x, y, z):
z = x + y
return x, y, z
A = 1
B = 2
C = 0
my_sum(A, B, C)
my_sum(B, C, A)
my_sum(C, A, B)
my_sum(A, B, C)
my_sum(B, C, A)
print(A, B, C)
My first instinct was to write this procedural approach, but when I do the calling the program won't give the right answer, because A, B and C aren't saving whatever is happening inside the function. So A is always 1, B is 2 and so forth
It turns out when I assign the calling with the arguments, the variables A, B and C receive the new values and they're now keeping it. Finally it prints 21, 8, 13, which is the answer.
A, B, C = my_sum(A, B, C)
B, C, A = my_sum(B, C, A)
C, A, B = my_sum(C, A, B)
A, B, C = my_sum(A, B, C)
B, C, A = my_sum(B, C, A)
How would you implement it or what are the other ways of writing this algorithm?
The thing is I can't wrap my head around why this works at all! It was just a random guess that happened to solve my problem.

python don't have pass by reference option, only pass by value, so your construction is correct, because you returning NEW values (in tuple form), not changing value of variables, that you are passing in.

In Python, an assignment made to a parameter name never affects the value of the name that the caller uses. They are separate names that initially reference the same object, but once the parameter name is assigned something else (like a sum), it references a different object.
Your second attempt works because the function returns a tuple with the values of the three paramater names and your main program unpacks that tuple back into its own names.
However, since the function doesn't need the original value of the third argument, and it doesn't touch the first two arguments, the caller doesn't really need to pass the third argument, and doesn't need to update its own names for the first two arguments... So the function could be designed to only take two arguments and return the new value:
def my_sum(x, y):
return x + y
A = 1
B = 2
C = my_sum(A, B)
A = my_sum(B, C)
B = my_sum(C, A)
C = my_sum(A, B)
A = my_sum(B, C)

Lets start with your function definition and one call.
def my_sum(x, y, z):
z = x + y
return x, y, z
A = 1
B = 2
C = 0
my_sum(A, B, C)
Without the function, this is functionally the same as:
A = 1
B = 2
C = 0
x = A
y = B
z = C
z = x + y
_ = x, y, z
# x, y, and z are discarded since you don't do anything with the return value
You shouldn't expect this to change A, B, or C or if you do you have a misconception about how python variables or names work.
Python variables or names are just a dict with a name pointing to a value.
A = 1
B = 2
C = 0
my_sum(A, B, C)
# this is a very condensed version of what python does in the background
dict_of_globals = dict()
dict_of_globals['A'] = 1
dict_of_globals['B'] = 2
dict_of_globals['C'] = 3
my_sum_local_dict = dict()
my_sum_local_dict['x'] = dict_of_globals['A']
my_sum_local_dict['y'] = dict_of_globals['B']
my_sum_local_dict['z'] = dict_of_globals['C']
# and so on..
Since you only ever assign 1 to dict_of_globals['A'], it would be unreasonable to expect it to be anything other than 1.
The reason this works:
A, B, C = my_sum(A, B, C)
is because you are assigning the return value back to A.
A = x # etc..
# or:
dict_of_globals['A'] = my_sum_local_dict['x']

Related

How to use one output of a function and store a second one=

So I have a function which outputs 2 values:
def example(a, b):
c = math.floor(a / b)
a = a%b
return (c, a)
I want to use this function this way:
print("text: ", c)
How can I use the function and print c, but store x for later?
Your function will return a tuple containing the two values. You can assign the result of calling your function to a variable.
Note,
that the parentheses are not required in your return statement.
you can replace math.floor(a / b) with a // b which will also do a floor division.
An example is shown below where the result of calling the function is unpacked into two variables, c and a.
def example(a, b):
c = a // b
a = a % b
return c, a
c, a = example(6, 3)
print("text:", c)
Alternatively, you can also store the result in a single variable that references your tuple as follows:
data = example(6, 3)
print("text:", data[0])
First, you need to call the function and assign its return values to some variables:
x, y = example(42, 5)
Then you can print the results:
print(x)
print(y)
You can even skip the variable assignment if you wish so
print("text:", example(a, b)[0])
but it's ugly

How do I do multiple things inside one lambda function?

I am learning Python and I want to do multiple things inside one lambda function.
Just for a small example if I want to do addition, subtraction, and multiplication in one function, how do I do that?
I tried to use code like this just to see if it would work and it didn't:
a = 1
b = 2
myFunction = lambda a, b: a + b, b - a, a * b
print(myFunction(a, b))
You can group those operations in a tuple
a = 1
b = 2
myFunction = lambda a, b: (a + b, b - a, a * b)
myFunction(a, b)
output:
(3, 1, 2)
NB. The mistake in you code is that myFunction was a tuple containing your lambda as first element, not a function.
I think there is a slight syntax issue around a lambda returning a tuple.
Use this syntax:
a = 1
b = 2
myFunction = lambda a, b: (a + b, b - a, a * b)
print(myFunction(a, b))

How to set default value for multiple inputs from one line in python

I'm trying to get specifications three necessary inputs and a fourth optional one from one input in Python.
a, b, c, d = input("Please enter the number of the figure you would like and the x y coordinated in that order and a colour if you choose.").split()
I want d to be optional with a set default value but I'm really struggling with it.
# get input
inp = input("Please enter the number of the figure you would like and the x y coordinated in that order and a colour if you choose.").split()
# check how many parameters are passed
if len(input) == 3:
# value for d is not passed
a, b, c = inp
d = default_value
else:
# value for d is passed
a, b, c, d = inp
The best you can do is:
answers = input("...").split()
if len(answers) < 4:
answers.append( default_value_for_4 )
If you really really feel the need to have them called a, b, c, d, then just do:
a, b, c, d = answers
You can use this:
a, b, c, d, *_ = (input("...") + " <default value>").split()
This will assign d to <default value> if there are only 3 inputs.
If there are 4 inputs then d will be assigned to the fourth value, and the value of the variable _ will be <default value> (which is a Python convention to discard a value).
You can use the following code
a , b , *c = input("Please enter the number of the figure you would like and the x y coordinated in that order and a colour if you choose.").split()
If there are multiple inputs, all will get saved in c which you can further process and assign it to variable d

assign increasing integer values to a list of variables without having to count the number of variables

I have some old code, that implements following pattern.
It declares n constants within the class, which have values from 0 to n-1.
class FSM:
ST_INITIAL, ST_FIRST, ST_SECOND = range(3)
def __init__(...):
self.state = self.ST_INITIAL
def step(self):
if self.STATE == self.ST_INITIAL:
blabla
elif self.state == self.ST_FIRST:
blabla
Now if there are many values (if n is a large number it is no fun having to count how many variables one wants to declare in order to fill in the right value of n into the range() function)
What I wanted to know is whether there is any feature in any of the newer python versions (> 2.7), that allows to write something like:
a, b, c, d = xxxxxxx #
without having to count, that a, b, c, d is a list of identifiers with 4 values and being forced to add the 4 on the right hand side of the expression.
a, b, c, d = range(4) # the 4 on the right hand side of the expression is
# what I want to get rid of.
It's not nice, but you could do the following:
a, b, c, d, *tmp = range(100) # large enough to cover all possibilites
del tmp # tmp is just a buffer that takes all the unwanted numbers
Re your comment: This
tmp = range(100)
a, b, c, d, *tmp = tmp
i, j, k, l, m, *tmp = tmp
print(a, b, c, d)
print(i, j, k, l, m)
leads to
0 1 2 3
4 5 6 7 8
Or did I misunderstand your comment?
One also ugly solution might be:
To transform:
class FSM:
ST_INITIAL, ST_FIRST, ST_SECOND = range(3)
def __init__(...):
into:
class FSM:
STATE_NAMES = ("ST_INITIAL", "ST_FIRST", "ST_SECOND")
def __init__(...):
for ctr, name in enumerate(FSM.STATE_NAMES):
setattr(FSM, name, ctr)

Python syntax clarification

Scrolling through the python 2.7 docs I came across this snippet
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while b < n:
print a,
a, b = b, a+b
But I don't understand the last line, and unsure of how I would google for it.
How should I read a, b = b, a+b, or, what does it mean ?
Python evaluates the right-hand side of assignments first. It evaluates
b, a+b
from left to right. It then assigns the values to the variables a and b respectively.
So a, b = b, a+b is equivalent to
c = b
d = a+b
a = c
b = d
except that it achieves the result without explicit temporary variables.
See the docs on Python's evaluation order.
There is a subtle point here worth examining with an example. Suppose a = 1, b = 2.
a, b = b, a+b
is equivalent to
a, b = 2, 1+2
a, b = 2, 3
So a gets assign to 2, b is assigned to 3.
Notice that this is not equivalent to
a = b
b = a + b
Since the first line would assign
a = 2
b = 2 + 2 = 4
Notice that done this (wrong) way, b ends up equal to 4, not 3. That's why it is important to know that Python evaluates the right-hand side of assignments first (before any assignments are made).
It is setting a to b, and b to a + b, without needing an intermediate variable. It could also be accomplished with:
temp = a
a = b
b = temp + b

Categories