Using pycharm, I wish to refactor methods into a class. (Staticmethod would do)
Current:
import math
class Solver(object):
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def demo(b, a, c):
d = b ** 2 - 4 * a * c
if d >= 0:
disc = math.sqrt(d)
root1 = (- b + disc) / (2 * a)
root2 = (- b - disc) / (2 * a)
print(root1, root2)
return root1, root2
else:
raise Exception
s = Solver(2, 123, 0.025)
demo(s.b, s.a, s.c)
Desired:
import math
class Solver(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def demo(self, a, b, c):
d = self.b ** 2 - 4 * self.a * self.c
if d >= 0:
disc = math.sqrt(d)
root1 = (- self.b + disc) / (2 * self.a)
root2 = (- self.b - disc) / (2 * self.a)
print(root1, root2)
return root1, root2
else:
raise Exception
Solver(2, 123, 0.025).demo()
I am basically trying to get the opposite functionality to:
"Moving function/method to the top-level"
as described here:
https://www.jetbrains.com/help/pycharm/2017.1/move-refactorings.html
I wouldn't mind on settling for a class with no init params.
By default there is no such option: PyCharm is quite good at refactoring classes and methods, but can't do much with standalone functions.
Though, there is a solution for your problem: regex!
Basically, what you have to do is:
Change function to bounded method (you already did that in your example)
Replace all occurrences of old method call with refactored one.
Here is the regex which would let you do that for aforementioned example:
([\w]+)[ \t]+=[ \t](Solver[ \t]*\(([\d.]+)[ \t]*,[ \t]*([\d.]+)[ \t]*,[ \t]*([\d.]+)[ \t]*\))\n\r?demo[ \t]*\(\1\.b[ \t]*,[ \t]*\1\.a[ \t]*,[ \t]*\1\.c[ \t]*\)
And here is the replacement:
$2\.demo()
Now you can select Edit -> Find -> Replace in Path in PyCharm, check regex option, paste first regex to first field and second to next one. I've tested that locally with one file and it worked well. And here is regex101 example so you can play with it and test it.
This would be useful if you have a lot of usages of that method, otherwise it could be faster to do that manually.
Related
The add and mul definitions here are nonsensical because of their dependence on returning self, causing infinite loops. If they create a new distribution using the lambdas then it works fine, as in my own answer below.
I'm just playing around with classes and overriding trying to build a small statistics tool. However, when I run this code I get stuck in a recursion loop inside the __mul__ call which is being run in the n1.pdf call and I cannot figure out why. I think it has something to do with Python lazily executing the __mul__ instead of doing what I kind of 'wanted' (let's say in the language of CS) which was to create a new pointer to the old function call for pdf that is owned by the new pointer to pdf, and then to set the old pointer (the main .pdf pointer) to the new function.
I think this is quite poorly worded so edits extremely welcome if you understand what I'm asking.
import math
import random
class Distribution:
def __init__(self, pdf, cdf):
self.pdf = pdf
self.cdf = cdf
def pdf(self, x):
return self.pdf(x)
def cdf(self, x):
return self.cdf(x)
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int):
newpdf = lambda x : self.pdf(x) * other
self.pdf = newpdf
newcdf = lambda x : self.cdf(x) * other
self.cdf = newcdf
return self
else:
return NotImplemented
def __add__(self, other):
self.pdf = lambda x : self.pdf(x) + other.pdf(x)
self.cdf = lambda x : self.cdf(x) + other.cdf(x)
return Distribution(self.pdf, self.cdf)
class Normal(Distribution):
def __init__(self, mean, stdev):
self.mean = mean
self.stdev = stdev
def pdf(self, x):
return (1.0 / math.sqrt(2 * math.pi * self.stdev ** 2)) * math.exp(-0.5 * (x - self.mean) ** 2 / self.stdev ** 2)
def cdf(self, x):
return (1 + math.erf((x - self.mean) / math.sqrt(2) / self.stdev)) / 2
def sample(self):
return self.mean + self.stdev * math.sqrt(2) * math.cos(2 * math.pi * random.random())
if __name__ == "__main__":
n1 = Normal(1,2)
n1half = n1 * 0.5
x = n1.pdf(1)
print(x)
p.s. I know that it is no longer a pdf after being multiplied by 0.5, this is not an issue.
class Distribution:
...
def pdf(self, x):
return self.pdf(x)
pdf() calls itself, which calls itself, which calls itself... infinitely.
Same with cdf().
def pdf(self, x):
return self.pdf(x)
def cdf(self, x):
return self.cdf(x)
I assume your intent is to delegate to the attributes. Since they are always assigned, they will be found (assuming you do the lookup on an instance) instead of the class methods (which would straightforwardly be infinite recursion without those attributes); but this in turn means that these class methods are just useless. x.cdf(y), where cdf is a callable instance attribute, just works; there is no need to provide a method as well.
newpdf = lambda x : self.pdf(x) * other
self.pdf = newpdf
I assume your intent is to create a new function that relies upon the existing value of self.pdf. Unfortunately, it doesn't work that way. The problem is that the lambda is late binding. When it executes, that is the time at which it will look up self.pdf... and find itself.
There is a separate problem here, in that you are writing __mul__ and __add__ implementations - that is, the * and + operators, which are supposed to return a new value, and not mutate either operand. (If you wrote a = 3 and b = 4 and then c = a * b, you would be extremely surprised if the values of a or b changed, yes?)
We can solve both problems at once, by simply using the computed pdf and cdf to create a new instance (which we need anyway):
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int):
newpdf = lambda x : self.pdf(x) * other
newcdf = lambda x : self.cdf(x) * other
return Distribution(newpdf, newcdf)
else:
return NotImplemented
Similarly, __add__ should use local variables, rather than modifying self:
def __add__(self, other):
newpdf = lambda x : self.pdf(x) + other.pdf(x)
newcdf = lambda x : self.cdf(x) + other.cdf(x)
return Distribution(newpdf, newcdf)
Note that implementing these methods also gives you the augmented assignment operators *= and += (albeit by creating a new object and rebinding the name).
Let's test it:
if __name__ == "__main__":
n1 = Normal(1,2)
n1half = n1 * 0.5
print(n1.pdf(1))
print(n1half.pdf(1))
n1 += n1
print(n1.pdf(1))
I get:
>py test.py
0.19947114020071635
0.09973557010035818
0.3989422804014327
Thanks for the help #John and #Tom and #bbbbbb... The problem was trying to return self instead of creating a new distribution. If I change the def'n of mul to
def __mul__(self, other):
if isinstance(other, float) or isinstance(other, int):
def newpdf(x):
return self.pdf(x) * other
def newcdf(x):
return self.cdf(x) * other
return Distribution(newpdf, newcdf)
else:
return NotImplemented
Then this solves this problem
I'm trying to solve the tasks (text below), but I have a problem with the second point, i.e. method in it that displays the length of the segment and the positions of the start and end points.-
I don't really know how to write it, Could someone look at the code and give some hints?
Define a Point class with x, y fields and a method displaying the
point's position (eg "point (2,3)").
Then create a class Segment that will inherit from the class point.
Create a method in it that displays the length of the segment and the
positions of the start and end points.
Then define the Triangle class which will contain 3 Points,
automatically determined 3 Sections (walls) of them and included a
method for displaying the surface area of the perimeter.
code:
from math import sqrt, hypot
class Point:
def __init__(self, x_init, y_init):
self.x = x_init
self.y = y_init
def __str__(self):
return "Point(%s,%s)"%(self.x, self.y)
class Segment(Point):
def distance(self): **!-probably a badly written method**
return ((self.x ** 2) + (self.y ** 2)) ** 0.5
def position(self, p): **!-probably a badly written method**
dx = self.x - p.X
dy = self.y - p.Y
return hypot(dx, dy)
class Triangle(Point):
def __init__(self, x, y, z):
Point.__init__(self, x, y)
self.z = z
def __str__(self):
return "Point(x %s ,y %s, z %s )" % (self.x, self.y, self.z)
def __area__(a, b, c):
s = (a + b + c) / 2
return (s * (s - a) * (s - b) * (s - c)) ** 0.5
def __perimeter__(a, b, c):
s = (a + b + c)
return s
Task 2 is just wrong. Segment needs to contain 2 points, so it can't inherit from Point. It should be:
class Segment:
def __init__(self, start, end):
self.start = start
self.end = end
def distance(self):
dist = ((self.start.x - self.end.x) ** 2 + (self.start.y - self.end.y) ** 2) ** 0.5
print(f"distance from {self.start} to {self.end} is {dist}"
I am using Python 2.7, and have a program that solves a recursive optimization problem, that is, a dynamic programming problem. A simplified version of the code is:
from math import log
from scipy.optimize import minimize_scalar
class vT(object):
def __init__(self,c):
self.c = c
def x(self,w):
return w
def __call__(self,w):
return self.c*log(self.x(w))
class vt(object):
def __init__(self,c,vN):
self.c = c
self.vN = vN
def objFunc(self,x,w):
return -self.c*log(x) - self.vN(w - x)
def x(self,w):
x_star = minimize_scalar(self.objFunc,args=(w,),method='bounded',
bounds=(1e-10,w-1e-10)).x
return x_star
def __call__(self,w):
return self.c*log(self.x(w)) + self.vN(w - self.x(w))
p3 = vT(2.0)
p2 = vt(2.0,p3)
p1 = vt(2.0,p2)
w1 = 3.0
x1 = p1.x(w1)
w2 = w1 - x1
x2 = p2.x(w2)
w3 = w2 - x2
x3 = w3
x = [x1,x2,x3]
print('Optimal x when w1 = 3 is ' + str(x))
If enough periods are added, the program can begin to take a long time to run. When x1 = p1.x(w1) is run, p2 and p3 are being evaluated multiple times by the minimize_scalar. Also, when x2 = p2(w2) is run, we know the ultimate solution will involve evaluating p2 and p3 in ways that were already done in the first step.
I have two questions:
What's the best way to use a memoize wrapper on the vT and vt classes to speed up this program?
When minimize_scalar is run, will it benefit from this memoization?
In my actually application, the solutions can take hours to solve currently. So, speeding this up would be of great value.
UPDATE: A response below points out that the example above could be written without the use of classes, and the normal decoration can be used for functions. In my actual application, I do have to use classes, not function. Moreover, my first question is whether the call of the function or method (when it's a class) inside of minimize_scalar will benefit from the memoization.
I found out the answer. Below is an example of how to memoize the program. There may be an even more efficient approach, but this approach memoizes the methods of the class. Furthermore, when minimize_scalar is run, the memoize wrapper records the results each time it evaluates the functions:
from math import log
from scipy.optimize import minimize_scalar
from functools import wraps
def memoize(obj):
cache = obj.cache = {}
#wraps(obj)
def memoizer(*args, **kwargs):
key = str(args) + str(kwargs)
if key not in cache:
cache[key] = obj(*args, **kwargs)
return cache[key]
return memoizer
class vT(object):
def __init__(self,c):
self.c = c
#memoize
def x(self,w):
return w
#memoize
def __call__(self,w):
return self.c*log(self.x(w))
class vt(object):
def __init__(self,c,vN):
self.c = c
self.vN = vN
#memoize
def objFunc(self,x,w):
return -self.c*log(x) - self.vN(w - x)
#memoize
def x(self,w):
x_star = minimize_scalar(self.objFunc,args=(w,),method='bounded',
bounds=(1e-10,w-1e-10)).x
return x_star
#memoize
def __call__(self,w):
return self.c*log(self.x(w)) + self.vN(w - self.x(w))
p3 = vT(2.0)
p2 = vt(2.0,p3)
p1 = vt(2.0,p2)
x1 = p1.x(3.0)
len(p3.x.cache) # how many times was p3.x evaluated?
Out[3]: 60
x2 = p2.x(3.0 - x1)
len(p3.x.cache) # how many additional times was p3.x evaluated?
Out[5]: 60
I am currently creating a class in python to make a quadratic equation. I wrote down a discriminant function within the class, and I'm trying to call on it within the roots function, however, I'm not sure how to do it for certain. I am getting an attribute error.
AttributeError: 'QuadraticEquation' object has no attribute 'discrimiant'
def discriminant(self):
return ((self.b)**2) - (4 * self.a * self.c)
def root1(self):
if self.discrimiant() < 0:
return None
else:
return (-self.b + math.sqrt(self.discriminant())) / (2 * self.a)
def root2(self):
if self.discrimiant() < 0:
return None
else:
return (-self.b - math.sqrt(self.discriminant())) / (2 * self.a)
There is a spelling mistake in your code. discriminant, not discrimiant. Here is a working code -
class QuadraticEquation:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def discriminant(self):
return ((self.b)**2) - (4 * self.a * self.c)
def root1(self):
if self.discriminant() < 0:
return None
else:
return (-self.b + math.sqrt(self.discriminant())) / (2 * self.a)
def root2(self):
if self.discriminant() < 0:
return None
else:
return (-self.b - math.sqrt(self.discriminant())) / (2 * self.a)
a = QuadraticEquation(1,2,3)
print a.root1()
print a.root2()
print a.discriminant()
I have the following code:
class Quadratic:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def function(self, x):
self.F(x) = a*(x**2) + b*x + c
return F(x)
def table(self, lower, upper, varz):
inc = np.absolute(upper-lower) / varz
print inc
for i in range(0 , varz - 1):
self.F(lower)
lower = lower + inc
#lower bound,upper bound, number of values
def roots():
x1 = (-b + math.sqrt(b**2 - 4*a*c)) / (2*a)
x2 = (-b - math.sqrt(b**2 - 4*a*c)) / (2*a)
return x1, x2
def dump(self):
print self.n
Whenever I try and run this script, I get the following:
line 15
self.F(x) = a*(x**2) + b*x + c
SyntaxError: can't assign to function call
Any help or ideas would be greatly appreciated.
It is not clear (to me at least) what it is you're trying to achieve, but perhaps it is as simple as this:
def F(self, x):
return self.a * (x ** 2) + self.b * x + c
As you might have guessed, F(x) is a function call. You're calling the function F, which does not actually exist, passing it the argument x, which does not actually exist either. You need to give your variables legal names, like f_of_x.
try with:
def __init__(self, a,b,c):
self.a = a
self.b = b
self.c = c
self.F = lambda x: a*(x**2)+b*x+c
and discard the function() method