Fundamentals 19 min read

Master Python Class/Static Methods, Copy Techniques, Decorators & Memory Basics

This article explains Python class methods versus static methods, compares shallow and deep copying, details decorator usage and implementation, and describes how variables and objects are stored in memory, providing clear examples and best‑practice guidelines for each concept.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Master Python Class/Static Methods, Copy Techniques, Decorators & Memory Basics

Python Class Methods vs Static Methods

Class Methods

Class methods are defined with the @classmethod decorator; their first parameter is conventionally named cls and represents the class itself.

Features

Can access and modify class state.

Cannot access instance state.

Often used to define alternative constructors.

Example

class MyClass:
    class_variable = 0

    @classmethod
    def increment_class_variable(cls):
        cls.class_variable += 1

    @classmethod
    def from_string(cls, string_param):
        # alternative constructor
        return cls(int(string_param))

# Using class methods
MyClass.increment_class_variable()
obj = MyClass.from_string("10")

Static Methods

Static methods are defined with the @staticmethod decorator and do not receive any special first argument.

Features

Cannot access or modify class state.

Cannot access instance state.

Primarily used to group related functionality inside a class.

Example

class MathOperations:
    @staticmethod
    def add(x, y):
        return x + y

    @staticmethod
    def multiply(x, y):
        return x * y

# Using static methods
result = MathOperations.add(5, 3)

Main Differences

Parameters : Class methods receive the class as an implicit first argument; static methods receive none.

Access to class attributes : Class methods can read and modify class attributes; static methods cannot.

Use cases :

Class methods are suited for operations that need class state, such as alternative constructors.

Static methods are suited for functionality related to the class but not requiring class state.

Inheritance behavior : When a subclass inherits a class method, the cls argument points to the subclass; static methods behave the same across inheritance.

Choosing Which to Use

If the method needs to access or modify class attributes, use a class method.

If the method does not need class or instance state and simply provides related functionality, use a static method.

If the method belongs logically to the class but does not require any state, a static method is appropriate.

Python Shallow vs Deep Copy

When copying objects in Python there are two main approaches: shallow copy and deep copy. Understanding their differences is essential for handling complex data structures correctly.

Shallow Copy

A shallow copy creates a new container object but inserts references to the original elements.

Features

Creates a new object.

Elements are references to the original objects.

Only copies the first level of the container.

Implementation

Using slice syntax [:].

Using the copy() method.

Using the copy module’s copy() function.

Example

import copy

original = [1, [2, 3], 4]
shallow = copy.copy(original)
# Modify nested list in shallow copy
shallow[1][0] = 'X'
print(original)   # Output: [1, ['X', 3], 4]
print(shallow)    # Output: [1, ['X', 3], 4]

Deep Copy

A deep copy creates a new container and recursively copies all nested objects, producing a fully independent duplicate.

Features

Creates a completely new object.

Recursively copies every nested object.

The original and the copy are completely independent.

Implementation

Using the copy module’s deepcopy() function.

Example

import copy

original = [1, [2, 3], 4]
deep = copy.deepcopy(original)
# Modify nested list in deep copy
deep[1][0] = 'X'
print(original)   # Output: [1, [2, 3], 4]
print(deep)      # Output: [1, ['X', 3], 4]

Main Differences

Copy depth : Shallow copy copies only the top level; deep copy copies all levels.

Memory usage : Deep copy uses more memory because it creates copies of all nested objects.

Performance : Deep copy is generally slower, especially for large or complex structures.

Independence : Objects created by deep copy are fully independent; shallow copies share parts of the original data.

Use Cases

Shallow copy when only the top‑level container needs duplication and nested objects can be shared.

Deep copy when a completely independent replica of a complex structure is required.

Notes

Immutable objects (e.g., tuples) behave the same for shallow and deep copy.

Circular references are handled by deepcopy() which includes a mechanism to avoid infinite recursion.

Custom classes can control copying by implementing __copy__ and __deepcopy__ methods.

Python Decorators Explained

Decorators are a powerful Python feature that allow you to modify or enhance the behavior of functions or classes without changing their source code.

Basic Concept

A decorator is essentially a function that takes another function as an argument and returns a new function.

Basic Syntax

@decorator_function
def target_function():
    pass

This is equivalent to:

def target_function():
    pass

target_function = decorator_function(target_function)

Simple Decorator Examples

1. Function Decorator

def uppercase_decorator(func):
    def wrapper():
        result = func()
        return result.upper()
    return wrapper

@uppercase_decorator
def greet():
    return "hello, world!"

print(greet())  # Output: HELLO, WORLD!

2. Parameterized Decorator

def repeat_decorator(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat_decorator(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")  # Prints the greeting 3 times

Advanced Uses

1. Class as Decorator

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0
    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

2. Preserving Metadata

Use functools.wraps inside a decorator to keep the original function’s name, docstring, etc.

from functools import wraps

def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('Before call')
        result = func(*args, **kwargs)
        print('After call')
        return result
    return wrapper

@my_decorator
def greet(name):
    """Greet someone"""
    print(f"Hello, {name}!")

print(greet.__name__)  # greet
print(greet.__doc__)   # Greet someone

Common Applications

Logging

Performance measurement

Access control and authentication

Caching

Error handling and retry logic

Important Notes

Decorators execute at function definition time, not at call time.

Multiple decorators stack; they are applied from the bottom up.

They can affect performance, especially when used on frequently called functions.

Use functools.wraps to preserve original metadata.

How Decorators Work

Python treats functions as first‑class objects, supports closures, and provides syntactic sugar ( @) to simplify decorator usage.

1. Functions as First‑Class Citizens

Functions can be assigned to variables, passed as arguments, and returned from other functions.

2. Closures

Inner functions can capture variables from the enclosing scope, forming a closure.

3. Basic Implementation

def simple_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

def say_hello():
    print("Hello!")

say_hello = simple_decorator(say_hello)

4. Syntax Sugar

@simple_decorator
def say_hello():
    print("Hello!")

5. Parameterized Decorators

def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hello(name):
    print(f"Hello, {name}!")

6. Class Decorators

class CountCalls:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0
    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f"Call {self.num_calls} of {self.func.__name__!r}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

7. Execution Timing

Decorators run when the function is defined (module import time), allowing them to modify behavior early.

8. Multiple Decorators

@decorator1
@decorator2
def func():
    pass

This is equivalent to func = decorator1(decorator2(func)).

How Python Stores Variables in Memory

Understanding Python’s memory model helps you write more efficient code.

1. Variable‑Object Relationship

Variables are references to objects. Assigning a value creates an object and binds the variable name to its memory address.

x = 5

2. Object Representation

Each object contains at least three parts: a type identifier, a reference count, and the actual value.

3. Storage by Type

Small Integers

Python caches small integers (usually –5 to 256); all references to the same value point to the same object.

a = 5
b = 5
print(a is b)  # True

Large Integers

Large integers are created anew each time.

a = 1000
b = 1000
print(a is b)  # False

Strings

Python also interns identical strings, so they often share the same object.

a = "hello"
b = "hello"
print(a is b)  # True

Mutable Objects (e.g., Lists)

Each creation of a mutable object allocates new memory.

a = [1, 2, 3]
b = [1, 2, 3]
print(a is b)  # False

4. Variable Assignment

Assigning a variable changes the reference it points to; it does not modify the original object.

x = 5   # x references integer 5
x = 10  # x now references integer 10

5. Reference Counting & Garbage Collection

Python uses reference counting to manage memory. When an object’s count drops to zero, the garbage collector frees it.

x = 5
y = x   # reference count becomes 2
del x    # count back to 1, y still holds the object

6. Memory Views

The id() function returns an object’s memory address.

x = 5
print(id(x))

7. Mutable vs Immutable Objects

Immutable objects (integers, strings, tuples) create a new object when their value appears to change.

Mutable objects (lists, dictionaries) can be modified in place without creating a new object.

# Immutable example
x = 5
print(id(x))
x += 1
print(id(x))  # address changes

# Mutable example
lst = [1, 2, 3]
print(id(lst))
lst.append(4)
print(id(lst))  # address stays the same
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Pythondeep copydecoratorsclass methodsstatic methods
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.