Files
the_information_nexus/tech_docs/python/python_deep_dive.md

8.9 KiB
Raw Blame History

Sure! Lets break it down into simpler, more digestible pieces:

1. Double Underscore Methods (Dunder Methods)

These are special methods in Python that have two underscores on each side, like __init__(). Python uses them automatically for specific operations, so you dont normally call them directly.

  • Examples:
    • __init__() is used when you create a new instance of a class (like a constructor).
    • __len__() is used when you call len() on an object.

These methods let you customize how objects behave with Pythons built-in functions.

2. Single Leading Underscore (_name)

A single underscore at the start of a name (e.g., _name) is a convention to say, "Hey, this is internal! Dont mess with it unless you really need to." Its like a "soft privacy" signal to other programmers.

  • Example: If you see _internal_data, its not strictly private, but its meant to be used internally within the class or module.

3. Double Leading Underscore (__name)

A double underscore at the start of a name (e.g., __name) triggers name mangling. This means Python changes the name behind the scenes to avoid conflicts in subclasses. Its a way to prevent accidental name collisions.

  • Example: If you define __private_var in a class, Python will rename it to something like _ClassName__private_var, making it harder to accidentally override it in subclasses.

4. Double Leading and Trailing Underscore (name)

If something has double underscores on both sides, like __init__ or __len__, its a special system method that Python uses. Dont name your own methods like this unless youre overriding a built-in method on purpose.

  • Example: Python already has a method like __str__() that defines how an object is printed. You can customize this in your own class to change how it looks when printed.

5. Single Trailing Underscore (name_)

When you see a single trailing underscore (e.g., class_), its used to avoid conflicts with Pythons reserved words or built-in functions.

  • Example: class is a reserved keyword in Python, so if you need a variable with that name, you can use class_ instead.

6. No Underscore (Public Names)

If a name has no underscores, like name, its just a regular attribute or method, and its intended for public use.

  • Example: self.name = "John" in a class means that anyone using this class can access the name attribute.

How To Use This:

  • If you see a method with __double_underscores__, its special and built into Python.
  • Use a single leading underscore _name to tell others, "This is internal! Handle with care."
  • Use double leading underscores __name when you want to protect something from being easily overridden in a subclass.
  • Avoid naming anything with double underscores on both sides unless you're overriding a special behavior.

Does this help clarify things? Let me know if any part is still unclear!


Certainly! Here's a clear outline that summarizes the key concepts we've discussed. You can use this as a reference to track these important items:


1. Python Naming Conventions: Double Underscore and Privacy

A. Dunder (Double-Underscore) Methods

  • Purpose: Special system-defined methods that control object behavior with built-in functions and operators.
  • Examples:
    • __init__() Constructor for initializing an object.
    • __len__() Defines length for len() function.
    • __str__() Controls string representation with str().
  • Usage: You implement these methods to define or customize how objects interact with common Python operations.

B. Single Leading Underscore (_name) Protected Attributes

  • Convention: Used to indicate protected attributes or methods meant for internal use.
  • Access: Accessible both within and outside the class, but its discouraged to access from outside.
  • Usage: Use _name to signal that an attribute or method should be treated as internal, though not strictly enforced.

C. Double Leading Underscore (__name) Private Attributes

  • Purpose: Used to mark attributes as private and avoid accidental access, especially in subclasses.
  • Name Mangling: Python renames __name to _ClassName__name to prevent accidental overrides.
  • Access: Not intended for external access, though it can still be accessed using the mangled name.
  • Usage: Use __name when you want to ensure that an attribute is not easily overridden in subclasses.

D. Double Leading and Trailing Underscore (name) Reserved System Methods

  • Purpose: Reserved for Python's system-defined methods and attributes.
  • Examples:
    • __init__(), __call__(), __str__()
  • Usage: Avoid using this pattern in your own code unless youre overriding a special method.

E. Single Trailing Underscore (name_)

  • Purpose: Used to avoid conflicts with Python keywords (e.g., class_, def_).
  • Usage: Use it to avoid naming collisions when naming attributes or variables that would otherwise conflict with reserved words.

2. Name Mangling in Python

A. Definition

  • What It Is: A process that alters the name of attributes with double leading underscores (__name) to include the class name (_ClassName__name).
  • Purpose: Prevents accidental overriding or access of private attributes from subclasses.

B. Example

class Parent:
    def __init__(self):
        self.__private_var = 42  # Becomes _Parent__private_var
  • You can't access __private_var directly from outside the class, but can still access it using the mangled name (_Parent__private_var).

3. Differences Between Private and Protected Attributes

A. Protected (_name)

  • Convention: Attribute is for internal use but still accessible from outside.
  • Access: Meant for access within the class and its subclasses, though not strictly enforced.
  • Example:
    class MyClass:
        def __init__(self):
            self._protected_var = 10
    

B. Private (__name)

  • Convention: Attribute is more "private" and is name-mangled to avoid accidental access or override.
  • Access: Can only be accessed via name mangling (e.g., _ClassName__name).
  • Example:
    class MyClass:
        def __init__(self):
            self.__private_var = 42  # Becomes _MyClass__private_var
    

4. Summary Table of Usage

Type Notation Intended Usage Enforced by Python?
Dunder (Special) __init__(), __len__() Special methods to control behavior of built-in operations. Yes, by system convention.
Protected _name Internal use; accessible from outside but discouraged. No, it's a convention.
Private (Name Mangling) __name Name-mangled to avoid accidental access or overriding. Somewhat, by name mangling.
Reserved System Methods __name__ Python-reserved methods and attributes. Yes, reserved for system use.
Avoid Conflicts name_ Used to avoid conflicts with reserved keywords. No, it's a naming convention.

5. Practical Applications and Recommendations

A. When to Use Protected (_name):

  • Internal Attributes: Use _name when you want to signal to other developers that an attribute or method is internal but may be accessed in subclasses.
  • Not Strict: It's a convention, so its not strongly enforced. Other developers can still access these if they need to.

B. When to Use Private (__name):

  • Avoiding Subclass Conflicts: Use __name if you want to avoid accidental overrides in subclasses.
  • More Private: This adds a layer of protection, making it harder to access or override. However, it's still accessible through name mangling if necessary.

C. When to Use Dunder Methods (__init__, __str__, etc.):

  • Customizing Behavior: Use dunder methods to customize how your class instances interact with Pythons built-in functions (e.g., len(), str(), +, ==).
  • Keep It Simple: Dont define your own names with leading and trailing double underscores unless you're overriding one of Pythons special methods.

This outline provides you with a structured way to understand and track how and when to use double underscores and underscores in Python. Let me know if you want further clarifications on any section!