Python 101: Special variables

Photo by David Clode on Unsplash

Python 101: Special variables

Python uses several special variables, often referred to as "dunder" (double underscore) variables or "magic methods" in the context of OOP, that have specific meanings and are used by the Python interpreter for particular purposes. This double underscore naming distinguishes them from regular variables and avoid naming conflicts with your custom variables.

These variables are integral to Python's internal operations and often relate to object-oriented features and module management.

Here are some of the key special variables in Python:

  1. __name__: This variable is perhaps the most well-known. It holds the name of the module in which it is used. If the module is the entry point to the program (i.e., the script that is run), __name__ is set to "__main__". This helps determine whether the module is being run directly or being imported.

     # example.py
     if __name__ == "__main__":
         print("This script is running directly")
     else:
         print("This script has been imported")
    

    Run this file directly or import it in another Python script to see the difference.

  2. __doc__: This variable contains the module's (script's) or function's documentation string (docstring), which is the first string after the definition. It's used to provide documentation about the module, class, method, or function.

     def example_function():
         """
         This is a docstring for example_function.
         """
         pass
    
     print(example_function.__doc__)
    
  3. __file__: This variable contains the pathname of the file from which the module was loaded, if it was loaded from a file. This can be useful for modules that want to load data files located in the same directory as the module file.

     # Prints the pathname of the file from which the module was loaded
     print(__file__)
    

    This will output the full path of the current script file.

  4. __dict__: This dictionary contains the namespace supported by most objects in Python, including modules, classes, and instances. It maps attribute names to their values and can be used for introspection or dynamically manipulating objects.

     class Example:
         def __init__(self):
             self.attribute = "value"
    
     instance = Example()
     print(instance.__dict__)
    

    This will print the dictionary containing the namespace of the instance of Example.

  5. __package__: This variable is used to support relative imports. It holds the name of the package that the current module is a part of. If the module is not part of a package, __package__ is set to None.

     # example_module.py
     print(__package__)
    

    When part of a package, this prints the package name. If not part of a package, it prints None.

  6. __path__: This variable only exists on packages. It is used to define the list of paths where Python searches for sub-modules and sub-packages under the package. This is how Python determines what can be imported within a package.

  7. __class__: Within a class method, this variable refers to the class object that the method is defined on. This can be useful for accessing class-level attributes and methods from instance methods.

     class MyClass:
         def show_class(self):
             print(self.__class__)
    
     obj = MyClass()
     obj.show_class()
    

    This code will print the class MyClass of the object obj.

  8. __bases__: Available only on class objects, this tuple contains the base classes, in the order of their occurrence in the base class list, of the class object.

     class BaseClass:
         pass
    
     class DerivedClass(BaseClass):
         pass
    
     print(DerivedClass.__bases__)
    

    This will print the tuple of base classes of DerivedClass, here (BaseClass,).

  9. __annotations__: This dictionary contains type hints for the module, class, or function. It maps parameter names to their type hints, and is available from Python 3.6 onwards.

     def func(a: int, b: str) -> float:
         return 3.14
    
     print(func.__annotations__)
    

    This will print the type hints of the parameters and the return type of func.

  10. __all__: This list controls what is exported when the module is imported using from module import *. Only names included in __all__ will be imported.

    # mymodule.py
    __all__ = ['public_function']
    
    def public_function():
        print("Accessible function")
    
    def _private_function():
        print("Hidden function")
    

    When you use from mymodule import *, only public_function will be imported due to __all__.