2

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.

tituszban
  • 4,797
  • 2
  • 19
  • 30
Topi
  • 25
  • 4
  • That's probably opinion-based, so not suitable for SO. But IMHO, your assumption is correct. As for "private" variables in functions - that doesn't make sense, as they can't be accessed from outside anyway. "Private" imports don't make sense either as they would only be ignored in `import *` which is a bad practice anyway. So as for me, only class attributes, object attributes, methods, and (not-imported) classes and functions should ever be "private". – Yevhen Kuzmovych Aug 02 '21 at 09:05

1 Answers1

3

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.

tituszban
  • 4,797
  • 2
  • 19
  • 30