Should Python class filenames also be camelCased?

Question:

I know that classes in Python are typically cased using camelCase.

Is it also the normal convention to have the file that contains the class also be camelCase’d especially if the file only contains the class?

For example, should class className also be stored in className.py instead of class_name.py?

Asked By: m4jesticsun

||

Answers:

My question is, is it also the normal convention to have the file that
contains the class also be camelCase’d especially if the file only
contains the class

Short answer: No.

Longer answer: should be all lower case and underscores as needed.

From PEP8 “Package and Module Names”:

Modules should have short, all-lowercase names. Underscores can be
used in the module name if it improves readability. Python packages
should also have short, all-lowercase names, although the use of
underscores is discouraged.

If you’re unclear what a module is:

A module is a file containing Python definitions and statements. The
file name is the module name with the suffix .py appended.

Answered By: Jack

The following answer is largely sourced from this answer.

If you’re going to follow PEP 8, you should stick to all-lowercase names, with optional underscores.

To quote PEP 8’s naming conventions for packages & modules:

Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability.

And for classes:

Class names should normally use the CapWords convention.

See this answer for the difference between a module, class and package:

A Python module is simply a Python source file, which can expose classes, functions and global variables.

The official convention is to use all lower case for file names (as others have already stated). The reason, however, has not been mentioned…

Since Python works cross platform (and it is common to use it in that manner), but file systems vary in the use of casing, it is better to just eliminate alternate cases. In Linux, for instance, it is possible to have MyClass.py and myclass.py in the same directory. That is not so in Windows!

On a related note, if you have MyClass.py and myclass.py in a git repo, or even just change the casing on the same file, git can act funky when you push/pull across from Linux and Windows.

And, while barely on topic, but in the same vein, SQL has these same issues where different standards and configurations may or may not allow UpperCases on table names.

I, personally, find it more pleasant to read TitleCasing / camelCasing even on filenames, but when you do anything that can work cross platform it’s safest not to.

Answered By: BuvinJ

There is a difference in the naming convention of the class name and the file that contains this class. This missunderstanding might come from languages like java where it is common to have one file per class.

In python you can have several classes per modul (a simple .py file). The classes in this module/file should be called according to the class naming convention: Class names should normally use the CapWords convention.
The file containing this classes should follow the modul naming convention: Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability.

=> CamelCase should in the file camelcase.py (or camel_case.py if neccessary)

Answered By: Franz Felberer

First of all, as mentioned above, class names should be CapWords, e.g.:

class SampleClass:
   ...

BEWARE: Having the same name for file (module) and class creates confusions.

Example 1: Say you have the following module structure:

src/
   __init__.py
   SampleClass.py
main.py

Your SampleClass.py is:

class SampleClass:
   ...

Your main.py is:

from src import SampleClass

instance = SampleClass()

Will this code work? NO, cause you should’ve done either from src.SampleClass import SampleClass or instance = SampleClass.SampleClass(). Awkward code, isn’t it?

You can also fix it by adding the following content to __init__.py:

from .SampleClass import SampleClass

Which leads to the Example 2.

Example 2: Say you develop a module:

src/
   __init__.py
   BaseClass.py
   ConcreteClass.py
main.py

BaseClass.py content:

class BaseClass:
    ...

ConcreteClass.py content:

from src import BaseClass

class ConcreteClass(BaseClass):
    ...

And your __init__.py content:

from .ConcreteClass import ConcreteClass
from .BaseClass import BaseClass

And main.py content is:

from src import ConcreteClass

instance = ConcreteClass()

The code fails with an error:

    class ConcreteClass(BaseClass):
TypeError: module() takes at most 2 arguments (3 given)

It took me a while to understand the error and why I cannot inherit from the class, cause in previous example when I added exports to __init__.py file everything worked. If you use snake case file names it does not fix the problem but the error is a bit easier to understand:

ImportError: cannot import name 'BaseClass' from partially initialized module 'src'

To fix the code you need to fix the import in ConcreteClass.py to be: from .BaseClass import BaseClass.

Last caveat, if in original code you would switch places imports in __init__.py so it looks like:

from .BaseClass import BaseClass
from .ConcreteClass import ConcreteClass

Initial code works, but you really don’t want anyone to write a code that will depend on the order of imports. If someone changes the order or applies isort tool to organize imports, good luck fixing those bugs.

Answered By: andnik