pythonclassprivatepep

Pythonic usage or underscore (private) names in Python


I would like to know which would be more pythonic way to write python code using _ in modules, classes and methods.

Example 1:

import threading as _threading

class Thread(_threading.Thread):
    pass

vs

from threading import Thread

class MyThread(Thread):
    pass

on module level does it make sense to introduce private vars in methods like this:

def my_module_method():
    _throw = foo + bar
    return _throw

vs

def my_module_method():
    throw = foo + bar
    return throw

Am I correct to assume that best usage of private name would be to prevent instance of the class to use some private temp method eg:

class MyClass(object):
    _my_internal = 0
    def _do_not_use_me()
        pass

so that enduser of that class would know not to use those methods directly in:

foo = MyClass._do_not_use_me()
bar = MyClass._my_internal

Any other advice on general usage of private names would be highly appreciated.


Solution

  • Keep in mind, with Python nothing is "hard rules" more conventions. With some exceptions, there's nothing wrong with prefixing your variables with whatever you want, as long as you are consistent and your code is easy to understand.

    However, if you want to follow the common convention, do read on.

    In general

    As Python doesn't have access modifiers like some other languages (access modifiers like private, public, protected, etc), the _ prefix marks fields, methods, etc in classes that are not to be accessed externally. It marks private use.

    With that in mind, let's look at your examples one by one:

    Example 1

    The prefered way is:

    from threading import Thread
    
    class MyThread(Thread):
        pass
    

    You may also use:

    import threading
    
    class MyThread(threading.Thread):
        pass
    

    But you should not _ prefix imported modules.

    Example 2

    Under ordinary circumstances, you do not have access to the inner variables of functions. As a result there is no reason to use _. Thus this is the way:

    def my_module_method():
        throw = foo + bar
        return throw
    

    The only exception I can think of, is in the case of nested functions, where you may replicate names and to avoid ambiguity you would use _ to differentiate between variables:

    def my_outer_method():
        throw = foo + bar
    
        def my_inner_method(_throw):
            return _throw * 2
        
        return my_inner_method(throw)
    

    Example 3

    Yes, this is the exact reason why you would use the _ prefix.

    my_class = MyClass()
    foo = my_class._do_not_use_me()
    bar = my_class._my_internal
    

    This tells the consumer of the class that they are doing something they are not supposed to or something that isn't safe.