Explain Codes LogoExplain Codes Logo

Defining private module functions in python

python
best-practices
functions
encapsulation
Anton ShumikhinbyAnton Shumikhin·Oct 13, 2024
TLDR

In Python, a leading underscore _ designates a function as private, signifying it's meant for internal use inside a module.

def _internal_use_only(): return "For module eyes only."

This "privacy" isn't enshrined by Python, rather, it's a convention respected among programmers – a polite request to other developers saying, "Hey, do not touch this!"

Enforcing "privacy" in modules

While Python doesn't offer an explicit mechanism to enforce private use at the module level, it does provide strategies we can employ. Python incorporates name mangling for class methods (using double underscores) to obfuscate and implicitly protect data, but when it comes to module-level functions, it leaves the decision in our more than capable hands.

# A strategy for privacy, not a "No Trespassing" sign. def _for_my_eyes_only(): # You didn't see anything! 🕵️‍♀️ return "Very secret stuff"

Here, the _for_my_eyes_only() function may be used within the module it resides in, but the leading underscore suggests to other developers that it isn't intended for use outside of it.

A step deeper: Inner secrets

You can level-up the encapsulation within a function using what's called an inner function. Remember, Python loves you and gives you all the necessary tools... use them wisely!

def public_function(): # Inner function definition - harder to pry open, still not invincible! def _private_plan(): return "You ain't heard nothin'!" return _private_plan()

Here, the _private_plan() function lives comfy and cozy inside the public_function() and is accessible only from there, providing another level of privacy.

No wildcards in imports, please!

Be explicitly explicit when it comes to imports. Remember, clearer code is happier code.

from secret_module import public_api # Awesome practice from secret_module import _secret_stuff # Um, let's not do this

Avoid using from module import * like your code's life depends on it (because greatly, it does!) Wildcard imports can pull in unexpected names, even those intending to be private. It's like aiming for a dartboard blindfolded - who knows what you'll hit?

Managing with classes

Class-level privacy employs double underscores (__) to invoke name mangling and prevent their accidental misuse.

class Recipe: def __init__(self): self.__top_secret = "This stays in the kitchen!" def prepare_dish(self): # Chef can access the secret return self.__top_secret meal = Recipe() print(meal.prepare_dish()) # "This stays in the kitchen!" print(meal.__top_secret) # AttributeError: Not so easy!

Remember, even here, we're not guaranteeing absolute privacy. The intention is to avoid clashes rather than prevent access.

Pythonic Privacy: Trust, not Enforcement

The essence of privacy in Python caters to the language's philosophy of giving the developers ample freedom. It's about respect: "Look, but don't touch!".