I want to translate some Haskell code into Python.
The Haskell classes/instances look like:
{-# LANGUAGE MultiParamTypeClasses #-}
module MyModule where
class Example a b where
doSomething :: a -> b -> Bool
doSomethingElse :: a -> b -> Int
instance Example Int Int where
doSomething a b = (a + b * 2) > 5
doSomethingElse a b = a - b * 4
Is there a way in Python to approximate the Haskell class/instance construct?
What is the least offensive way to translate this into Python?
This doesn't really have an analogue in Python, but you can fake it:
def int_int_doSomething(a, b):
return (a + b * 2) > 5
def int_int_doSomethingElse(a, b):
return a - b * 4
Example = {}
Example[(int, int)] = (int_int_doSomething, int_int_doSomethingElse)
def doSomething(a, b):
types = type(a), type(b)
return Example[types][0](a, b)
def doSomethingElse(a, b):
types = type(a), type(b)
return Example[types][1](a, b)
All you have to do is add new values to Example for each type combination you want to have. You could even throw in some extra error handling in doSomething and doSomethingElse, or some other methods to make it easier. Another way would be to make an object that keeps track of all of these and lets you add new types to the map in a more managed way, but it's just more bookkeeping on top of what I've already shown.
Keep in mind that this is essentially how Haskell does it, too, except the checks are performed at compile time. Typeclasses are really nothing more than a dictionary lookup on the type to pick the appropriate functions to insert into the computation. Haskell just does this automatically for you at compile time instead of you having to manage it yourself like you do in Python.
To add that bookkeeping, you could do something like the following, keeping it in its own module and then it'll only (by default) export the symbols in __all__. This keeps things looking more like the Haskell version:
class _Example(object):
def __init__(self, doSomething, doSomethingElse):
self.doSomething = doSomething
self.doSomethingElse = doSomethingElse
ExampleStore = {}
def register(type1, type2, instance):
ExampleStore[(type1, type2)] = instance
def doSomething(a, b):
types = type(a), type(b)
return ExampleStore[types].doSomething(a, b)
def doSomethingElse(a, b):
types = type(a), type(b)
return ExampleStore[types].doSomethingElse(a, b)
def Example(type1, type2, doSomething, doSomethingElse):
register(type1, type2, _Example(doSomething, doSomethingElse))
__all__ = [
'doSomethingElse',
'doSomethingElse',
'Example'
]
Then you can make instances like
Example(int, int,
doSomething=lambda a, b: (a + b * 2) > 5,
doSomethingElse=lambda a, b: a - b * 4
)
Which looks almost like Haskell.
You don't have parametric types in Python, as it's dynamically typed. Also the distinction between classes and instances is clear in Python, but as classes are themselves "live objects", the distinction of usage might be a little bit blurred sometimes...
For your case, a classical implementation might go as:
#you don't really need this base class, it's just for documenting purposes
class Example:
def doSomething(self, a, b):
raise "Not Implemented"
def doSomethingElse(self, a, b):
raise "Not Implemented"
class ConcreteClass(Example):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def doSomething(self, a, b):
return (a + b * self.x) > self.y
def doSomethingElse(self, a, b):
return a - b * self.z
instance = ConcreteClass((2, 5, 4)
but I personally dislike that convoluted style, so you might just go with something more lightweight, like:
from collections import namedtuple
Example = namedtuple('Example', 'doSomething doSomethingElse')
instance = Example((lambda a, b: (a + b * 2) > 5),
(lambda a, b: a - b *4 ))
And of course, rely on duck typing and usually "let it crash". The lack of type safety should be made up with extensive unit testing.
Related
I have a large number of blending functions:
mix(a, b)
add(a, b)
sub(a, b)
xor(a, b)
...
These functions all take the same inputs and provide different outputs, all of the same type.
However, I do not know which function must be run until runtime.
How would I go about implementing this behavior?
Example code:
def add(a, b):
return a + b
def mix(a, b):
return a * b
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = run(add, a, b) # I need a run function
I have looked online, but most searches lead to either running functions from the console, or how to define a function.
I'm not really big fan of using dictionary in this case so here is my approach using getattr. although technically its almost the same thing and principle is also almost the same, code looks cleaner for me at least
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
# Required blend -> decided by other code
blend_name = "add"
a = input("Some input")
b = input("Some other input")
method = getattr(operators, blend_name)
result = method(operators, a, b)
print(result) #prints 12 for input 1 and 2 for obvious reasons
EDIT
this is edited code without getattr and it looks way cleaner. so you can make this class the module and import as needed, also adding new operators are easy peasy, without caring to add an operator in two places (in the case of using dictionary to store functions as a key/value)
class operators():
def add(self, a, b):
return (a + b)
def mix(self, a, b):
return(a * b)
def calculate(self, blend_name, a, b):
return(operators.__dict__[blend_name](self, a, b))
# Required blend -> decided by other code
oper = operators()
blend_name = "add"
a = input("Some input")
b = input("Some other input")
result = oper.calculate(blend_name, a, b)
print(result)
You can create a dictionary that maps the function names to their function objects and use that to call them. For example:
functions = {"add": add, "sub": sub} # and so on
func = functions[blend_name]
result = func(a, b)
Or, a little more compact, but perhaps less readable:
result = functions[blend_name](a, b)
You could use the globals() dictionary for the module.
result = globals()[blend_name](a, b)
It would be prudent to add some validation for the values of blend_name
my code is probably very unconventional since I am self-taught, any help or tips are appreciated.
I tried to speed up my python code using cython and have had some very good results only using a little bit of static typing here and there. However, I think there is much room for improvement.
I'm using a few classes to do similar operations in slightly different fashion, depending on their type, like this:
class A:
def __init__(self, A, B, C):
self.A = A
self.B = B
self.C = C
self.combined = 0
def UpdateCombined(self):
self.combined = A + B + C
return
class B:
def __init__(self, A, B, C):
self.A = A
self.B = B
self.C = C
self.combined = 0
def UpdateCombined(self):
self.combined = A * B * C
return
I looked into interfaces, because they seemed like the conventional way of implementing classes with the same type of methods and attributes, but different behaviour, but I came to the conclusion, that using interfaces through inheritance in my case is just unnecessary boilerplate and not really useful in anyway (if I have a interface class with NotImplemented everywhere, it really isn't any help, is it?)
I have quite a bit operations, where I have a list of instances of these classes and want to perform the same operation on all of them:
a, b, c = A(1, 3, 2)
x, y, z = B(5, 4, 3)
object_list = [a, b, c, x, y, z]
for SomeObject in object_list:
SomeObject.UpdateCombined()
My question now is, how could I go about cleanly improving this with cython? I think, probably use cdef class to make A and B extensions types, staticly type their arguements, that would be my first move. But how to I improve the latter code part, can I use extension types for static typing?
Thanks for any help in advance, any comments are appreciated
I'm trying to write my own "fraction" class that takes in two numerical objects: the numerator and denominator. However, depending on the data type for the two arguments, I'd like the object to initialize in different ways.
For example, if I declare x = Frac(2,5) I want x to stay a Frac type. Whereas if I declare y = Frac(2.1, 5) I want y to be cast to a float with the value of 0.42, rather than Frac(21,50).
What would be the right way to go about something like this?
This feels very similar to the scenario in which a tuple with a single object simply returns the original object. This means that x = ("cat") sets x to be a str type, rather than a tuple type.
There are two options.
1. Factory method
x = Frac.create_by_type(2, 5)
y = Frac.create_by_type(2.1, 5)
Implementation example:
class Frac:
...
#classmethod
def create_by_type(cls, a, b):
if isinstance(a, float):
return a / b
return cls(a, b)
If you want to use Frac constructor directly,
2. Overriding Frac.__new__ method
class Frac:
def __new__(cls, a, b):
if isinstance(a, float):
return a / b
return super().__new__(cls)
def __init__(self, a, b):
self.a = a
self.b = b
f1 = Frac(2, 5)
f2 = Frac(2.1, 5)
print(type(f1))
print(type(f2))
print(f1.a, f1.b)
output:
<class '__main__.Frac'>
<class 'float'>
2 5
But overriding __new__ method might be tricky, so I'm not sure to recommend it.
I understand from this answer why the warning exists. However, why would the default value of it be 2?
It seems to me that classes with a single public method aside from __init__ are perfectly normal! Is there any caveat to just setting
min-public-methods=1
in the pylintrc file?
The number 2 is completely arbitrary. If min-public-methods=1 is a more fitting policy for your project and better matches your code esthetic opinions, then by all means go for it. As was once said, "Pylint doesn't know what's best".
For another perspective, Jack Diederich gave a talk at PyCon 2012 called "Stop Writing Classes".
One of his examples is the class with a single method, which he suggests should be just a function. If the idea is to set up an object containing a load of data and a single method that can be called later (perhaps many times) to act on that data, then you can still do that with a regular function by making an inner function the return value.
Something like:
def complicated(a, b, c, d, e):
def inner(k):
return (a*k, b*k, c*k, d*k, e*k)
return inner
foo = complicated(1, 2, 3, 4, 5)
result = foo(100)
This does seem much simpler to me than:
class Complicated:
def __init__(self, a, b, c, d, e):
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
def calc(self, k)
return (self.a*k, self.b*k, self.c*k, self.d*k, self.e*k)
foo = Complicated(1, 2, 3, 4, 5)
result = Complicated.calc(100)
The main limitation of the function based approach is that you cannot read back the values of a, b, c, d, and e in the example.
I'm trying to write a small Python module which contain some mathematical functions. For example, it might contain a function like:
def quad(x, a, b, c):
return a*x**2 + b*x + c
As you may notice it contains several parameters (viz. a, b, c) apart from the variable x. Now if I were to put this in a file and simply import it, the end user would have to always call the function with the parameters in addition to the variable. Because of this I was thinking of creating a class such as this:
class quad:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def eq(x):
return self.a*x**2 + self.b*x + self.c
Thus allowing the end user to use it as:
q = quad(p, q, r)
eq = q.eq
Is this the right way of doing things? I am terribly sorry about the title of the question, as I couldn't think of a better one!
That seems like a perfectly reasonable use of a class. Essentially you should consider using a class when your program involves things that can be modelled as objects with state. Here, the "state" of your polynomial is just the coefficients a, b, and c.
You can also use Python's __call__ special method to allow you to treat the class as though it were a function itself:
class quad:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def __call__(x):
return self.a * x**2 + self.b * x + self.c
q = quad(p, q, r)
q(x)
Yet another way of doing it, which could be slightly cleaner, would be simply to return a function with those coefficients baked into it. This is essentially an example of currying, as Tichodrama mentions:
def quad(a, b, c):
def __quad(x):
return a * x**2 + b * x + c
return __quad
Or using lambda syntax:
def quad(a, b, c):
return lambda x: a * x**2 + b * x + c
These could then be used like so:
q = quad(p, q, r)
q(x)
It looks like you are searching for something like currying.
Perhaps this question can help you.