pass class method to fsolve - python

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.

Related

Python setter without argument?

I'm using the property and setter decorators int he following way:
class PCAModel(object):
def __init__(self):
self.M_inv = None
#property
def M_inv(self):
return self.__M_inv
#M_inv.setter
def set_M_inv(self):
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
self.__M_inv = np.linalg.inv(M)
This generates an error in the __init__ function because my setter is not taking an argument:
TypeError: M_inv() takes 1 positional argument but 2 were given
I don't want to set the M_inv with an argument, since the calculations of M_inv rely solely on other properties of the class object. I could put a dummy argument in the setter:
#M_inv.setter
def set_M_inv(self, foo):
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
self.__M_inv = np.linalg.inv(M)
but that feels dirty. Is there a better way to get around this?
You are missing the point of setters and getters, although the names are pretty self-explanatory. If your parameter is calculated independently from what you are trying to set (you want to ommit the argument in the setter), then a setter is just not needed at all. Since all you wanna do is calculate this parameter for each instance, just calculate and return the value in the getter, so you will be getting the correct, newly-calculated value each time you try to access your parameter.
#property
def M_inv(self):
M = self.var * np.eye(self.W.shape[1]) + np.matmul(self.W.T, self.W)
return np.linalg.inv(M)

TypeError: f2() takes 1 positional argument but 2 were given

My code
class MyClass:
i =123
def f2(a):
global b
print (a)
print (b)
b = 9
x = MyClass()
x.f2(1)
It does not work as expected
TypeError: f2() takes 1 positional argument but 2 were given
Why? How to inspect function and positional arguments?
If I change
x.f2()
<__main__.MyClass object at 0x7fb3f028fbe0>
9
In this case I can not pass a.
One of the 'OOP' reasons to create functions inside a class are inheriting constructors.
You've created the class 'MyClass' and the function f2() is one of the functions inside it.
To convey that the function belongs to/ is a part of the class, you have to pass a default parameter 'self' in the function or it is not recognized by the interpreter.
Coming to your error:
You are passing 1 to the function, but by default there is a 'self' passed to all the class functions. Two solutions possible,
Either make the function static by the decorator
#static
def f2(a):
pass
*this conveys that the function is just inside the class but
doesn't belong to it. It just is there.
pass a 'self' in the function.
def f2(self, a):
pass
Hope it helps.
class MyClass:
i =123
def f2(self,a):
print (a)
x = MyClass()
x.f2(1)
OUTPUT
1
class MyClass:
i =123
def f2(self,a):
global b
print (a)
print (b)
b = 9
write as this ,you will work ok

Passing multiple arguments to pool.map using class function

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]))))

TypeError: unbound method must be called with instance as first argument (got int instance instead) in Python 2

In python 3 the following set of codes works, I wonder why in python 2.7 it gives me a TypeError: unbound method add() must be called with calc instance as first argument(got int instance instead)? how do I resolve this in Python 2.7?
class calc:
def add(x,y):
answer = x + y
print(answer)
def sub(x,y):
answer = x - y
print(answer)
def mult(x,y):
answer = x * y
print(answer)
def div(x,y):
answer = x / y
print(answer)
calc.add(5, 7)
Use staticmethod for python2.7 in your case
class calc:
#staticmethod
def add(x,y):
answer = x + y
print(answer)
#call staticmethod add directly
#without declaring instance and accessing class variables
calc.add(5,7)
Or, Use instance method if you need to call other instance methods or use anything inside class
class calc:
def add(self,x,y):
print(self._add(x,y)) #call another instance method _add
def _add(self,x,y):
return x+y
#declare instance
c = calc()
#call instance method add
c.add(5,7)
Additionally, Use classmethod if you need to use class variables but without declaring instance
class calc:
some_val = 1
#classmethod
def add_plus_one(cls,x,y):
answer = x + y + cls.some_val #access class variable
print(answer)
#call classmethod add_plus_one dircetly
#without declaring instance but accessing class variables
calc.add_plus_one(5,7)
It looks like you are trying to implement a class with a whole bunch of static functions. You can do that, but there really is no need. Unlike other languages, python does not require classes to function. You can define your methods without the class:
def add(x, y):
answer = x + y
print(answer)
add(5, 7)
Because of the way importing works in python, the fundamental unit of namespace is the module, not the class.
from module import some_class # works.
from module import submodule # works.
from module.some_class import method # doesn't work
So, you'll always be better off using modules as they were intended and not using classes as modules :-).

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.

Categories