Thomas Johnson
Thomas Johnson

Reputation: 11638

Proper use of class constants in 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?

Upvotes: 10

Views: 9863

Answers (3)

Erik Kaplun
Erik Kaplun

Reputation: 38207

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

Upvotes: 4

zhangxaochen
zhangxaochen

Reputation: 33997

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.

Upvotes: 0

Paulo Bu
Paulo Bu

Reputation: 29794

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.

Upvotes: 9

Related Questions