6

The normal way of creating a class in python does not allow for whitespace in the class name.

>>> class Foo Bar(object):
SyntaxError: invalid syntax

However, using the built-in type() function, we can create a class with whitespace in the name:

>>> C = type('Foo Bar', (object,),{})
>>> C
<class '__main__.Foo Bar'>

Is there any risks, or is it considered bad practice using class names with white space?

RasmusN
  • 147
  • 1
  • 12
  • 5
    https://media.giphy.com/media/1M9fmo1WAFVK0/giphy.gif – cs95 Aug 03 '18 at 06:19
  • 6
    why do you need a class name with an empty space in the middle? – blfuentes Aug 03 '18 at 06:19
  • 7
    Yes, it is considered a bad practice. As for risks, the only risk I foresee is a baseball bat to the face from an irate colleague. I'll echo coldspeed: BUT WHY? – Amadan Aug 03 '18 at 06:21
  • Other user still need to use `C()` to setup the object, so `Foo Bar` seems to be superfluous. – atline Aug 03 '18 at 06:28
  • @blfuentes The classes are generated dynamically from an external file. I could, simply remove the white space but prefer not if there isn't any risk with it. – RasmusN Aug 03 '18 at 06:32
  • @atline yes you are correct. And we can actually achieve the same result with the _classic_ way by changing the name after declaration: `>>> class FooBar(object): pass` `>>> FooBar.__name__ = "Foo Bar"` `>>> FooBar ` – RasmusN Aug 03 '18 at 06:35
  • @RasmusN Please don't do that. – cs95 Aug 03 '18 at 06:35
  • @coldspeed can you give me an example where it can be a problem? – RasmusN Aug 03 '18 at 06:37
  • How do you intend to create instances of those classes with whitespace in their names? I'm not claiming it's impossible, just that I can't think of a way to do it that isn't messy. – PM 2Ring Aug 03 '18 at 06:44
  • 2
    @RasmusN basically you want to make your code harder to read. That's enough as bad practice and risk itself, because you are sold and it would lead to potential issues. You can remove the white spaces and keep a mapping between class name and files if you do really need. – blfuentes Aug 03 '18 at 06:46
  • @PM2Ring In this case you can create an instance by `c = C()`. In my code I'm storing them in a dictionary. `classes = {"Foo Bar", type('Foo Bar', (object,),{}), ...}` – RasmusN Aug 03 '18 at 06:47
  • Ok, but I still count that as a bit messy. I strongly advise replacing the spaces, eg with an underscore. And you still haven't explained what you're doing with these weird class names. I suspect an XY problem. – PM 2Ring Aug 03 '18 at 06:52
  • @PM2Ring I thought the topic was very clear. There is no, to me, known problem with this other than that the code is a little bit harder to read. – RasmusN Aug 03 '18 at 07:01
  • The topic is clear. There are no risks. But yes, it _is_ considered bad practice. And we suspect that it's unnecessary, or at least that there's a better way to deal with your real problem, which is why we continue to ask why you want to do this. – PM 2Ring Aug 03 '18 at 07:09
  • @PM 2Ring Not the OP, but I imagine that I have a separate XY problem. My overall goal is to parse a CSV-like file format that supports multiple tables in a single physical file. What I’d like to do is create a different type of row class for each of the tables (so that validation attributes such as the number and names of columns can be part of the class definition). What brought me to this specific question is whether to use the table names directly from the file (in which there may be spaces) or to modify them into more normal class names. – cjm Aug 25 '21 at 19:09
  • @cjm You *can* do that, but I expect that you'll find it annoying to not be able to use the normal syntax to set & get your class attributes. But do you really need classes for this? Why not just use dicts & lists, like you'd use If you were loading data from JSON? – PM 2Ring Aug 25 '21 at 20:27

2 Answers2

6

There is no risk, the class __name__ is a writable attribute and it's not used for anything particularly important - just boring stuff like the repr and the help display.

If you try to assign non-string to it, there is a custom error message, which is strong evidence that Python devs had the chance to restrict to valid identifiers here, and they intentionally chose not to:

>>> class A:
...     pass
... 
>>> A.__name__ = '123Class'
>>> A.__name__ = 123
TypeError: can only assign string to 123Class.__name__, not 'int'

Here is Guido answering a similar question - about whether attribute names should be restricted to valid identifiers:

https://mail.python.org/pipermail/python-dev/2012-March/117441.html

I've spoken out on this particular question several times before; it is a feature that you can use any arbitrary string with getattr() and setattr(). However these functions should (and do!) reject non-strings.

The same reasoning applies to class names (which could also be stored as arbitrary strings in a module namespace). An example use-case for this feature: ensuring there's a consistent mapping between a sequence of class names and some external data source, even if the external data collides with Python reserved words or syntax.

wim
  • 338,267
  • 99
  • 616
  • 750
  • The sentence 'it's not used for anything important' is mostly right. The first thing that jumps to mind is `pickle`, although it uses `__qualname__` instead of `__name__`, but that may lead to other unexpected behavior. You could add a paragraph about `__qualname__` – MegaIng Aug 03 '18 at 07:56
2

Is there any risks, or is it considered bad practice using class names with white space?

It is absolutely considered bad practice, since PEP8 advises to use CapWords style for class names. The only technical difficulty you'll encounter is that such a whitespace-named class can't be instanciated with the usual syntax:

x = Foo Bar()  # SyntaxError

But the actual problem will always be that it is very unusual and any human reading your code or debugging your bugs will have a hard time. If I imagine seeing something like AttributeError: 'Foo Bar' object has no attribute 'x', I'd first try to find out what went wrong with the class name, because there is no way someone included a whitespace there.. right?

So please, just don't.

Arne
  • 17,706
  • 5
  • 83
  • 99
  • Dynamic invocation would be `getattr(mynamespace, 'Foo Bar')()`. Seems reasonable to me. – wim Aug 03 '18 at 07:42
  • Isn't that PEP8 article refering to the global() namespace rather than the class.__name__? – RasmusN Aug 03 '18 at 07:52
  • @wim Does that still fly as "usual syntax" with you? – Arne Aug 03 '18 at 08:02
  • @RasmusN It doesn't, I think. My example with the class instantiation syntax does, but it was a minor point anyways. The important point is that the name will still appear e.g. in error logs. – Arne Aug 03 '18 at 08:05
  • @Arne For working with names coming from a data source, yeah. You would do the same even if these names had "normal" identifier values, since you'd have to loop over a sequence of them anyway. Don't/can't write declarative code here, so you set with `setattr` and get with `getattr`. – wim Aug 03 '18 at 16:22
  • @wim That does sound reasonable – Arne Aug 03 '18 at 16:24