Python Class Methods and Attributes: Complete Guide

What are Python Class Members?
Python class members are the variables (attributes) and functions (methods) that belong to a class. Choosing the right type — instance, class, or static — is the key to writing clean, efficient OOP code that scales.
Introduction to Class Members
In our previous tutorial, we covered the basics of Python OOP. Now, let's explore the "members" of a class—the variables and methods that give your objects data and functionality.
Typically, a Python class consists of:
- Docstrings: For documentation.
- Built-in Attributes: Predefined metadata.
- Variables: To store state (Instance, Class, Private).
- Methods: To define behavior (Instance, Class, Static, Magic).
1. Docstrings & Built-in Attributes
Docstrings
A docstring is a string literal used to describe the purpose of your class or method. It’s accessed via the __doc__ attribute.
Essential Built-in Attributes
Every Python class comes with several built-in attributes that provide metadata:
| Attribute | Description |
|---|---|
__name__ | Returns the name of the class. |
__module__ | Returns the name of the module where the class is defined. |
__bases__ | Returns a tuple of base classes (parent classes). |
__dict__ | Returns a dictionary containing the class's namespace. |
2. Types of Variables
Instance Variables
These are unique to each object. Every instance has its own copy, and changing one doesn't affect the others. They are usually defined inside the __init__ constructor.
Class Variables
These are shared by ALL instances of a class. They are defined outside the constructor.
Avoid Altering Class Variables via Instances
If you do `instance.classvariable = newvalue`, Python creates a NEW instance variable for that specific object instead of changing the class-wide value. Always use `ClassName.variablename` to update class variables.
Private Variables (Name Mangling)
Python doesn't have true "private" variables, but it uses a convention called Name Mangling. Any attribute starting with __ (double underscore) is "hidden."
3. Types of Methods
Instance Methods
The most common type. They take self as the first argument and can access/modify instance-specific data.
Class Methods
Bound to the class itself, not the instance. They take cls as the first argument and are marked with the @classmethod decorator. Use them for factory methods or modifying class state.
Static Methods
These don't take self or cls. They act like regular functions but are grouped within the class for organization (Utility functions).
Magic (Dunder) Methods
These have double underscores (e.g., __init__, __str__). They allow you to perform special operations like operator overloading.
4. Practical Example: Combining All Member Types
Here is a complete example that shows all three method types and all three variable types working together in a real-world Employee class:
When to Use Each Method Type
| Method Type | Use When... | Example |
|---|---|---|
| Instance Method | You need to access or modify self data | get_salary(), deposit() |
| Class Method | You need a factory or to read class-level state | from_string(), get_count() |
| Static Method | You have a utility function related to the class but not dependent on it | is_valid_email(), validate_id() |
Related Python OOP Topics
- Python OOP Overview: Classes and Constructors — start here if new to OOP
- Python Inheritance and Operator Overloading — extend classes with inheritance
- Python Scope and LEGB Rule — understanding how variable lookup works inside methods
- Python Functions and Parameters — the foundation before learning class methods
For the official reference, see the Python Classes documentation, the section on classmethod and staticmethod, and the Python data model: special method names.
Common Mistakes with Class Members
-
Modifying a class variable through an instance. Writing
instance.class_var = valuedoes not update the class-wide value — it creates a new instance variable that shadows it. Always useClassName.class_var = valueto update shared state. -
Putting mutable defaults in class variables. If a class variable is a list or dict, all instances share that same object. Appending to it in one instance affects all others. Define mutable attributes in
__init__instead. -
Overusing static methods. If a static method grows to need class or instance data, converting it to an instance or class method becomes awkward. When in doubt, start with an instance method.
-
Using double underscores (
__) for every private attribute. Name mangling (__attrbecomes_ClassName__attr) is intended to prevent accidental overriding in subclasses, not as a general privacy mechanism. Use a single underscore_attrfor most "internal" attributes. -
Confusing
@classmethodwith@staticmethod. Class methods receiveclsas their first argument and can access class state. Static methods receive neitherselfnorcls— they are plain functions scoped to the class namespace for organisation purposes.
Best Practices
- Use
@classmethodas factory methods to provide alternative constructors (from_string,from_dict). - Use
@staticmethodfor pure utility functions that logically belong in the class but don't need access toselforcls. - Expose private data via properties (
@property) rather than a plain getter method — it reads more naturally (obj.salaryvsobj.get_salary()). - Keep class variables for genuinely shared, read-only data (constants, registry entries) and instance variables for anything that differs per object.
- Document the distinction between class and instance variables with a class-level docstring so maintainers understand the intent.
- Always call
super().__init__()in subclass constructors to avoid breaking parent class initialization.
FAQ
What is the difference between a class method and a static method?
A class method receives cls as its first argument, giving it access to and the ability to modify class-level state. A static method receives no implicit first argument and behaves like a regular function that is namespaced inside the class for organisation. Use a class method when you need to access or change the class; use a static method when you just want to group a utility function with the class.
Can you call a class method on an instance?
Yes. instance.my_classmethod() works — Python passes the class (not the instance) as cls. However, calling it on the class directly (MyClass.my_classmethod()) is clearer and conventional.
What is name mangling in Python?
When an attribute name starts with two underscores (__attr), Python internally renames it to _ClassName__attr. This prevents accidental overriding in subclasses but does not provide true access control — the mangled name is still accessible from outside the class if you know it.
Conclusion
Understanding the difference between these members is key to writing clean, efficient OOP code. You now know how to manage shared data with Class Variables, protect data with Private Variables, and organize logic with Static Methods.
What's Next?
Up next, we'll explore Inheritance and how to reuse code across multiple classes!
Common Mistakes with Python Classes
1. Mutable default class attributes
Every instance shares the same list. Define mutable attributes in __init__ instead: self.members = []. See the Python class documentation.
2. Confusing @classmethod and @staticmethod
@classmethod receives the class as its first argument (cls) and can access or modify class state. @staticmethod receives no implicit first argument and is essentially a plain function namespaced inside the class. Use @classmethod for alternative constructors and factory methods.
3. Forgetting self in instance methods
Every instance method must have self as its first parameter. Omitting it causes TypeError: takes 0 positional arguments but 1 was given — Python automatically passes the instance as the first argument.
4. Using __class__ instead of type(self)
Inside a method, self.__class__ and type(self) are usually equivalent, but type(self) is more explicit and works correctly with metaclasses and __class__ cell optimisations.
5. Not using super() in __init__
When subclassing, forgetting super().__init__() means the parent class is never initialised. Always call super().__init__(*args, **kwargs) in the child's __init__ unless you deliberately want to skip parent initialisation.
Frequently Asked Questions
What is the difference between a class attribute and an instance attribute?
A class attribute is defined at class level and shared across all instances. An instance attribute is defined inside __init__ (or other methods) with self.attr = value and belongs to a specific instance. Instance attributes shadow class attributes of the same name. The Python data model documentation covers the attribute lookup chain.
When should I use @property instead of a regular attribute?
Use @property when you need to compute a value on access, validate a value on assignment, or maintain backward compatibility when changing a public attribute to computed logic. It provides getter/setter semantics with clean dot-notation access.
What is __slots__ and when should I use it?
__slots__ replaces the per-instance __dict__ with a fixed set of attributes, reducing memory usage significantly for classes with many instances. Use it for data-heavy classes (e.g. holding millions of records) where memory is a concern. The trade-off is that you cannot add arbitrary attributes at runtime.
