Star (*) as an argument in python function [duplicate] - python

This question already has answers here:
Bare asterisk in function parameters?
(6 answers)
Closed 4 years ago.
I was looking at the definition of the glob function and I noticed that the second argument was simply *.
def glob(pathname, *, recursive=False):
"""Return a list of paths matching a pathname pattern.
[...]
"""
return list(iglob(pathname, recursive=recursive))
What is the point of the *?

The * indicates the end of the positional arguments. Every argument after that can only be specified by keyword. This is defined in PEP 3102
>>> def foo1(a, b=None):
... print(a, b)
...
>>> def foo2(a, *, b=None):
... print(a, b)
...
>>> foo1(1, 2)
1 2
>>> foo2(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo1() takes 1 positional argument but 2 were given
>>> foo2(1, b=2)
1 2

All arguments after the * must have their name explicitly specified. For example, if you had this function:
def somefunction(a,*,b):
pass
You could write this:
somefunction(0, b=0)
but not this:
somefunction(0, 0)

Related

*args vs list as a arguments in Python [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 3 years ago.
I just want to understand why we use *args when the same work can be done by list when we pass it as a argument. In which scenarios do we really need *args, where list as a argument will fail to do that operation.
list =[1,2,3,4,5,6,7]
def method1(args):
for i in args:
print(i*2)
method1(list)
list =[1,2,3,4,5,6,7]
def method1(*args):
for i in args:
print(i*2)
method1(*list)
I didn't find any differences. Please correct me if i am wrong.
def method1(args):
print(args)
method1(5) it will print 5
method1() method1() missing 1 required positional argument: 'args'
method1(2,6) TypeError: method1() takes 1 positional argument but 2 were given
To Avoid this situation we use
def method1(*args):
print(args)
method1(1, 2, '3')
(1, 2, '3') print this
So *args is useful when we don’t know in advance how many arguments we need to pass in.
The difference is that you can pass any number of arguments in the second case where it will throw error in the first case.
Case 1:
lst = [1,2,3,4,5,6,7]
a = 1
b = 2
def method1(args):
for i in args:
print(i*2)
method1(lst, a, b)
...fails with 'TypeError: method1() takes 1 positional argument but 3 were given'.
Case 2 (i):
lst = [1,2,3,4,5,6,7]
a = 1
def method1(*args):
for i in args:
print(i*2)
method1(lst, a)
...works.
Case 2 (ii):
lst = [1,2,3,4,5,6,7]
a = 1
b = 2
def method1(*args):
for i in args:
print(i*2)
method1(lst, a, b)
...works and so on, you can pass any number of arguments.

Can addition between classes be evaluated by the class of the 2nd argument? [duplicate]

This question already has an answer here:
Addition overloading in Python behaviour x+y vs y+x
(1 answer)
Closed 6 years ago.
I've defined a new modulus 7 class:
class mod7:
def __init__(self, n):
self.val = n % 7
def __repr__(self):
return str(self.val)
Then
In [2]: a = mod7(18)
In [3]: a
Out[3]: 4
I wanted to allow additions of not just mod7 objects but also of integers to the new class. So under the class I've added
def __add__(self, other):
if type(other) is int:
return mod7(self.val + other)
if type(other) is mod7:
return mod7(self.val + other.val)
and
In [11]: a + mod7(5)
Out[11]: 2
In [12]: a + 5
Out[12]: 2
However
In [13]: 5 + a
Traceback (most recent call last):
File "<ipython-input-13-14fd8adcbf4d>", line 1, in <module>
5+a
TypeError: unsupported operand type(s) for +: 'int' and 'mod7'
I understand why - The addition function is called by the class of the 1st argument. My question: Is there any way to override 5 + a according to the class of 2nd argument, i.e. a?
You'll want to also define __radd__. This would be called automatically if the left operand did not support +, but ints do, so you have to define it specifically to handle this situation. You can just define it to call your __add__ function so you don't have to rewrite anything.

* mark in print function call [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 6 years ago.
What is this star mark in this print function call?
for i in range(int(input())):
s=input()
print(*["".join(s[::2]),"".join(s[1::2])])
It is called argument unpacking. If you were to omit it, then it would only give the list created by the list comprehension to the print function as one argument. With the asterisk it passes every item in that list as separate argument.
Consider this example:
def my_func(arg1, arg2, arg3):
print('yay it worked')
and then call it with:
my_func(*[1, 2, 3])
that way arg1 will be 1, arg2 will be 2 and arg3 will be 3.
If you change the call to:
my_func([1, 2, 3])
then you pass the list to arg1 and it will raise a TypeError because it's missing two positional arguments.

Can you have keyword arguments without supplying a default value?

I am used to having function/method definitions like so in Python:
def my_function(arg1=None , arg2='default'):
... do stuff here
If I don't supply arg1 (or arg2), then the default value of None (or 'default') is assigned.
Can I specify keyword arguments like this, but without a default value? I would expect it to raise an error if the argument was not supplied.
You can in modern Python (3, that is):
>>> def func(*, name1, name2):
... print(name1, name2)
...
>>> func()
Traceback (most recent call last):
File "<ipython-input-5-08a2da4138f6>", line 1, in <module>
func()
TypeError: func() missing 2 required keyword-only arguments: 'name1' and 'name2'
>>> func("Fred", "Bob")
Traceback (most recent call last):
File "<ipython-input-7-14386ea74437>", line 1, in <module>
func("Fred", "Bob")
TypeError: func() takes 0 positional arguments but 2 were given
>>> func(name1="Fred", name2="Bob")
Fred Bob
Any argument can be given as with a keyword expression, whether or not it has a default:
def foo(a, b):
return a - b
foo(2, 1) # Returns 1
foo(a=2, b=1) # Returns 1
foo(b=2, a=1) # Returns -1
foo() # Raises an error
If you want to force the arguments to be keyword-only, then see DSM's answer, but that didn't seem like what you were really asking.

python passing positional arguments to another function call [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
What do *args and **kwargs mean? [duplicate]
(5 answers)
Closed 9 years ago.
Can someone please explain to me how the below works:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
return self.memo[args]
Then:
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
factorial = Memoize(factorial)
This is taken from this question. I would like to understand how does self.f(*args) work. args is a tuple of positional arguments. When I try to do:
*(1,2,3)
I get syntax error. I thought it's some kind on unpacking operator or something like that. Does asterisk with a tuple mean anything independently or does it exist only in the context of a function call? Thank you for any explanations.
It /is/ an unpacking operator. However, it doesn't always work that way when called directly in the interpreter. Check this out:
In [90]: def addThese(a,b,c):
....: print 'a', a
....: print 'b', b
....: print 'c', c
....: print 'a+b+c', a+b+c
....: return a+b+c
....:
In [91]: args = (1,3,5)
In [92]: addThese(1,3,5)
a 1
b 3
c 5
a+b+c 9
Out[92]: 9
In [93]: addThese(args)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-93-cc47562f352a> in <module>()
----> 1 addThese(args)
TypeError: addThese() takes exactly 3 arguments (1 given)
In [94]: addThese(*args)
a 1
b 3
c 5
a+b+c 9
Out[94]: 9

Categories