Proper use of class constants in Python - python

This question specifically relates to the use of the class constants ABOVE and BELOW in the sample code below.
I have a few different classes in different modules that look like this:
class MyClass(object):
ABOVE = 1
BELOW = 0
def __init__(self):
self.my_numbers = [1,2,3,4,5]
def find_thing_in_direction(self, direction, cutoff):
if direction == self.ABOVE:
return [n for n in self.my_numbers if n > cutoff]
else:
return [n for n in self.my_numbers if n < cutoff]
my_class = MyClass()
my_var = my_class.find_thing_in_direction(MyClass.ABOVE, 3)
If I have a handful of classes scattered across different modules that each have their own ABOVE and BELOW, should I extract these constants to somewhere, or is it better to keep the constants within their own classes?
Is there a more Pythonic way to do this instead of using these class constants?

It seems you're using classes as namespaces for your constants. You should ask yourself if the ABOVE and BELOW constants in every single class differs in something between each other.
If a differentiation is required (not just numeric difference, but semantic as well) then storing them in the class they represent is the best approach. On the other side if they have the same semantics in every class then you're not sticking to DRY principle and you're duplicating code.
A solution can be stored them at module level or create a class merely to contain the constants.

EDIT:
based on the OP's comment, I've realized that I overlooked that fact that ABOVE and BELOW are not really parametric constants but just strongly typed names (i.e. an enumeration).
Therefore I think the accepted answer is the correct one :)
Old answer:
It really boils down to preference if the number of constants is small, in the end, however, if you have a lot of them, namespacing by classes is probably a good idea.
Also, do you have inheritance? if yes, do you override the constant values in subclasses? If yes, you obviously need to keep them inside of your classes.
Also, my_class.find_thing_in_direction(MyClass.ABOVE, 3) is smelly: find_thing_in_direction should most probably refer to its own class' ABOVE constant directly.
Also, SomeClass is a really bad class name :)

For your specific method find_thing_in_direction, the direction param is better be a bool flag named something like reverse, just like what the builtin sorted function does:
def find_thing_in_direction(self, reverse, cutoff):
if not reverse:
pass
else:
pass
This way you don't have to use class attributes.

Related

Where to put a function that acts on two instances of a specific class

This is really a design question and I would like to know a bit of what design patterns to use.
I have a module, let's say curves.py that defines a Bezier class. Then I want to write a function intersection which uses a recursive algorithm to find the intersections between two instances of Bezier.
What options do I have for where to put this functions? What are some best practices in this case? Currently I have written the function in the module itself (and not as a method to the class).
So currently I have something like:
def intersections(inst1, inst2): ...
def Bezier(): ...
and I can call the function by passing two instances:
from curves import Bezier, intersections
a = Bezier()
b = Bezier()
result = intersections(a, b)
However, another option (that I can think of) would be to make intersection a method of the class. In this case I would instead use
a.intersections(b)
For me the first choice makes a bit more sense since it feels more natural to call intersections(a, b) than a.intersections(b). However, the other option feels more natural in the sense that the function intersection really only acts on Bezier instances and this feels more encapsulated.
Do you think one of these is better than the other, and in that case, for what reasons? Are there any other design options to use here? Are there any best practices?
As an example, you can compare how the builtin set class does this:
intersection(*others)
set & other & ...
Return a new set with elements common to the set and all others.
So intersection is defined as a regular instance method on the class that takes another (or multiple) sets and returns the intersection, and it can be called as a.intersection(b).
However, due to the standard mechanics of how instance methods work, you can also spell it set.intersection(a, b) and in practice you'll see this quite often since like you say it feels more natural.
You can also override the __and__ method so this becomes available as a & b.
In terms of ease of use, putting it on the class is also friendlier, because you can just import the Bezier class and have all associated features available automatically, and they're also discoverable via help(Bezier).

How to "fool" duck typing in Python

Suppose I had a class A:
class A:
def __init__(self, x, y):
self.x = x
self.y = y
def sum(self):
return self.x + self.y
And I defined a factory method called factory:
def factory(x, y):
class B: pass
b = B()
setattr(b, 'x', x)
setattr(b, 'y', y)
B.__name__ = 'A'
return b
Now, If I do print(type(A(1, 2))) and print(type(factory(1, 2))) they will show that these are different types. And if I try to do factory(1, 2).sum() I'll get an exception. But, type(A).__name__ and type(factory(1, 2)).__name__ are equivalent and if I do A.sum(factory(1, 2)) I'll get 3, as if I was calling it using an A. So, my question is this:
What would I need to do here to make factory(1, 2).sum() work without defining sum on B or doing inheritance?
I think you're fundamentally misunderstanding the factory pattern, and possibly getting confused with how interfaces work in Python. Either that, or I am fundamentally confused by the question. Either way, there's some sorting out we need to do.
What would I need to do here to make factory(1, 2).sum() work without
defining sum on B or doing inheritance?
Just return an A instead of some other type:
def factory(x, y):
return A(x, y)
then
print(factory(1,2).sum())
will output 3 as expected. But that's kind of a useless factory...could just do A(x, y) and be done with it!
Some notes:
You typically use a "factory" (or factory pattern) when you have easily "nameable" types that may be non-trivial to construct. Consider how when you use scipy.interpolate.interp1d (see here) there's an option for kind, which is basically an enum for all the different strategies you might use to do an interpolation. This is, in essence, a factory (but hidden inside the function for ease of use). You could imagine this could be standalone, so you'd call your "strategy" factory, and then pass this on to the interp1d call. However, doing it inline is a common pattern in Python. Observe: These strategies are easy to "name", somewhat hard to construct in general (you can imagine it would be annoying to have to pass in a function that does linear interpolation as opposed to just doing kind='linear'). That's what makes the factory pattern useful...
If you don't know what A is up front, then it's definitely not the factory pattern you'd want to apply. Furthermore, if you don't know what you're serializing/deserializing, it would be impossible to call it or use it. You'd have to know that, or have some way of inferring it.
Interfaces in Python are not enforced like they are in other languages like Java/C++. That's the spirit of duck typing. If an interface does something like call x.sum(), then it doesn't matter what type x actually is, it just has to have a method called sum(). If it acts like the "sum" duck, quacks like the "sum" duck, then it is the "sum" duck from Python's perspective. Doesn't matter if x is a numpy array, or A, it'll work all the same. In Java/C++, stuff like that wont compile unless the compiler is absolutely certain that x has the method sum defined. Fortunately Python isn't like that, so you can even define it on the fly (which maybe you were trying to do with B). Either way, interfaces are a much different concept in Python than in other mainstream languages.
P.S.
But, type(A).__name__ and type(factory(1, 2)).__name__ are equivalent
Of course they are, you explicitly do this when you say B.__name__ = 'A'. So I'm not sure what you were trying to get at there...
HTH!

Function Encapsulation Efficiency in Python

I have a large set of objects, and I need to be able to do some complex stuff with each object, so I have some fairly long functions.
In general, is it better to put the long functions in the class that they'll actually be used in (GreatObject, below) for proper encapsulation, or is it better for efficiency to put one function in the collection class (GreatSet, which will only ever have one instance)?
class GreatSet(object):
def __init__(self):
self.great_set = [] # Will contain a lot of GreatObjects.
def long_method(self, great_object): # Is this function better here?
[Many lines of code]
class GreatObject(object):
def __init__(self, params):
self.params = params
def.long_method(self): # Or here?
[Many lines of code]
I'm using Python 2.7.
in both cases, long_method will belong to it's class (there will be a single long_method function per class, shared by all instances), and in both cases looking up obj.long_method will create a new Method instance for each lookup, so wrt/ "efficiency" (whatever it's supposed to mean) it won't make any difference. Also, unless you need maximum time and space performances - in which case a lower level language might be a best choice - you should really feel more concerned with proper design and maintainability than with maximum raw performances.
So, if long_method is supposed to work on GreatObject it might belong to GreatObject, but it depends on the respective responsabilities of those classes, what long_method really do, and which application layers long_method, GreatObject and GreatSet belong to. If for example GreatObject and GreatSet both belong to the domain model and long_method do presentation-related stuff then obviously long_method belongs neither in GreatObject nor GreatSet.
Finally, as PartialOrder mentions in his comment, "long" functions are most often a code / design smell. Sometimes a function has to be "long enough" because it has do something complex - and even then you can usually refactor it into smaller functions (eventually into methods of a distinct class if those functions need to share state) -, but quite often a long function means it's just doing too many things.

function of a function (property) python

I have a Python class with functions and properties like this:
#property
def xcoords(self):
' Returns numpy array. '
try:
return self.x_coords
except:
self.x_coords = self._read_coords('x')
return self.x_coords
def _read_coords(self, type):
# read lots of stuff from big file
return array
This allows me to do this: data.xcoords, nice and simple.
I want to keep this as it is, however I want to define functions which allow me to do this:
data.xcoords.mm
data.xcoords.in
How do I do it? I also want these function to work for other properties of the class such as data.zcoords.mm.
If you really want xcoords to return a numpy array, then people may not expect the value of xcoords to have mm and in_ methods. You should think about whether mm and in_ are really properties of the arrays themselves, or if they are properties of the class you're defining. In the latter case, I would recommend against subclassing ndarray -- just define them as methods of the containing class.
On the other hand, if these are definitely properties of the thing returned by xcoords, then subclassing ndarray is a reasonable approach. Be sure to get it right by defining __new__ and __array_finalize__ as discussed in the docs.
To decide whether you should subclass ndarray, you might consider whether you can see yourself reusing this class elsewhere in your program. (You don't actually have to use it elsewhere, right now -- you just have to be able to see yourself reusing it at some point.) If you can't, then these are probably properties of the containing class. The line of reasoning here is that -- thinking in terms of functions -- if you have a short function foo and a short function bar, and know you will never call them any other way than foo(bar(x)), you might be better off writing foo_bar instead. The same logic applies to classes.
Finally, as larsmans pointed out, in is a keyword in python, and so isn't available for use in this case (which is why I used in_ above).

Python: Using a dummy class to pass variable names?

This is a followup to function that returns a dict whose keys are the names of the input arguments, which I learned many things (paraphrased):
Python objects, on the whole, don't know their names.
No, this is not possible in general with *args. You'll have to use keyword arguments
When the number of arguments is fixed, you can do this with locals
Using globals(). This will only work if the values are unique in the module scope, so it's fragile
You're probably better off not doing this anyway and rethinking the problem.
The first point highlighting my fundamental misunderstanding of Python variables. The responses were very pedagogic and nearly instantaneous, clearly this is both a well-understood yet easily confused topic.
Since I'd like to learn how to do things proper, is it considered bad practice to create a dummy class to simply hold the variables with names attached to them?
class system: pass
S = system ()
S.T = 1.0
S.N = 20
S.L = 10
print vars(S)
This accomplishes my original intent, but I'm left wondering if there is something I'm not considering that can bite me later.
I do it as a homage to Javascript, where you don't have any distinction between dictionaries and instance variables. I think it's not necessarily an antipattern, also because differently from dictionaries, if you don't have the value it raises AttributeError instead of KeyError, and it is easier to spot typos of the name. As I said, not an antipattern, provided that
the scope of the class is restricted to a very specific usage
the routine or method you are calling (e.g. vars in your example) is private in nature. I would not want a public interface with that calling semantics, nor I want it as a returned entity
the name of the "dummy" class is extremely clear in its intent and the kind of aggregate it represents.
the lifetime of that object is short and uneventful. It is just a temporary bag of data.
If these constraints are not respected, go for a fully recognized class with properties.
you can do that, but why not use a dictionary?
but if you do that, you're better off passing keywords args to the class's constructor, and then let the constructor copy them to the app's members. something like:
class Foo(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)

Categories

Resources