This question already has answers here:
Is this an example of python function overload?
(3 answers)
Closed 2 years ago.
I have come across that only parameters at the END of a paramater list can have a default value as VALUES are assigned by position in a function as how it is defined below
def greeting(a,b=7):
pass
and NOT
def greeting(a=4,b):
pass
The doubt which I have in built-in range() function is we can pass the arguments as follows
range(start_value, stop_value, increment_value)
and not all the arguments are needed while calling the function, so is range() function an overloaded function, or does it has default paraments in the definition?
range gets three arguments and it checks count of argument then returns generated iterible object
If you want to do something like it so you shoud replace all arguments with *args then do like following
def range_(*args):
start = 0
end = 0
step = 0
# args is a list of arguments
if len(args) == 1:
end = args[0]
elif len(args) == 2:
start, end = args
elif len(args) == 3:
start, end, step = args
else:
print("the function gets maximum three arguments")
# calculating something with start, end, step
# and return result
P. S.
if you want define function with default arguments then default arguments should be defined before others
Related
How does one determine the arguments for a function inside a function in python.
Consider an the following example:
def fun1():
mysum = 0
def fun2(arg):
mysum += arg
fun2(1)
fun2(2)
fun2(3)
print mysum
This can be written as
def fun1():
mysum = 0
def fun2(mysum, arg):
mysum += arg
fun2(mysum, 1)
fun2(mysum, 2)
fun2(mysum, 3)
print mysum
In the above case, sum can either be passed as argument or not. When does one determine if it should be passed as argument or not?
It depends on the situation. Do you want to modify a parameter variable or do you want your function to modify a closed variable. The latter may be less reusable, but in the end it is subjective.
In python3 you must use either global or nonlocal in order to modify any closed variables.
def fun1():
sum = 0
def fun2(arg):
nonlocal sum
sum += arg
fun2(sum, 1)
fun2(sum, 2)
fun2(sum, 3)
print sum
When I try to port it it errors out asking for key2
Python 2:
def SortItems(self,sorter=cmp):
items = list(self.itemDataMap.keys())
items.sort(sorter)
self.itemIndexMap = items
self.Refresh()
Python 3:
try:
cmp
except NameError:
def cmp(x, y):
if x < y:
return -1
elif x > y:
return 1
else:
return 0
def SortItems(self,sorter=cmp):
items = list(self.itemDataMap.keys())
items.sort(key=sorter)
self.itemIndexMap = items
self.Refresh()
Getting the error:
items.sort(key=sorter)
TypeError: __ColumnSorter() missing 1 required positional argument: 'key2'
It looks like lambda function needs second argument
Any idea how to make it work?
Also tried functools.cmp_to_key:
def SortItems(self):
import locale
items = list(self.itemDataMap.keys())
items= sorted(items, key=cmp_to_key(locale.strcoll))
self.itemIndexMap = items
self.Refresh()
Getting error:
items= sorted(items, key=cmp_to_key(locale.strcoll))
TypeError: strcoll() argument 1 must be str, not int
Probably because I'm sorting integers not strings
How do I make it work for int?
cmp and key are fundamentally different. However there is a conversion function you can use: functools.cmp_to_key().
From the docs Python3 list.sort():
sort() accepts two arguments that can only be passed by keyword
(keyword-only arguments)
key specifies a function of one argument that is used to extract a
comparison key from each list element (for example, key=str.lower).
That is, the key callable only takes a single argument in py3. So in this case doing
items.sort(int), or equivalently items.sort(lambda x: x)
will sort a list of int in ascending order.
In general cmp should return the comparison property of the each element
of the list.
def cmp(x):
# code to compute comparison property or value of x
# eg. return x % 5
Additionally, you can convert the python2 cmp function:
The functools.cmp_to_key() utility is available to convert a 2.x style
cmp function to a key function.
https://docs.python.org/3/library/stdtypes.html#list.sort
What is a most pythonic way to write a function to either pass in arguments or a tuple/list of arguments?
For example, a function add could either take in an argument of add(1, 2) or add((1, 2)) and both output 3.
What I have so far: (it works, but does not look nice)
def add(*args):
if len(args) == 1:
return (args[0][0] + args[0][1])
if len(args) == 2:
return args[0] + args[1]
else:
print "error: add takes in one or two arguments"
What I don't like about it is:
I have to print the error about passing in one or two arguments
The args[0][0] looks very unreadable
This way, it is hard to tell what the arguments passed in represent (they don't have names)
I dont know if this is the most "pythonic" way but it will do what you want:
def add(a, b=None):
return a+b if b is not None else sum(a)
If your function takes a specific number of arguments, then the most pythonic way to do this is to not do it. Rather if the user has a tuple with the arguments, you make them unpack them when they call the function. E.g.
def add(a, b):
return a + b
Then the caller can do
add(1,2)
or
t = (1,2)
add(*t)
The only time you want to accept either a sequence of params or individual params is when you can have any arbitrary (non-zero) number of arguments (e.g. the max and min builtin functions) in which case you'd just use *args
If you can only take a finite number of arguments, it makes more sense to ask for those specifically. If you can accept an arbitrary number of arguments, then the *args paradigm works well if you loop through it. Mixing and matching those two aren't very elegant.
def add(*args):
total = 0
for i in args:
total += i
return total
>>> add(1, 2, 3)
6
(I know we could just use sum() there, but I'm trying to make it look a bit more general)
In the spirit of python duck typing, if you see 1 argument, assume its something that expands to 2 arguments. If its then 2, assume its two things that add together. If it violates your rules, raise an exception like python would do on a function call.
def add(*args):
if len(args) == 1:
args = args[0]
if len(args) != 2:
raise TypeError("add takes 2 arguments or a tuple of 2 arguments")
return args[0] + args[1]
A decorator would be best suited for this job.
from functools import wraps
def tupled_arguments(f):
#wraps(f) # keeps name, docstring etc. of f
def accepts_tuple(tup, *args):
if not args: # only one argument given
return f(*tup)
return f(tup, *args)
return accepts_tuple
#tupled_arguments
def add(a, b):
return a + b
I am searching how I could use optional arguments in python.
I have read this question but it is not clear to me.
Lets say I have a function f that can take 1 or more arguments to understand time series. Am i obliged to specify the number of arguments and set default values for each argument?
What I aim to do is being able to write a function this way:
simple function:
def f(x,y):
return x + y
#f(1,2) returns 3
What i want is also f(1,2,3) to return me 6 and f(7) returning me 7
Is it possible to write it without setting a predefined number of mandatory/optional parameters?
Is it possible to write it without having to set default values to 0 ?
How to write this function?
Its a simple example with numbers but the function i need to write is comparing a set of successive objects. After comparison is done, the data set will feed a neural network.
Thanks for reading.
EDIT:
Objects I am feeding my function with are tuples like this (float,float,float,bool,string)
You can put *args in your function and then take arbitrary (non-keyword) arguments. *args is a tuple, so you can iterate over it like any Python tuple/list/iterable. IE:
def f(*args):
theSum = 0
for arg in args:
theSum += arg
return theSum
print f(1,2,3,4)
def f(*args):
"""
>>> f(1, 2)
3
>>> f(7)
7
>>> f(1, 2, 3)
6
>>> f(1, 2, 3, 4, 5, 6)
21
"""
return sum(args)
If you need to do something more complicated than sum you could just iterate over args like this:
def f(*args):
r = 0
for arg in args:
r += arg
return r
See this question for more information on *args and **kwargs
Also see this sections on the Python tutorial: Arbitray Argument List
You can use the follow syntax:
def f(*args):
return sum(args)
The * before args tells it to "swallow up" all arguments, makng args a tuple. You can also mix this form with standard arguments, as long as the *args goes last. For example:
def g(a,b,*args):
return a * b * sum(args)
The first example uses the built-in sum function to total up the arguments. sum takes a sequence as adds it up for you:
>>> sum([1,3,5])
9
>>> sum(range(100))
4950
The args name is not mandatory but is used by convention so best to stick with it. There is also **kwargs for undefined keyword arguments.
I'd like to learn how to pass an arbitrary number of args in a python function, so I wrote a simple sum function in a recursive way as follows:
def mySum(*args):
if len(args) == 1:
return args[0]
else:
return args[-1] + mySum(args[:-1])
but when I tested mySum(3, 4), I got this error:
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
Does anyone have an idea about this and gimme some clue to correct it?
This line:
return args[-1] + mySum(args[:-1])
args[:-1] returns a slice of the arguments tuple. I assume your goal is to recursively call your function using that slice of the arguments. Unfortunately, your current code simply calls your function using a single object - the slice itself.
What you want to do instead is to call with those args unrolled.
return args[-1] + mySum(*args[:-1])
^---- note the asterisk
This technique is called "unpacking argument lists," and the asterisk is sometimes (informally) called the "splat" operator.
If you don't want to do it recursively:
def mySum(*args):
sum = 0
for i in args:
sum = sum + i
return sum
args[:-1] is a tuple, so the nested call is actually mySum((4,)), and the nested return of args[0] returns a tuple. So you end up with the last line being reduced to return 3 + (4,). To fix this you need to expand the tuple when calling mySum by changing the last line to return args[-1] + mySum(*args[:-1]).
In your code, args[:-1] is a tuple, so mySum(args[:-1]) is being called with the args being a tuple containing another tuple as the first argument. You want to call the function mySum with args[:-1] expanded to the arguments however, which you can do with
mySum(*args[:-1])
The arbitrary arguments are passed as tuple (with one asterisk*) to the function, (you can change it to a list as shown in the code) and calculate the sum of its elements, by coding yourself using a for loop; if don't want to use the sum() method of python.
def summing(*arg):
li = list(*arg)
x = 0
for i in range((len(li)-1)):
x = li[i]+x
return x
#creating a list and pass it as arbitrary argument to the function
#to colculate the sum of it's elements
li = [4, 5 ,3, 24, 6, 67, 1]
print summing(li)
Option1:
def mySum(*args):
return sum(args)
mySum(1,2,3) # 6
mySum(1,2) # 3
Option 2:
mySum2 = lambda *args: sum(args)
mySum2(1,2,3) # 6
mySum2(1,2) # 3