Im VERY new to programming. Its my second day. In functions like file.read(), empty parenthesis are part of the syntax. Are they always supposed to be empty, or is there an option to fill them? My script works fine, It's just a question I've always had.
When you define a function, you specify the function's arguments. A function can have zero or more arguments. When a function has zero arguments, or all of its arguments have default values, then you can call the function without passing any arguments.
It depends whether you what them empty (no arguments ) or not (with arguments)
Here is an example of a function
#Let's create a function that can add two values :)
def add(x, y): # the function have positional arguments 'x' 'y'
z = x + y
return z # the function output the value of z
addition = add(5, 33) # call the add() function with arrguments x=5, y=33
print(addition)
#this time variables as arguments
a = 5
b = 33
additon = add(a ,b)
print(addition)
As you can see above that function takes input as arguments and returns the output
Related
I want to apply a function along a column, eg coco.convert, and pass to it, along with the value in the row, the argument to = 'ISO3'.
df['alpha-3'] = df['Country'].apply(coco.convert('ISO3'))
misses 1 positional argument:
TypeError: convert() missing 1 required positional argument: 'names'
but
df['alpha-3'] = df['Country'].apply(coco.convert)
works fine (I assume it uses default values).
How do I pass the positional argument here?
Also, what exactly is happening here - can someone explain a little how the function is passed to apply?
Probably the most normal way to solve this would be to use the **kwds argument for .apply which are covered in the apply documentation. Basically you can just pass any other named arguments to .apply() and it uses them with the passed function.
df['alpha-3'] = df['Country'].apply(coco.convert, to='ISO3')
An alternative way to do it would be to define your own new function with the arguments pre-passed such as below.
def my_fun(x):
return coco.convert(names = x, to = 'ISO3')
df['alpha-3'] = df['Country'].apply(my_fun)
To your other about how .apply works...
Take the column of data you give it, and loop through each element
For each element, feed its value into the supplied function as the *first
For each return of that function, convert it into another Pandas series.
I want to define a resize(h, w) method, and I want to be able to call it in one of two ways:
resize(x,y)
resize(x)
Where, in the second call, I want y to be equal to x. Can I do this in the method definition or should I do something like resize(x,y=None) and check inside:
if y is None:
y = x
Can I do this in the method definition
No. During the method definition there's no way to know what value x might have at run-time. Default arguments are evaluated once at definition time, there's no way to save a dynamic value for y.
or should I do something like resize(x,y=None) and check inside
exactly. This is a common idiom in Python.
To complete Jim's answer, in the case that None is valid as a parameter value, you could use variable length arguments feature (positional, and/or keyword). Example of use for positional:
def resize(x,*args):
if args:
if len(args)>1:
raise Exception("Too many arguments")
y = args[0]
else:
y = x
in that example, you have to pass x, but you can pass 0 or more extra positional arguments. Of course you have to do the checking manually, and you lose the y keyword.
I created a function that takes an arbitrary number of variables via the *args feature. Now another function needs to call this original function using a list of varying length, but I can't seem to find a solution. As a simplified example:
def print_all(*args):
for x in args:
print(x)
print_all([1,2,3,4,5])
Running this, the console displays:
[1,2,3,4,5]
But I would like it to display:
1
2
3
4
5
Is there a way to turn an iterable like this into proper input for a function that accepts *args like above?
The following will do the trick:
print_all(*[1,2,3,4,5])
With the star operator every item in the list is like been passed as a separate argument to the function.
Remove the * which exists in the parameter part of the function definition. Here * is unnecessary.
def print_all(args):
for x in args:
print(x)
Following code is incorrect:
def add(a, b, c):
return a + b + c
args = (2, 3)
add(a = 1, *args)
TypeError: add() got multiple values for keyword argument 'a'
I've seen some example in python docs, but I still don't know why there's an error, can anybody explain in detail?
When applying the arguments, Python first fills in the positional arguments, then the keyword arguments.
In your specific case, *args is then applied firsts, so the first positional argument is passed 2, the second is passed 3. The first argument is a here.
Then the a = 1 is applied, and Python finds that you already applied a value to it.
In other words, Python cannot and will not take positional arguments out of consideration when you use one as a keyword argument. Just because you used a as keyword argument does not make it ineligible as a positional argument.
def f1(n): #accepts one argument
pass
def f2(): #accepts no arguments
pass
FUNCTION_LIST = [(f1,(2)), #each list entry is a tuple containing a function object and a tuple of arguments
(f1,(6)),
(f2,())]
for f, arg in FUNCTION_LIST:
f(arg)
The third time round in the loop, it attempts to pass an empty tuple of arguments to a function that accepts no arguments. It gives the error TypeError: f2() takes no arguments (1 given). The first two function calls work correctly - the content of the tuple gets passed, not the tuple itself.
Getting rid of the empty tuple of arguments in the offending list entry doesn't solve the problem:
FUNCTION_LIST[2] = (f2,)
for f,arg in FUNCTION_LIST:
f(arg)
results in ValueError: need more than 1 value to unpack.
I've also tried iterating over the index rather then the list elements.
for n in range(len(FUNCTION_LIST)):
FUNCTION_LIST[n][0](FUNCTION_LIST[n][1])
This gives the same TypeError in the first case, and IndexError: tuple index out of range when the third entry of the list is (f2,).
Finally, asterisk notation doesn't work either. This time it errors on the call to f1:
for f,args in FUNCTION_LIST:
f(*args)
gives TypeError: f1() argument after * must be a sequence, not int.
I've run out of things to try. I still think the first one ought to work. Can anyone point me in the right direction?
Your comment in this code snippet shows a misconception relevant in this context:
FUNCTION_LIST = [(f1,(2)), #each list entry is a tuple containing a function object and a tuple of arguments
(f1,(6)),
(f2,())]
The expressions (2) and (6) are not tuples – they are integers. You should use (2,) and (6,) to denote the single-element tuples you want. After fixing this, your loop code should look thus:
for f, args in FUNCTION_LIST:
f(*args)
See Unpacking Argument Lists in the Python tutorial for an explanation of the *args syntax.
The problem is that such notation:
(6)
evaluates to integer value and you need tuple, so write this way:
(6, )
and your asterisk notation will succeed.
Try passing *() instead of (). The * symbol tells python to unpack the iterable that follows it, so it unpacks the empty tuple and passes nothing to the function, since the tuple was empty.
For the record, a nice alternative I have since discovered is the use of functools.partial. The following code does what I was trying to do:
from functools import partial
def f1(n): #accepts one argument
pass
def f2(): #accepts no arguments
pass
FUNCTION_LIST = [partial(f1,2), #each list entry is a callable with the argument pre-ordained
partial(f1,6),
partial(f2)] #the call to partial is not really necessary for the entry with no arguments.
for f in FUNCTION_LIST: f()