Passing multiple arguments to pool.map using class function - python

I'm trying to thread as described in this post, and also pass multiple arguments in Python 2.7 through a work-around described here.
Right now I have something like this, a function that is part of class pair_scraper:
def pool_threading(self):
pool = ThreadPool(4)
for username in self.username_list:
master_list = pool.map(self.length_scraper2,
itertools.izip(username*len(self.repo_list),
itertools.repeat(self.repo_list)))
def length_scraper2(self, username, repo):
#code
However, when I run my code I get the error:
TypeError: length_scraper2() takes exactly 3 arguments (2 given)
Which seems to be because it wants self passed as an argument, which is nonsensical given I'm using a class function within the class. Thoughts on how to fix?

itertools.izip(username*len(self.repo_list),itertools.repeat(self.repo_list)) yields a tuple.
You need to pass 2 arguments explicitly to your method (self is implicitly passed because it's a non-static method), but you only pass 1 tuple explicitly, plus the implicit self which makes 2 arguments, hence the confusing error message.
You have to use * to pass your tuple as 2 separate arguments, like this:
master_list = pool.map(self.length_scraper2,
*itertools.izip(username*len(self.repo_list),itertools.repeat(self.repo_list)))
simple test using the classical map on a simple function:
def function(b,c):
return (b,c)
print(list(map(function,zip([1,2],[4,5]))))
error:
print(list(map(function,zip([1,2],[4,5]))))
TypeError: function() missing 1 required positional argument: 'c'
now adding single asterisk to expand args:
print(list(map(function,*zip([1,2],[4,5]))))
works:
[(1, 2), (4, 5)]
same goes for class method:
class Foo:
def function(self,b,c):
return (b,c)
f = Foo()
print(list(map(f.function,*zip([1,2],[4,5]))))

Related

Passing an object to a decorator

I'm trying to create a Python file containing all of the decorators which I need to use in the rest of the program. These decorators are stored inside a class, which I called Decorators. Then I tried to add a decorator to check if the argument of a decorated function match with the argument types passed to the decorator itself (I took this kind of decorator from the example 4 at the site https://www.python.org/dev/peps/pep-0318/#examples, but I changed it a bit to better fit my style of coding). The syntax is like this:
class Decorators(object):
""" Decorators class: contain all the decorators """
#classmethod
def argument_consistency(cls, *function_arguments_type):
""" check the consistency of argument and their types of the decorated function """
def check_arguments(function):
""" check if the number of passed arguments is different from the number of accepted arguments """
# check if the number of passed arguments is different from the number of accepted arguments
if not len(function_arguments_type) == function.__code__.co_argcount:
raise Exception("the number of passed argument is different from the number of the accepted arguments")
def inner_function(*args, **kwds):
""" check if the type of the passed arguments match with the requested ones """
# iterate through the list of couples (argument, argument's type) and check for their match
for (arguments, argument_types) in zip(args, function_arguments_type):
# remember that: {arguments} is the n-th argument passed to the function, while
# the {argument_types} is the n-th argument types. {args} is the entire list of arguments
# passed to the function; {function_arguments_type} is the entire list of types. So zip
# returns an iterator of tuples of element of {args} and {function_arguments_type} paired
# together, for example zip((1, 2, 3, 4), (a, b, c, d)) = ((1, a), (2, b), (3, c), (4, d))
# check if the n-th argument type match with the one requested
if not type(arguments) == argument_types:
raise Exception(f"The argument {arguments} doesn't match the type, "
f"which must be {argument_types}")
# returning the passed function using the passed arguments
return function(*args, **kwds)
# changing the name of the inner_function to the {function}'s name
inner_function.__name__ = function.__name__
# return the inner function
return inner_function
# return the check_argument function
return check_arguments
To test the previous decorator I created the simple class A whith a function a:
class A():
def __init__(self):
pass
#Decorators.argument_consistency(str, str)
def a(self, str1, str2):
print(f"{str1} AND {str2}")
a = A()
a.a("ciao", "ciao2")
Obviously, when I decorated the function a I got an error (rised by the argument_consistency decorator itself). This because the length of the list argument types is different from the length of the list of passed arguments. The error appeared because I didn't put the self parameter. Understood this error, I tried to pass self to the decorator, but I got an error: NameError: name 'self' is not defined (this happens even if I pass type(self)); then I tried to pass the class A itself, but I still got the same error. So I tried to fix this by adding to the decorator one line between the for loop and the if not type(arguments) == argument_types:
if not (args.index(arguments) == 0 and argument_types is None):
# check if the n-th argument type match with the one requested
if not type(arguments) == argument_types:
# the rest of the code
pass
These line checks whether the first argument passed to the function decorator is None, then that means that the first parameter of the function is self, so the function doesn't proceed to check if None is equal to the type of the self parameter (which obviously is not). This way is very cumbersome and the opposite of elegant. Therefore I wonder if there is a way to avoid this fix and directly pass the self type to the decorator.
You can make a stub class for self argument for object/class methods
class selftype:
pass
and pass it to decorator
#Decorators.argument_consistency(selftype, str, str)
def a(self, str1, str2):
print(f"{str1} AND {str2}")
Then check in inner_function if the first type in decorator is your stub type:
def inner_function(*args, **kwds):
for (argument, argument_type, i) in zip(args, function_arguments_type, range(0, len(args))):
if argument_type == selftype and i == 0:
pass
# check if the n-th argument type match with the one requested
elif not type(argument) == argument_type:
raise Exception(f"The argument {argument} doesn't match the type, "
f"which must be {argument_type}")
# returning the passed function using the passed arguments
return function(*args, **kwds)
Not very elegant, but this works for both object/class methods and functions
class A():
def __init__(self):
pass
#Decorators.argument_consistency(selftype, str, str)
def a(self, str1, str2):
print(f"{str1} AND {str2}")
a = A()
a.a("ciao", "ciao2")
#Decorators.argument_consistency(str)
def b(str1):
print(f"{str1}")
b("a")
Also, if you want to use your decorator in pair with #classmethod or #staticmethod, make sure to apply your decorator first, otherwise it won't be able to access function.__code__ attribute.
I quite liked the solution proposed by #go2nirvana in comments, but it didn't work for me, unfortunately. inspect.ismethod(function) returns False inside decorator functions calls, idk why.

How to use the functools.partial on a function which has an argument which is a callable?

I'm trying to use the function partial from module functools on a callable which has an argument which is a function.
I've come up with a minimalist sample code.
from functools import partial
def g(f, x):
return f(x)
def cube(x):
return x*x*x
p1 = partial(g, x=3)
abc = p1(cube) # works
p2 = partial( g, f=cube)
abc = p2(3) # fails TypeError: g() got multiple values for keyword argument 'f'
Can the function work with that case?
Thanks
It is not link to the type of the argument, the (partial) function call follows the rules https://docs.python.org/2/reference/expressions.html#calls
The positional arguments are placed in the first parameter slots, then if *expression is present, expression is unzipped and placed in the next slots, finally if **expression is present, expression is mapped to function parameters and throws an error if parameter is already bound to an argument.
So
p2 = partial( g, f=cube)
p2(3) # fails
is the same as calling
g(3, f=cube)
You can refer to the partial method from the python doc
In partial we cannot pass two functions, so this may be the issue. Try to pass one function object and the second arg is the functional argument.
You can use this,
p2 = partial(g, f=cube, x=1)
abc = p2(x=3)
print(abc)
Hope this will help you.

pass class method to fsolve

I have the following code:
import scipy.optimize
class demo(object):
def get_square(self, var):
return var ** 2 - 4
new = demo()
scipy.optimize.fsolve(new.get_square(), 1)
And I got the following error:
TypeError: get_square() missing 1 required positional argument: 'var'
But get_square() should always have self and self need not be passed. What's the problem?
You're actually calling the function before fsolve has a change to do anything; since the call has no arguments this will raise the expected TypeError.
You could either remove the call () to new.get_square:
scipy.optimize.fsolve(new.get_square, 1)
or, since you aren't actually even using self in get_square, make it a #staticmethod:
class demo(object):
#staticmethod
def get_square(var):
return var ** 2 - 4
new = demo()
scipy.optimize.fsolve(new.get_square, 1)
Two small notes:
Use CapWords for class names, that is, demo -> Demo.
If you aren't trying to be portable between Python 2/3, no need to inherit from object.

Static lambdas in python

I have class in python like this
import numpy as np
class BackPropogationNetwork:
# Static lambdas
sigmoid = lambda x : 1/(1+np.exp(-x))
sigmoid_prime = lambda sigmoid: sigmoid(1-sigmoid)
and this is the contructor
def __init__(self):
self.some_attr = self.sigmoid(2)
I get this error
TypeError: <lambda>() takes exactly 1 argument (2 given)
If I call like this
self.some_attr = ClassName.sigmoid()
I get this error
TypeError: unbound method <lambda>() must be called with BackPropogationNetwork instance as first argument (got int instance instead)
You need to wrap the lambdas in staticmethod objects:
class BackPropogationNetwork:
sigmoid = staticmethod(lambda x : 1/(1+np.exp(-x)))
sigmoid_prime = staticmethod(lambda sigmoid: sigmoid(1-sigmoid))
lambda expressions still produce function objects, just using different (limited) syntax. The same rules apply as defining functions in a class; if you want it to be a static method then you still need to wrap them.
So your sigmoid function is kinda independent of the class, it would make sense to keep it outside, unless:
you want to not pollute the namespace of the module
you want to increase the discoverability of the function
you want this method to me overwritten.
Let's assume you have made up your mind and nothing can change it, well in that case you can do this.
When you call a method like self.method() python passes the the first argument to the funtion the instance self, so either you can make you lambda like this: sigmoid = lambda self, x : 1/(1+np.exp(-x))
or you can do what others have suggested like make it a staticmethod, since staticmethod is a decorator, (function that takes a function) it can be called like this
In [1]: class A:
...: s = staticmethod(lambda x: x)
...: def a(self):
...: print self.s(10)
...:
In [2]: f = A()
In [3]: f.a()
10
Your two sigmoid's are not class methods. This means when you call them they expect Class as the implicit first argument.
This error
TypeError: <lambda>() takes exactly 1 argument (2 given)
occurs on this call
self.some_attr = self.sigmoid(2)
because Class instance object is being passed implicitly along with the int 2. But your sigmoid is defined to accept only one argument.
And I don't think you will get this error
TypeError: unbound method <lambda>() must be called with BackPropogationNetwork instance as first argument (got int instance instead)
with this call
self.some_attr = ClassName.sigmoid()
The error you should get should be something like.
TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'type'
May be you made a copy paste error while typing the question.

Pass in tuple to multi-argument function

The issue here is I want to pass a tuple as an argument to a second function. Before there are outcries of "duplicate!" I have already looked at a post regarding a similar question Expanding tuples into arguments
Here is the code I am testing with:
def producer():
return ('a','b')
def consumer(first, second, third):
print first+second+third
arg = producer()
consumer(*arg, 'c') # expected abc
This outputs the error:
There's an error in your program *** only named arguments may follow *expression
This useful error message has led switch the order of arguments to consumer('c', *arg), but this does not quite solve the issue as it will output 'cab'.
So my question is, is there a better way to pass in a tuple to a multi argument function, and preserve the ordering?
Also for bonus points, what does the '*' operator do? (this was not explained in the previous post)
As the error message states, Python does not allow you to have unnamed arguments after *arg.
Therefore, you need to explicitly name third:
>>> def producer():
... return ('a','b')
...
>>> def consumer(first, second, third):
... print first+second+third
...
>>> arg = producer()
>>> consumer(*arg, third='c')
abc
>>>
If you need to add an argument, concatenate the tuple:
arg += ('c',)
consumer(*arg)
Alternatively, you can name the argument explicitly by using a keyword parameter:
consumer(third='c', *arg)
You cannot put more positional arguments after *arg, these are always added to any explicit positional arguments.

Categories