46

I am putting a bunch of related stuff into a class. The main purpose is to organize them into a namespace.

class Direction:

  north = 0
  east = 1
  south = 2
  west = 3

  @staticmethod
  def turn_right(d):
    return turn_to_the_right

  @staticmethod
  def turn_left(d):
    return turn_to_the_left



# defined a short alias because direction will be used a lot
D = Direction

d0 = D.north
d1 = D.turn_right(d)

There is not much object concept involved. In C++, I will be using the actual language keyword namespace. There is no such thing in Python. So I am trying to use class for this purpose.

Is this a good idea? Any pitfall with this approach?

I've just answer a related question yesterday. This question is asked in a different way. It is an actual decision I need to make for myself.

Static method vs module function in python - Stack Overflow

Static method vs module function in python

Ian
  • 5,704
  • 6
  • 40
  • 72
Wai Yip Tung
  • 18,106
  • 10
  • 43
  • 47
  • Thank you. So far the comment I got is 1. Use module 2. Do what make sense. What I still want to figure out is if class is considered a legitimate option for simply using as namespace or if there is some good reason not to. – Wai Yip Tung Aug 26 '10 at 18:14
  • 1
    I would suggest using `types.SimpleNamespace` here. A class that isn't meant to be instantiated is just conceptually wrong. – Kevin Aug 24 '21 at 17:32

6 Answers6

32

Yes, indeed. You can use Python classes strictly for namespacing as that is one of the special things they can do and do differently than modules. It's a lot easier to define a class as a namespace inline in a file than to generate more files. You should not do it without commenting your code saying what it's for. Python classes come in a lot of different forms and purposes and this makes difficulty understanding code you have not seen before.

A Python class used as a namespace is no less a Python class than one that meets the perception of what a class is in other languages. Python does not require a class to be instantiated to be useful. It does not require ivars and does not require methods. It is fairly flexible.

Clases can contain other classes too.

Lots of people have their ideas about what is or isn't Pythonic. But if they were all worried about something like consistency, they'd push to have things like len() dir() and help() be a method of objects rather than a global function.

Do what works, comment / document it if it isn't usual or obvious usage.

uchuugaka
  • 12,679
  • 6
  • 37
  • 55
  • 3
    Stuff like `len` is a function specifically to *ensure* consistency, so everything with a `len` uses `len` instead of ending up with something like Java's `array.length`/`string.length()`/`collection.size()`. – user2357112 Apr 15 '20 at 00:20
  • hmm, I disagree. That's the lack of a common base class, in my opinion. – uchuugaka Jan 18 '22 at 01:24
  • remember len() still needs to call a so-called dunder method __len__ on the object passed in, so it's not consistent with just giving the objects a len property or len() method. – uchuugaka Jan 18 '22 at 01:26
  • But if you just place the code in a file and limit that to be a module then you can use it the same as a a class used for namespace only – uchuugaka Aug 09 '22 at 03:51
  • I like this answer because of my own confirmation bias. To contribute to implicit documentation, we could stop instantiation by inheriting from a custom class that raise a suitable error on \_\_new\_\_ and \_\_init\_\_ – Graham Monkman Aug 11 '23 at 12:54
18

No. Stick it in a module instead.

Python doesn't have namespaces in the same way that C++ does, but modules serve a somewhat similar purpose (that is, grouping "like" classes and functions together, and giving them unique names to avoid clashes).

Edit
I saw the comment you posted to your question. To answer more explicitly, no, in Pythonic code it's not really correct to use a class to emulate a namespace. Modules are there to group related classes, functions, and variables -- use a module instead. A class represents a "thing" that has a behavior (methods) and data (instance variables) -- it's not just a collection of standalone functions and variables.

mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 5
    Is there stronger justification for module? I can think of an option to do `from direction import *`. On the other hand, if there are only 4 constants "north, east, south, west", it seems an overkill to put them in their own module. – Wai Yip Tung Aug 26 '10 at 15:54
  • 2
    You should put them where they make sense, from an organizational standpoint. If they "go together" with an existing module, put them there (you could rename them to `DIRECTION_NORTH` or whatever). If not, put them in a separate module, if that makes sense. – mipadi Aug 26 '10 at 15:59
  • 3
    Your rationale for using a class instead of a module for namespacing denies the very real qualities that both things share in Python. More the same than different. – uchuugaka Oct 14 '17 at 13:46
  • 1
    Since everything in python is an object (including modules) isn't the distinction between class and module semantic? – Marcel Wilson Apr 07 '20 at 18:26
  • @MarcelWilson: In the same sense that a function and a class is just a semantic difference, sure. – mipadi Apr 08 '20 at 20:16
  • @mipadi you're right. Boiling down to 'everything is an object' oversimplified things too much. I guess what I was trying to ask (poorly) was, when talking about _namespaces_ (in a pythonic sense) at the level of class and module, what is the distinction? – Marcel Wilson Apr 08 '20 at 20:33
  • 1
    a module is 'too heavy' often. you just want to create an object with some attribs..but not a dataclass or a dict. – Majid alDosari Aug 03 '22 at 16:04
  • In my case, the packaging for a python based tool allows only a single code file. Since I have a single huge file, I have to use classes to mimic what I'd normally use modules for. – Benny Jobigan Jun 06 '23 at 07:39
5

Yes, it's fine. You can even use property to make methods look like attributes.

If you have a big class, it might be neater to use a module

Katriel
  • 120,462
  • 19
  • 136
  • 170
4

It depends on the situation; if you can stick a constant in the module and have it make sense, by all means do so, but putting them in the class can make their meaning more obvious, and allow similar constants to have more "abstraction": placing them in the ServerError class makes more sense than having them all prepended with SERVER_ERROR residing freely in the module.

Do what is most intuitive, but try to avoid namespace pollution.

Humphrey Bogart
  • 7,423
  • 14
  • 52
  • 59
4

I mostly agree with @uchuga's answer, but I want to emphasize a caveat:

a = "global"
class C:
    a = "class"
    def f():
        print(a)
    f()

... will print "global", not "class".

Webthusiast
  • 986
  • 10
  • 16
  • 1
    Its obvious there should be a syntax that allows to create a module like object, defined similar to class but just called "namespace". Its weird that there's still no such nice thing. – Karolius Sep 07 '22 at 08:45
  • 1
    Perhaps even more interesting, if the outer `a` is not defined, the above will error out. – Nico Schlömer Feb 10 '23 at 10:23
-2

In my opinion, a class is a class, and a Namespace is a namespace. You can use argparse.Namespace like so to create a namespace:

from argparse import Namespace

directions = Namespace(
    north = 0,
    east  = 1,
    south = 2,
    west  = 3,
)

print(directions.north)  # 0
print(directions.east)   # 1
print(directions.south)  # 2
print(directions.west)   # 3
Arthur Khazbs
  • 705
  • 8
  • 19
  • 2
    This is backwards. `argparse.Namespace` **is not** a language level namespace. A `class` **is** a language level namespace. Using `argparse.Namespace` to group related names is possible but impractical and confusing. – Mattias Wallin Apr 07 '21 at 06:01
  • A `named_tuple` would be more appropriate for your code example. Just to be pedantic, Namespace is a class. – Olsgaard Jun 24 '22 at 10:32
  • @Olsgaard I do realize that `Namespace` itself is a `class` indeed, but still it is called `Namespace`, which is exactly why I suggested it back then. However, now I think that an [`Enum`](https://docs.python.org/3/library/enum.html) would be a most appropriate choice in this situation. – Arthur Khazbs Jun 25 '22 at 20:45