Default Parameters in Function Definition, Syntax problems. - python

I am having an issue finding a straightforward answer to a question that I have.
I am coding a program that has some default values for certain parameters that do not end up being called by the user. My program is somewhat complicated so I decided to try a simplified problem.
def mult(x = 1, y = 2, z = 3):
ans = x * y * z
print(ans)
mult()
In this quick program, the function call would result in 6. Which makes sense because it goes to the default values I provided. My question is, how can I call this function if, for example, I wanted to define y and not any other variable? What would be the correct syntax in that situation.
My intuition was to call mult(x, 5, z) to indicate default values for x and z but a new value for y. I know that does not work and would like to know what the correct syntax would be.

You can specify the parameter to supply by using = at the call site:
mult(y = 5)

you can call it with keywords
mult(y=7)
mult(z=55)
mult(z=12,y=16,x=5)
mult(x=15)
although as an aside its probably preferable to return ans instead of just printing it ...

Related

How do I fix this while loop? [duplicate]

I have noticed that it's common for beginners to have the following simple logical error. Since they genuinely don't understand the problem, a) their questions can't really be said to be caused by a typo (a full explanation would be useful); b) they lack the understanding necessary to create a proper example, explain the problem with proper terminology, and ask clearly. So, I am asking on their behalf, to make a canonical duplicate target.
Consider this code example:
x = 1
y = x + 2
for _ in range(5):
x = x * 2 # so it will be 2 the first time, then 4, then 8, then 16, then 32
print(y)
Each time through the loop, x is doubled. Since y was defined as x + 2, why doesn't it change when x changes? How can I make it so that the value is automatically updated, and I get the expected output
4
6
10
18
34
?
Declarative programming
Many beginners expect Python to work this way, but it does not. Worse, they may inconsistently expect it to work that way. Carefully consider this line from the example:
x = x * 2
If assignments were like mathematical formulas, we'd have to solve for x here. The only possible (numeric) value for x would be zero, since any other number is not equal to twice that number. And how should we account for the fact that the code previously says x = 1? Isn't that a contradiction? Should we get an error message for trying to define x two different ways? Or expect x to blow up to infinity, as the program keeps trying to double the old value of x
Of course, none of those things happen. Like most programming languages in common use, Python is a declarative language, meaning that lines of code describe actions that occur in a defined order. Where there is a loop, the code inside the loop is repeated; where there is something like if/else, some code might be skipped; but in general, code within the same "block" simply happens in the order that it's written.
In the example, first x = 1 happens, so x is equal to 1. Then y = x + 2 happens, which makes y equal to 3 for the time being. This happened because of the assignment, not because of x having a value. Thus, when x changes later on in the code, that does not cause y to change.
Going with the (control) flow
So, how do we make y change? The simplest answer is: the same way that we gave it this value in the first place - by assignment, using =. In fact, thinking about the x = x * 2 code again, we already have seen how to do this.
In the example code, we want y to change multiple times - once each time through the loop, since that is where print(y) happens. What value should be assigned? It depends on x - the current value of x at that point in the process, which is determined by using... x. Just like how x = x * 2 checks the existing value of x, doubles it, and changes x to that doubled result, so we can write y = x + 2 to check the existing value of x, add two, and change y to be that new value.
Thus:
x = 1
for _ in range(5):
x = x * 2
y = x + 2
print(y)
All that changed is that the line y = x + 2 is now inside the loop. We want that update to happen every time that x = x * 2 happens, immediately after that happens (i.e., so that the change is made in time for the print(y)). So, that directly tells us where the code needs to go.
defining relationships
Suppose there were multiple places in the program where x changes:
x = x * 2
y = x + 2
print(y)
x = 24
y = x + 2
print(y)
Eventually, it will get annoying to remember to update y after every line of code that changes x. It's also a potential source of bugs, that will get worse as the program grows.
In the original code, the idea behind writing y = x + 2 was to express a relationship between x and y: we want the code to treat y as if it meant the same thing as x + 2, anywhere that it appears. In mathematical terms, we want to treat y as a function of x.
In Python, like most other programming languages, we express the mathematical concept of a function, using something called... a function. In Python specifically, we use the def function to write functions. It looks like:
def y(z):
return z + 2
We can write whatever code we like inside the function, and when the function is "called", that code will run, much like our existing "top-level" code runs. When Python first encounters the block starting with def, though, it only creates a function from that code - it doesn't run the code yet.
So, now we have something named y, which is a function that takes in some z value and gives back (i.e., returns) the result of calculating z + 2. We can call it by writing something like y(x), which will give it our existing x value and evaluate to the result of adding 2 to that value.
Notice that the z here is the function's own name for the value was passed in, and it does not have to match our own name for that value. In fact, we don't have to have our own name for that value at all: for example, we can write y(1), and the function will compute 3.
What do we mean by "evaluating to", or "giving back", or "returning"? Simply, the code that calls the function is an expression, just like 1 + 2, and when the value is computed, it gets used in place, in the same way. So, for example, a = y(1) will make a be equal to 3:
The function receives a value 1, calling it z internally.
The function computes z + 2, i.e. 1 + 2, getting a result of 3.
The function returns the result of 3.
That means that y(1) evaluated to 3; thus, the code proceeds as if we had put 3 where the y(1) is.
Now we have the equivalent of a = 3.
For more about using functions, see How do I get a result (output) from a function? How can I use the result later?.
Going back to the beginning of this section, we can therefore use calls to y directly for our prints:
x = x * 2
print(y(x))
x = 24
print(y(x))
We don't need to "update" y when x changes; instead, we determine the value when and where it is used. Of course, we technically could have done that anyway: it only matters that y is "correct" at the points where it's actually used for something. But by using the function, the logic for the x + 2 calculation is wrapped up, given a name, and put in a single place. We don't need to write x + 2 every time. It looks trivial in this example, but y(x) would do the trick no matter how complicated the calculation is, as long as x is the only needed input. The calculation only needs to be written once: inside the function definition, and everything else just says y(x).
It's also possible to make the y function use the x value directly from our "top-level" code, rather than passing it in explicitly. This can be useful, but in the general case it gets complicated and can make code much harder to understand and prone to bugs. For a proper understanding, please read Using global variables in a function and Short description of the scoping rules?.

Issue with function definition for Write and Call Some Simple Functions [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I know you guys are not here to do my homework for me, but I just don't have enough python program knowledge to resolve the assignment. I tried, but it doesn't seems working. Can you please help me out? Below is the assignment.
Assignment instruction:
Page 1 of 3
Instructions
Examine the starter code in the code editor window and understand what it is doing.
Content of the exercise.py file is below which is in the editor window.
x = 3
y = 4
if x < y:
min_xy = x
else:
min_xy = y
print(min_xy)
a = 12.3
b = 13.7
if a < b:
min_ab = a
else:
min_ab = b
print(min_ab)
w = -3.9
z = -4.7
if w < z:
min_wz = w
else:
min_wz = z
print(min_wz)
Instructions
Now we want to write a Python function that carries out this repeated
operation, so that we can just write it once and call it repeatedly.
In the code editor, at the top of the file before the existing code,
write a function named find_min that takes two inputs and returns the
lesser of the two. Remember to use the def keyword to start the
definition of a new function, indent the body of the function under
the def line, and return the result at the end.
Start the ipython interpreter by typing ipython at the command prompt.
Run the exercise in the interpreter (%run exercise.py): you should see
some variables printed out from the starter code. Type %who to see
that the interpreter also knows about your new function find_min. Test
out your new function interactively within the interpreter, with some
input values of your choosing.
Now we want to reorganize exercise.py so that it does the same thing
as before, except more efficiently by using your new find_min
function.
Replace the appropriate blocks of code with new code that accomplishes
the same thing by calling your find_min function. Do not replace the
variables or change their values.
For example, one such operation will call find_min with the variables
x (with x having a value of 3) and y (with y having a value of 4) as
arguments and assign the returned value to the new variable min_xy.
Verify that your new code runs and produces the same results as the
original code.
My function definition is below.
def find_min(x, y):
if x < y:
return x
else:
return y
min_xy = find_min(3, 4)
print(min_xy)
I am getting the following errors:
Tests that failed:
! Call function find_min to find the lesser of x (x has a value of 3) and y (y has a value of 4) and assign returned value to min_xy
make sure x and y are defined create min_xy
! Call function find_min to find the lesser of a (a has a value of 12.3) and b (b has a value of 13.7) and assign returned value to min_ab
make sure a and b are defined create variable min_ab
! Call function find_min to find the lesser of w (w has a value of -3.9) and z (z has a value of -4.7) and assign returned value to min_wz
make sure w and z are defined create min_wz
Page 2 of 3
Instructions
The code editor should contain your find_min function. We are free to
define more than one function in our code. In the code editor, write a
second function called find_max that takes two inputs and returns the
greater of the two. Do Not Delete the Existing Code in the Code
Editor.
Use your new function to find the greater of x (x has a value of 3)
and y (y has a value of 4) and assign it to the variable max_xy.
Thanks in advance,
Marie
You need to take the call of the function out of the function definition.
def find_min(x, y):
if x < y:
return x
else:
return y
min_xy = find_min(3, 4)
print(min_xy)

Returning variables Matlab and Python?

I am trying to translate some code from Matlab to Python. The start of my function (in Matlab) starts like this:
function [varargout]=hysime(varargin);
error(nargchk(3, 4, nargin))
if nargout > 2, error('too many output parameters'); end
verbose = 1; % default value
y = varargin{1}; % 1st parameter is the data set
Later in the program there is something like this:
n = varargin{2}; % the 2nd parameter is the noise
Rn = varargin{3}; % the 3rd parameter is the noise correlation matrix
if nargin == 4, verbose = ~strcmp(lower(varargin{4}),'off');end
and finally there is this:
varargout(1) = {kf};
if nargout == 2, varargout(2) = {Ek};end
return
I am incredibly confused about what this code means. On one hand I understand that the parameters inputed all need to be returned. However, at the end of the program it appears like only 2 variables will be returned (while we input 3?). How can I translate this code so that the necessary parameters are returned? I guess my biggest issue here is that the matlab code is letting the agent input the parameters however they do not all seem required? And it seems like there cannot be more than two outputs? I am just having trouble deciphering what each line of code here means. Can someone please provide an explanation both in what is happening with the matlab code and what I can do to make the same sort of functionality in python?
Thanks!
Short version
The MATLAB code should have been written like this:
function [kf, Ek]=hysime(y, n, Rn, verbose);
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
If you know MATLAB, this should be clearer. The (mostly) corresponding Python code can be written like this:
def hysime(y, n, Rn, verbose=True):
# rest of the function here
return kf, Ek
Long Version
This function expects 3 or 4 input arguments, with a default value set if the fourth argument is not provided. However, it is done in a way that is much more complicated than it needs to be (although I see this pattern a lot). Ideally in MATLAB you would specify the same thing like this:
function [varargout]=hysime(y, n, Rn, verbose)
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
So what it is doing is putting the first argument in the variable y, the second in the variable n, the third in Rn, and if the fourth is specified put it in verbose (based on how it compares to the string 'off'), otherwise set verbose to true.
In python, handling of optional arguments is built-in. You can specify default value for arguments right in the function definition by setting name=value, where name is the argument name and value is the default value. Also, for historical reasons MATLAB often uses 'on' and 'off' instead of true and false. This is almost never done in Python, people just use True and False. So you can specify the same thing in Python like so:
def hysime(y, n, Rn, verbose=True):
This makes y, n, and Rn required arguments, but lets verbose be optional.
This doesn't handle the case where verbose is set to the string 'off'. As I said, this is common in MATLAB for historical reasons, but you really shouldn't be doing it in MATLAB anymore when you can avoid it, and you definitely shouldn't be doing it in Python. But if you really, really need to handle that case, you can just do:
def hysime(y, n, Rn, verbose=True):
if isinstance(verbose, str):
verbose = verbose.lower() != 'off'
For the output, what the MATLAB code does is let the function either return one value or two. So someone could do this:
kf = hysime(y, n, Rn);
Or
[kf, Ek] = hysime(y, n, Rn);
However, this is also being done in a way that is more complicated than necessary. If you just return the two values, and only one return value is used, MATLAB will throw away the rest. So rather than messing around with varargout, the function could just return [kf, Ek] and MATLAB will do the same thing. An error will automatically occur if someone tries to call the function with more than 2 outputs as well, so that is also unnecessary.
Dealing with varargout in this way is only necessary if you want the program to change its behavior based on the number of outputs. In this sort of structure, the main reason you would do this is if eK was expensive to calculate, in which case you would do something like this:
varargout(1) = {kf};
if nargout == 2
# calculate eK here
varargout(2) = {Ek};
end
As for the return, that is only needed in MATLAB if you want to cause the function to stop early, before it reaches the end normally. Once it reaches the end normally, it will return automatically. So if the last block of code you specified is the end of the function, then the return is redundant.
So all the code you showed in MATLAB can be reduced to:
function [kf, Ek]=hysime(y, n, Rn, verbose);
error(nargchk(3, 4, nargin))
if nargin < 4
verbose = true;
else
verbose = ~strcmpi(verbose ,'off');
end
As for Python, as I mentioned in my other answer to you, Python requires all returned values be handled. It will never throw away returned values unless you explicitly tell it to. In your case, the simplest solution is just to have return kf, Ek at the end of the function. If someone wants both kf and Ek, they can do:
kf, Ek = hysime(y, n, Rn)
If they only want kf, they can do (where _ is the python convention for a variable you don't care about):
kf, _ = hysime(y, n, Rn)
Or:
kf = hysime(y, n, Rn)[0]
So the python code would be:
def hysime(y, n, Rn, verbose=True):
# rest of the function here
return kf, Ek
If you really want to be able to have one or two returned values, you would need to have another argument to change the behavior. Such as:
def hysime(y, n, Rn, verbose=True, ret_eK=False):
# rest of the function here
return (kf, Ek) if ret_eK else kf
So in this case if the ret_eK argument is specified and set to True, then kf, Ek is returned, otherwise just kf is returned. But in Python you really don't want to do this unless there is some major additional cost to calculating Ek, which doesn't appear to be in this case.

Python Trig Functions Return Complex Numbers?

I am writing code that accepts the degree by which a motor turns and uses that data to calculate the distance covered by the wheels (using distance = no. of rotations * distance covered per rotation).
It then makes an error adjustment (taking into consideration environmental factors such as friction).
Finally, using trigonometry, it calculates the distance moved along the x-axis and y-axis.
All the above is done by the function straight contained within the class CoordinateManager. This function is called by an instance of another class.
class CoordinateManager:
goalcord = [20, 0]
def __init__(self):
self.curcord = [0, 0]
self.theta = 0
def get_compass_angle(self):
compass = Sensor(address='in2')
return compass.value(0)
def turn(self, iangle, fangle):
self.theta = self.theta + (fangle-iangle)
def straight(self, turnangle):
d = turnangle*2*3.14*2/360
d = 1.8120132*(d**0.8938054)
thetarad = radians(self.theta)
dx = d*sin(thetarad)
dy = d*cos(thetarad)
self.curcord[0] += dx
self.curcord[1] += dy
Printing both d and self.theta shows that they contain correct values.
This must mean that the array self.curcord has valid values too. However, this has not been the case. Printing the two elements of self.curcord outputs complex numbers (some big float + another big floatj).
I can think of no logical explanation for this other than that the trigonometric functions must be returning complex numbers. However, I think the chances that a python built-in lib function returns wrong values are extraordinarily slim.
Is there any logical error that I may be overlooking?
Edit: I just tried changing the last two lines to:
self.curcord[0] += dx
self.curcord[1] += dy
I just tried using .real when displaying the values. Even though the values are real now, they are still wrong. I will look further into whether this is caused by some calculation error.
Since you said in the comments above that turnangle can be any integer, the problem can be directly traced to this line:
d = 1.8120132*(d**0.8938054)
Since turnangle can be negative, the value of d before this line is executed can also be negative; a negative value raised to an arbitrary decimal power is in general complex.
Therefore the problem does not lie with the trig functions at all. The above also leads me to believe that when you said
Printing both d and self.theta shows that they contain correct values
... you only did so after this line:
d = turnangle*2*3.14*2/360
This would explain why you wrongly thought the problem must lie elsewhere.
UPDATE:
It is a very bad habit to set a variable to some function of itself like you did. Try to use a different variable name to avoid confusion - as you saw above I had to refer to "this line" rather than by their variable names.
Perhaps something like this would work, assuming that the behaviour of the motor is the same regardless of the sign of turnangle?
d = sign(d) * 1.8120132 * (abs(d) ** 0.8938054)

what's the reason for the unexpect behavior of plot()

def f(u):
value = 0.0
if u > -1 and u < 1:
value = u * u
return value
Given the above, the following produces the expected plot:
plot(f,(x,-5,5))
But plot(f(x),(x,-5,5)) just draws a horizontal line. Can anyone explain what's going on?
The former passes the function, allowing it to be called inside plot(). The latter calls the function once and passes the returned value, resulting in the same value each time.
Similar to what #Ignacio said, the cause is the function being called once. The problem with this vs other functions like sin is the conditional. The if statement is evaluated when the function is called and not preserved as a symbolic statement. That is, the u > -1 and u < 1[1] is evaluated on the first function call and result is treated accordingly (i.e. left at 0).
As an illustration of what is happening:
sage: x = var('x')
sage: print ":)" if x > 0 else ":("
:(
There is no way to get around this in general[2], because Python has to evaluate the condition in the if statement to work out which code path to take when the function is called.
Best case solution
There is a solution that should work (but doesn't yet). Sage provides Piecewise, so you can define f as:
f = Piecewise([((-5, -1), ConstantFunction(0)),
((-1, 1), x*x),
((1, 5), ConstantFunction(0))],
x)
Unfortunately, the implementation of Piecewise is as yet incomplete, and severely lacking, so the only way to plot this seems to be:
f.plot()
(Limitations: trying to call f with a variable causes errors; it doesn't work with the conventional plot; you can't restrict the domain in Piecewise.plot, it plots the whole thing (hence why I restricted it to &pm;5); it doesn't cope with infinite intervals.)
Working solution
You could also just detect whether the argument to f is a number or variable and do the appropriate action based on that:
def f(u):
try:
float(u) # see it's a number by trying to convert
return u*u if -1 < u < 1 else 0.0
except TypeError: # the conversion failed
if callable(f):
return lambda uu: f(u(uu))
else:
return f
Note the callable call, it checks to see if u is a function (in some sense), if so returns the composition of f with u.
This version allows us to do things like:
sage: f(10)
0.0
sage: f(x)(0.5)
0.25
sage: f(x+3)(-2.2)
0.64
and it also works perfectly fine with plot, in either form. (Although it warns about DeprecationWarnings because of the u(uu) syntax; there are ways to get around this using u.variables but they are fairly awkward.)
Note: This "working" solution is quite fragile, and very suboptimal; the Piecewise version would be the correct solution, if it worked.
[1]: Python actually allows you to write this as -1 < u < 1. Pretty cool.
[2]: Although in some special cases you can, e.g. if you know x > 0, then you can use assume(x > 0) which means the example will print :).
Here is a (possibly) simpler solution for now, using lambdas.
sage: plot(lambda x:f(x), (x,-5,5))

Categories

Resources