Decorators in PyMC - python

I have three question regarding decorators which I am not able to find answer to :
Q1)What do the arguments to decorators in PyMC (#Deterministic, #Stochastic) denote ?
Q2)
#pymc.stochastic(dtype=int)
def switchpoint(value=10, t_l=0, t_h=110):
def logp(value, t_l, t_h):
if value > t_h or value < t_l:
return -np.inf
else:
return -np.log(t_h - t_l + 1)
def random(t_l, t_h):
from numpy.random import random
return np.round( (t_l - t_h) * random() ) + t_l
1)print switchpoint.logp #prints log-probability as expected
2)print switchpoint.random #does not generate the random number
3)print switchpoint.random() # generates a random number
4)print switchpoint.logp() #error
If 2 did not work and 3 worked then 1 should not have worked and instaed 4 should have worked (which is opposite of what I observed). Can someone explain what is going on ?
Q3)
#pymc.stochastic(dtype=int)
def switchpoint(value=1900, t_l=1851, t_h=1962):
if value > t_h or value < t_l:
# Invalid values
return -np.inf
else:
# Uniform log-likelihood
return -np.log(t_h - t_l + 1)
Here it is not specified that it is logp still if I type switchpoint.logp, this piece of code is executed ?

Q1) The meaning of all the arguments to stochastic is documented here. The arguments to deterministic are the same, plus the additional ones documented here.
Q2) The difference in behavior is that there is some magic inside PyMC that actually executes the switchpoint.logp function and turns it into a Python property, while switchpoint.random doesn't get this treatment, and is kept as a function.
If you're curious about what's actually going on, here's some of the relevant the source:
def get_logp(self):
if self.verbose > 1:
print '\t' + self.__name__ + ': log-probability accessed.'
logp = self._logp.get()
if self.verbose > 1:
print '\t' + self.__name__ + ': Returning log-probability ', logp
try:
logp = float(logp)
except:
raise TypeError, self.__name__ + ': computed log-probability ' + str(logp) + ' cannot be cast to float'
if logp != logp:
raise ValueError, self.__name__ + ': computed log-probability is NaN'
# Check if the value is smaller than a double precision infinity:
if logp <= d_neg_inf:
if self.verbose > 0:
raise ZeroProbability, self.errmsg + ": %s" %self._parents.value
else:
raise ZeroProbability, self.errmsg
return logp
def set_logp(self,value):
raise AttributeError, 'Potential '+self.__name__+'\'s log-probability cannot be set.'
logp = property(fget = get_logp, fset=set_logp, doc="Self's log-probability value conditional on parents.")
There's some other stuff going on there, like during the logp function into something called a LazyFunction, but that's the basic idea.
Q3) The stochastic decorator has some (more) magic in it that uses code introspection to determine if random and logp sub functions are defined inside switchpoint. If they are, it uses the logp sub-function to compute logp, if not, it just uses switchpoint itself. That source code for that is here:
# This gets used by stochastic to check for long-format logp and random:
if probe:
# Define global tracing function (I assume this is for debugging??)
# No, it's to get out the logp and random functions, if they're in there.
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
kwds.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
# Get the functions logp and random (complete interface).
# Disable special methods to prevent the formation of a hurricane of Deterministics
cur_status = check_special_methods()
disable_special_methods()
try:
__func__()
except:
if 'logp' in keys:
kwds['logp']=__func__
else:
kwds['eval'] =__func__
# Reenable special methods.
if cur_status:
enable_special_methods()
for key in keys:
if not kwds.has_key(key):
kwds[key] = None
for key in ['logp', 'eval']:
if key in keys:
if kwds[key] is None:
kwds[key] = __func__
Again, there's some more stuff going on, and it's fairly complicated, but that's the basic idea.

Related

python2 .x to python 3.x : '>' not supported between instances of 'float' and 'NoneType'

The following error occurs when executing (Python 2.x code) in python 3.x version:
" File "C:\Users\silen\Documents\♠ Asset Allocation
Project\HRP(Hierarchical Risk Parity)_py2.7\Python3.7\CLA.py", line
47, in solve
if (self.l[-1] is None or l<self.l[-1]) and l>l_out:l_out,i_out=l,i
TypeError: '>' not supported between instances of 'float' and 'NoneType' "
What is the solution?
class CLA:
def __init__(self,mean,covar,lB,uB):
# Initialize the class
self.mean=mean
self.covar=covar
self.lB=lB
self.uB=uB
self.w=[] # solution
self.l=[] # lambdas
self.g=[] # gammas
self.f=[] # free weights
def solve(self):
# Compute the turning points,free sets and weights
f,w=self.initAlgo()
self.w.append(np.copy(w)) # store solution
self.l.append(None)
self.g.append(None)
self.f.append(f[:])
while True:
#1) case a): Bound one free weight
l_in=None
if len(f)>1:
covarF,covarFB,meanF,wB=self.getMatrices(f)
covarF_inv=np.linalg.inv(covarF)
j=0
for i in f:
l,bi=self.computeLambda(covarF_inv,covarFB,meanF,wB,j,[self.lB[i],self.uB[i]])
if l>l_in:l_in,i_in,bi_in=l,i,bi
j+=1
#2) case b): Free one bounded weight
l_out=None
if len(f)<self.mean.shape[0]:
b=self.getB(f)
for i in b:
covarF,covarFB,meanF,wB=self.getMatrices(f+[i])
covarF_inv=np.linalg.inv(covarF)
l,bi=self.computeLambda(covarF_inv,covarFB,meanF,wB,meanF.shape[0]-1, \
self.w[-1][i])
if (self.l[-1] is None or l<self.l[-1]) and l>l_out:l_out,i_out=l,i
if (l_in is None or l_in < 0) and (l_out is None or l_out < 0):
#3) compute minimum variance solution
self.l.append(0)
covarF,covarFB,meanF,wB=self.getMatrices(f)
covarF_inv=np.linalg.inv(covarF)
meanF=np.zeros(meanF.shape)
else:
#4) decide lambda
if l_in>l_out:
self.l.append(l_in)
f.remove(i_in)
w[i_in]=bi_in # set value at the correct boundary
else:
self.l.append(l_out)
f.append(i_out)
covarF,covarFB,meanF,wB=self.getMatrices(f)
covarF_inv=np.linalg.inv(covarF)
#5) compute solution vector
wF,g=self.computeW(covarF_inv,covarFB,meanF,wB)
for i in range(len(f)):w[f[i]]=wF[i]
self.w.append(np.copy(w)) # store solution
self.g.append(g)
self.f.append(f[:])
if self.l[-1]==0:break
#6) Purge turning points
self.purgeNumErr(10e-10)
self.purgeExcess()
def getCLA(cov, **kargs):
# Compute CLA's minimum variance portfolio
mean = np.arange(cov.shape[0]).reshape(-1, 1)
# Not used by C portf
lB = np.zeros(mean.shape)
uB = np.ones(mean.shape)
cla = CLA.CLA(mean, cov, lB, uB)
cla.solve()
return cla.w[-1].flatten()
w_ = pd.Series(getCLA(cov=cov_, corr=corr_))
You can't compare disparate types in Python 3. Luckily, in this case it looks like all new ls are float, and you just want a "smaller than anything" value as the initializer, and that's easy enough for float with -inf:
from math import inf
...
l_in = -inf # Instead of None

Facing issues in writing def inside if in python

This I need to do
def x1(ap,dp,ph,e1,e2,e3,e4,e5,y):
if Delta(ap,dp,ph,e1,e2,e3,e4,e5,y) >= 0:
return 2*(b(ap,dp,ph,e1,e2,e3,e4,e5,y)**3) - 9*a*b(ap,dp,ph,e1,e2,e3,e4,e5,y)*c(ap,dp,ph,e1,e2,e3,e4,e5,y) + 27*(a**2)*d(ap,dp,ph,e1,e2,e3,e4,e5,y)
else:
return None
def y1(ap,dp,ph,e1,e2,e3,e4,e5,y):
if Delta(ap,dp,ph,e1,e2,e3,e4,e5,y) >= 0:
return 3*np.sqrt(3)*a*np.sqrt(Delta(ap,dp,ph,e1,e2,e3,e4,e5,y))
else:
return None
This is creating a problem, output:
return np.sqrt(x1(ap,dp,ph,e1,e2,e3,e4,e5,y)**2+y1(ap,dp,ph,e1,e2,e3,e4,e5,y)**2)
TypeError: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int'
so I want to write it like
def Delta(ap,dp,ph,e1,e2,e3,e4,e5,y):
Delta = 18*a*b(ap,dp,ph,e1,e2,e3,e4,e5,y)*c(ap,dp,ph,e1,e2,e3,e4,e5,y)*d(ap,dp,ph,e1,e2,e3,e4,e5,y) - 4*(b(ap,dp,ph,e1,e2,e3,e4,e5,y)**3)*d(ap,dp,ph,e1,e2,e3,e4,e5,y) + (b(ap,dp,ph,e1,e2,e3,e4,e5,y)**2)*(c(ap,dp,ph,e1,e2,e3,e4,e5,y)**2) - 4*a*(c(ap,dp,ph,e1,e2,e3,e4,e5,y)**3) - 27*(a**2)*(d(ap,dp,ph,e1,e2,e3,e4,e5,y)**2)
if Delta(ap,dp,ph,e1,e2,e3,e4,e5,y) >= 0:
def x1(ap,dp,ph,e1,e2,e3,e4,e5,y):
return 2*(b(ap,dp,ph,e1,e2,e3,e4,e5,y)**3) - 9*a*b(ap,dp,ph,e1,e2,e3,e4,e5,y)*c(ap,dp,ph,e1,e2,e3,e4,e5,y) + 27*(a**2)*d(ap,dp,ph,e1,e2,e3,e4,e5,y)
def y1(ap,dp,ph,e1,e2,e3,e4,e5,y):
return 3*np.sqrt(3)*a*np.sqrt(Delta(ap,dp,ph,e1,e2,e3,e4,e5,y))
return x1, y1
but it is also making a definition error.
Actually by defining such functions i have to construct some new functions like U1(),U2(),U3() using the x1(),y1() and atlast I have to satisfy the best-fit values for U1(),U2(),U3() for this I am doing a for loop run of the variables ap,dp.... Etc. In range (-10,10) to find the all possible set of variables which satisfies the best fit
Your definition error appears to be due to improper indentation. You're returning x1 and y1 outside of the if statement where they're defined.
Your TypeError TypeError: unsupported operand type(s) for ** or pow(): 'NoneType' and 'int' implies that either x1(...) or y1(...) returns None, which you allow in your function definition. I'd suggest changing that to explicitly throw an error, assuming None is not a desirable return value. Looking at your code, it seems that Delta(...) is negative when it shouldn't be.
def x1(ap,dp,ph,e1,e2,e3,e4,e5,y):
"x1 is a function that does something"
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
a = 5 # keep `a` in local scope, or include it as a function argument
# e.g., along with ap,dp,ph,e1,e2,e3,e4,e5,y
if Delta(**keywordargs) >= 0:
return 2*(b(**keywordargs)**3) - 9*a*b(**keywordargs)*c(**keywordargs) + 27*(a**2)*d(**keywordargs)
else:
raise ValueError(f"Delta should be non-negative, but instead was {Delta(**keywordargs)}")
def y1(ap,dp,ph,e1,e2,e3,e4,e5,y):
"y1 is a function that does something"
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
a = 5 # keep `a` in local scope, or include it as a function argument
if Delta(**keywordargs) >= 0:
return 3*np.sqrt(3)*a*np.sqrt(Delta(**keywordargs))
else:
raise ValueError(f"Delta should be non-negative, but instead was {Delta(**keywordargs)}")
And...
def Delta(ap,dp,ph,e1,e2,e3,e4,e5,y):
"Delta does some crazy stuff"
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
a = 5 # keep `a` in local scope, or include it as a function argument
# Avoid defining variables with the same name as their function, to avoid confusion and accidental recursion...
delta_val = 18*a*b(**keywordargs)*c(**keywordargs)*d(**keywordargs) \
- 4*(b(**keywordargs)**3)*d(**keywordargs) \
+ (b(**keywordargs)**2)*(c(**keywordargs)**2) \
- 4*a*(c(**keywordargs)**3) \
- 27*(a**2)*(d(**keywordargs)**2)
if delta_val >= 0:
def x1(ap,dp,ph,e1,e2,e3,e4,e5,y):
return 2*(b(ap,dp,ph,e1,e2,e3,e4,e5,y)**3) - 9*a*b(ap,dp,ph,e1,e2,e3,e4,e5,y)*c(ap,dp,ph,e1,e2,e3,e4,e5,y) + 27*(a**2)*d(ap,dp,ph,e1,e2,e3,e4,e5,y)
def y1(ap,dp,ph,e1,e2,e3,e4,e5,y):
return 3*np.sqrt(3)*a*np.sqrt(Delta(ap,dp,ph,e1,e2,e3,e4,e5,y))
return x1(**keywordargs), y1(**keywordargs)
else:
raise ValueError(f"Delta should be non-negative, but instead was {delta_val}")
Also, what is a? I hope it's not a mutable global variable that gets changed throughout your application... because that will create hard to find bugs. I'd recommend avoiding having functions depend on variables that are defined outside of the function (or class containing the function) if you can.
Also, for the love of all that is sacred, make your function names longer or capitalized or something, to help distinguish them from all your one letter variable names. Also, consider having more descriptive variable names, or include comments. Code is read more than it is written. You don't want to make debugging harder than it has to be.
EDIT
After looking at your code a second time, it would be even better if you simplified things further and kept all your functions separate from each other.
# Define your functions separately
def X1(ap,dp,ph,e1,e2,e3,e4,e5,y,a,a):
"""X1 is a function that does something
Input: ap,dp,ph,e1,e2,e3,e4,e5,y,a
Output: some crazy number
Dependencies: b(), c(), d()
"""
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y,a]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y,a".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
result = 2*(b(**keywordargs)**3) \
- 9*a*b(**keywordargs)*c(**keywordargs) \
+ 27*(a**2)*d(**keywordargs)
return result
def Y1(ap,dp,ph,e1,e2,e3,e4,e5,y,a):
"""Y1 is a function that does something
Input: ap,dp,ph,e1,e2,e3,e4,e5,y,a
Output: some crazy number
Dependencies: Delta(), b(), c(), d()
"""
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y,a]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y,a".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
if Delta(**keywordargs) >= 0:
return 3*np.sqrt(3)*a*np.sqrt(Delta(**keywordargs))
else:
raise ValueError(f"Delta should be non-negative, but instead was {Delta(**keywordargs)}")
def Delta(ap,dp,ph,e1,e2,e3,e4,e5,y,a):
"""Delta does some crazy stuff
Input: ap,dp,ph,e1,e2,e3,e4,e5,y,a
Output: some crazy number
Dependencies: b(), c(), d()
"""
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y,a]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y,a".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
# Avoid defining variables with the same name as their function, to avoid confusion and accidental recursion...
delta_val = 18*a*b(**keywordargs)*c(**keywordargs)*d(**keywordargs) \
- 4*(b(**keywordargs)**3)*d(**keywordargs) \
+ (b(**keywordargs)**2)*(c(**keywordargs)**2) \
- 4*a*(c(**keywordargs)**3) \
- 27*(a**2)*(d(**keywordargs)**2)
return delta_val
# Run your already defined functions
if (__name__ == "__main__"):
# ... give values to ap,dp,ph,e1,e2,e3,e4,e5,y,a
variables = [ap,dp,ph,e1,e2,e3,e4,e5,y,a]
varnames = "ap,dp,ph,e1,e2,e3,e4,e5,y,a".split(',')
keywordargs = {k:a for (k,a) in zip(varnames, variables)}
if Delta(**keywordargs) >= 0:
x1,y1 = X1(**keywordargs), Y1(**keywordargs)
Basically, you want to keep the logic of your program separate from individual function definitions. Build your program up from smaller, simpler functions that don't depend on outside global variables or functions.
Also capitalize B(),C(),D(), or give them different names. Do something to show that they're functions and not variables.

What is the most computationally efficient method to recursively calculate the Fibonacci sequence?

Here is the code I currently have.
def fibonacci(n):
if n == 1:
return 1
elif n == 2:
return 1
else:
value = fibonacci(n - 1) + fibonacci(n - 2)
return value
This currently takes quite some time to calculate values greater than n = 30. Is there a more computationally efficient method to accomplish this?
Adding a value cache to trade some memory for a reduced processing time can be a useful method. A purely recursive program will attempt to calculate values over and over again, however this takes time for larger values. If the values do not change, then storing them can be helpful. It is important to note, however, that should values be volatile you might need a different approach.
fibonacci_value_cache = {}
def fibonacci(n):
if n == 1:
return 1
elif n == 2:
return 1
elif n in fibonacci_value_cache:
return fibonacci_value_cache[n]
else:
fibonacci_value_cache[n] = fibonacci(n - 1) + fibonacci(n - 2)
return fibonacci_value_cache[n]
n = 100
print("Fib " + str(n) + ": " + str(fibonacci(n)))
Here, we check if the value is in the dictionary and return it if it is, otherwise we calculate it and add it to the dictionary. This means that we are make better use of the processor by not calculating the same value multiple times.
There's a recipe for a decorator that uses as an example exactly what you want. It's named Memoize in the PythonDecoratorLibrary.
It may seem like overkill, but having the memoized decorator around could be useful for other future tasks. That said, here it is in its entirety (although I changed the print at the end):
import collections
import functools
class memoized(object):
'''Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, collections.Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return functools.partial(self.__call__, obj)
#memoized
def fibonacci(n):
"Return the nth fibonacci number."
if n in (0, 1):
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(12))
Using idea of Dynamic Programming, and store the intermediate results to save computational cost, it could be very efficient. The code below cost less than 0.02s for n=10000 on my laptop.
def fib(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
for i in range(n):
result.append(b)
a, b = b, a + b
return result
No need for caching/memoization. Here's a Python 3 implementation that expresses the Fibonacci sequence as powers of a matrix, then does efficient exponentiation via halving and squaring. The result is O(log n) in both time and storage.
def matrix_fib(n):
if n == 1:
return [0,1]
else:
f = matrix_fib(n // 2)
c = f[0] * f[0] + f[1] * f[1]
d = f[1] * (f[1] + 2 * f[0])
return [c,d] if (n & 1) == 0 else [d,c+d]
def fib(n):
return n if n == 0 else matrix_fib(n)[1]
print(fib(1000000))
On my laptop this coughs up the value of the millionth Fibonacci number in a little over half a second, and the bulk of that is probably in the big integer arithmetic and formatting of the output—the result is ridiculously large. You don't need to worry about stack overflow, though. The call stack depth for this is only log2(1000000) = 20.

Pythonic way to have a function return value in proper units

Objective: return a value from a function in the units (or any trivial modification) requested by the caller.
Background:
I am running Python 2.7 on a Raspberry Pi 3, and use the function distance() to get the distance a rotary encoder has turned. I need this distance in different units depending on where the function is called. How then, should this be written pythonically (i.e. short, and easily maintained).
First Attempt:
My first attempt was to use a unit of meters in the function, and have a long elif tree to select the right units to return in.
def distance(units='m'):
my_distance = read_encoder()
if units == 'm':
return my_distance * 1.000
elif units == 'km':
return my_distance / 1000.
elif units == 'cm':
return my_distance * 10.00
elif units == 'yd':
return my_distance * 1.094
else:
return -1
The nice thing about this approach is that it has a way to recognize a unit that isn't available.
Second Attempt:
My second attempt was to create a dictionary to contain various multipliers.
def distance(units='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
'yd': 1.094
}
try:
return read_encoder() * mulitplier[units]
except KeyError:
return -1
Here, unrecognized units are caught with a KeyError.
Relevance:
I know of existing libraries like Pint, but am looking for a solution to this programming problem. When you have a function in Python, and you need to make slight modifications to the output in a reusable way. I have other functions such as speed() that use 'm/s' as a base unit, and need a similar units argument. From my experience, a well-structured program does not involve a paragraph of elif branches before every return statement. In this case, if I wanted to change how I calculate the units, I would have to carefully grep through my code, and make sure I change how the units are calculated at every instance. A proper solution would only require changing the calculation once.
This is possibly too broad, but it is a pattern I keep running into.
How about, using a decorator:
def read_encoder():
return 10
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units):
return multiplier.get(units, -1) * fn(units)
return deco
#multiply
def distance(units='m'):
my_distance = read_encoder()
return my_distance
print distance("m")
print distance("yd")
print distance("feet")
output:
10.0
10.94
-10
or, as a more generic wrapper that goes around any unit-less function:
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00,
'yd': 1.094,
}
def multiply(fn):
def deco(units, *args, **kwds):
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
#multiply
def read_encoder(var):
#I've added a variable to the function just to show that
#it can be passed through from the decorator
return 10 * var
print read_encoder("m", 1)
print read_encoder("yd", 2)
print read_encoder("feet", 3)
output:
10.0
21.88
-30
The bit about raise a KeyError vs -1 is a question of taste. Personally, I'd return * 1 if not found (if the receiver didn't care). Or throw a KeyError. The -1 isn't obviously useful.
Last iteration, making the unit parameter optional:
def multiply(fn):
def deco(*args, **kwds):
#pick up the unit, if given
#but don't pass it on to read_encoder
units = kwds.pop("units", "m")
return multiplier.get(units, -1) * fn(*args, **kwds)
return deco
#multiply
def read_encoder(var):
return 10 * var
print read_encoder(1, units="yd")
print read_encoder(2)
print read_encoder(3, units="feet")
10.94
20.0
-30
The dictionary lookup is good, but don't return a sentinel value to signal an error; just raise an appropriate exception. It could be as simple (though opaque) as letting the KeyError in your lookup propagate. A better solution, though, is to raise a custom exception:
class UnknownUnitError(ValueError):
pass
def distance(unit='m'):
multiplier = {
'm': 1.000,
'km': 0.001,
'cm': 10.00
}
try:
unit = multiplier[unit]
except KeyError:
# Include the problematic unit in the exception
raise UnknownUnitError(unit)
return read_encoder() * unit
For your example it could be:
class DistanceUnits():
"""
Enum class for indicating measurement units and conversions between them.
Holds all related logic.
"""
M = 'm'
KM = 'km'
CM = 'cm'
def distance(units=DistanceUnits.M):
multiplier = {
DistanceUnits.M: 1.000,
DistanceUnits.KM: 0.001,
DistanceUnits.CM: 10.00
}
return read_encoder() * mulitplier[units] if units in multiplier else -1
But, it can be reasonable to move multipliers outside of distance function and make it part of DistanceUnits.
UPD: there are a lot of different ways of 'how to ..' and all of them depends on you needs, but there is one main principle DRY. Even lots of elifs can be good enough (creating dictionary instance consume some ram on each function call..) if you don't forget do not repeat youself.

why is there this TypeError?

i am trying to find the square root a number through the function sqrt(a). fixedPoint(f, epsilon) is a helper function. the problem is that i get a this TypeError: 'float' object is not callable. i am new to programming, so if anybody can help and find were is the bug and explain what does this error mean ??
def fixedPoint(f, epsilon):
"""
f: a function of one argument that returns a float
epsilon: a small float
returns the best guess when that guess is less than epsilon
away from f(guess) or after 100 trials, whichever comes first.
"""
guess = 1.0
for i in range(100):
if abs(f(guess) - guess) < epsilon:
return guess
else:
guess = f(guess)
return guess
def sqrt(a):
def tryit(x):
return 0.5 * (a/x + x)
return fixedPoint(tryit(a), 0.0001)
In sqrt function, the code is passing the return value of the tryit (which is a float value), not tryit itself.
Passing the function itself will solve the problem.
def sqrt(a):
def tryit(x):
return 0.5 * (a/x + x)
return fixedPoint(tryit, 0.0001)

Categories