python passing positional arguments to another function call [duplicate] - python

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

Related

Get only one of a function's returned values [duplicate]

This question already has answers here:
Ignore python multiple return value
(12 answers)
Closed 1 year ago.
I have defined a function as:
def f():
a = 5
b = 6
c = 7
def g(x):
return x+2
return a, b , c, g
I would like to know how to get only one of the value returned, without the other ones. For example If I am only interested in c, is there an alternative to:
a, b, c, g = f()
To get c?
Python returns multiple values as a tuple. You can check this by doing
>>> type(f())
>>> <class 'tuple'>
As from your implementation we can assume that the c variable value always lies on the index 2 so you can do
c_value = f()[2]

*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.

How to know how many arguments to pass to referenced function

lets say a I have two functions:
def foo1(bar, a, b, c):
result = bar(a, b)
return result
def foo2(bar, a, b, c):
result = bar(a, b, c)
return result
the arguments are the same in both situation, but it depends on the function "bar" that may need only 2, and another one may need all 3 (in the same order)
is it possible to make this into a single function without knowing how many arguments the referenced function needs?
You can use the function object's __code__.co_argcount attribute to obtain the number of arguments it expects, with which you can slice the argument list:
def bar1(a, b):
return b, a
def bar2(a, b, c):
return c, b, a
def foo(bar, *args):
return bar(*args[:bar.__code__.co_argcount])
print(foo(bar1, 1, 2, 3))
print(foo(bar2, 1, 2, 3))
This outputs:
(2, 1)
(3, 2, 1)
Try this.
from inspect import signature
def foo(bar, *args):
arg_count = len(signature(bar).parameters)
return bar(*args[:arg_count])
This passes however many arguments the function expects, and ignores the rest. If you want to use all the arguments later, they're in the args list.
Yes. If I understand you correctly, you want to pass unspecified amount of arguments to a function?
If so, you can accept a tuple; such that the function can accept (a, b, c) or several more arguments. Tuples are similar to lists, but are not mutable. Of course, it's up to you to make sure the right amount of arguments are inputted.
Below, arguments is a tuple.
You can do len(arguments) to find out how many arguments were inputted.
arguments=(bar, a, b)
foo(arguments)
def foo(my_tuple):
result = arguments[0](arguments[1], arguments[2])
return result
I think you may be looking for the * expansion operator
def foo(bar, *args):
result = bar(*args)
return result
For example:
In [1]: def foo(bar,*args):
...: return bar(*args)
...:
In [2]: def f1(a):
...: return a
...:
In [3]: def f2(a,b):
...: return a+b
...:
In [4]: foo(f1,5)
Out[4]: 5
In [5]: foo(f2,5,6)
Out[5]: 11
In [6]: foo(f1,5,6)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-5ca26cac7f4d> in <module>
----> 1 foo(f1,5,6)
<ipython-input-1-fe8d4699f744> in foo(bar, *args)
1 def foo(bar,*args):
----> 2 return bar(*args)
3
TypeError: f1() takes 1 positional argument but 2 were given

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

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)

Is it possible to convert a python function into a class? [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 6 years ago.
Improve this question
I am new to Python coming from C++ background and this is the first time I am seeing a language which contains nothing but objects. I have just learned that class and functions are also just objects. So, is there a way to convert the following function to a class?
In [1]: def somefnc(a, b):
...: return a+b
...:
I have first tried assigning the __call__ variable to None to take away the "callable nature" from the function. But as you can see, the __call__ was successfully replaced by None but this didn't cause the function to stop adding numbers when called, though, somefnc.__call__(1,3) was working before assigning somefnc.__call__ to None
In [2]: somefnc.__dict__
Out[2]: {}
In [3]: somefnc.__call__
Out[3]: <method-wrapper '__call__' of function object at 0x7f282e8ff7b8>
In [4]: somefnc.__call__ = None
In [5]: x = somefnc(1, 2)
In [6]: print(x)
3
In [7]: somefnc.__call__
In [8]: print(somefnc.__call__(1, 2))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
ipython-input-8-407663da97ca
in <module>()
----> 1 print(somefnc.__call__(1, 2))
TypeError: 'NoneType' object is not callable
In [9]: print (somefnc(1,2))
3
In [10]:
I am not doing this for developing purpose here, so claiming this to be a bad practice will not make any sense. I am just trying to understand Python very well. Of course, for development purpose, I could rather create a class than to convert a function to one!
After robbing the function off its ability to add two numbers, I am thinking of assigning a valid function to the attribute somefnc.__init__ and some members by modifying somefun.__dict__, to convert it to a class.
In Python functions are instances of the function class. So I'll give you a general answer about any class and instance.
In [10]: class Test:
...: def __getitem__(self, i):
...: return i
...:
In [11]: t = Test()
In [12]: t[0]
Out[12]: 0
In [13]: t.__getitem__(0)
Out[13]: 0
In [14]: t.__getitem__ = None
In [15]: t[0]
Out[15]: 0
In [16]: t.__getitem__(0)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-c72f91d2bfbc> in <module>()
----> 1 t.__getitem__(0)
TypeError: 'NoneType' object is not callable
In Python all special methods (the ones with double underscores in the prefix and the postfix) are accessed from the class when triggered via operators, not from the instance.
In [17]: class Test2:
...: def test(self, i):
...: return i
...:
In [18]: t = Test2()
In [19]: t.test(1)
Out[19]: 1
In [20]: t.test = None
In [20]: t.test(1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-261b43cb55fe> in <module>()
----> 1 t.test(1)
TypeError: 'NoneType' object is not callable
All methods are accessed via the instance first, when accessed by name. The difference is due to different search mechanics. When you access a method/attribute by name, you invoke __getattribute__ which will first search in the instance's namespace by default. When you trigger a method via operators, __getattribute__ is not invoked. You can see it in the disassembly.
In [22] import dis
In [23]: def test():
...: return Test()[0]
...:
In [24]: dis.dis(test)
2 0 LOAD_GLOBAL 0 (Test)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 LOAD_CONST 1 (0)
9 BINARY_SUBSCR
10 RETURN_VALUE
In [25]: def test2():
...: return Test().__getitem__(0)
...:
In [26]: dis.dis(test2)
2 0 LOAD_GLOBAL 0 (Test)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 LOAD_ATTR 1 (__getitem__)
9 LOAD_CONST 1 (0)
12 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
15 RETURN_VALUE
As you can see, there is no LOAD_ATTR in the first case. The [] operator is assembled as a special virtual-machine instruction BINARY_SUBSCR.

Categories