Python 101 · Functions

Feb 13, 2016 | Tech Software

Index
Index

Definitions

  • Basics

    : the def keyword, docstring, arguments, and return.
  • Typed Hints

    : defined with type hints (soft suggestions) for arguments and return, enhancing readability and allowing static analysis.
  • Typed Checks

    : defined with type checks (hard rules) for arguments and return, via the typeguard module and @typechecked decorator.

Arguments

  • Positional, Keywords

    : positional args depend on the order, while keyword args are identified by the parameter name.
  • Default Values

    : parameters with predefined values that are used if no argument is provided during the call.
  • Variadic

    : *args collects extra positional args into a tuple, and **kwargs collects extra keyword args into a dictionary.
  • Unpacking

    : using * or ** to explode a sequence (list/tuple) or a dictionary into individual function arguments.
  • Keyword-Only

    : forcing specific arguments to be passed only by name using a standalone * in the parameter list.
  • Signature Order

    : Standard -> *args -> Keyword-only -> **kwargs.
  • Default Value Pitfalls

    : default values are evaluated only once at definition time, causing all calls to share the same object if it is mutable.
  • In Python, functions are objects. The default args are stored in the function's __defaults__ and __kwdefaults__ attributes when the code is first loaded.
  • If you use mutables as defaults and modify these objects, they stay modified throughout the program.
  • For mutable and immutable types, see Python 101 · Data Types and Behaviors.
  • Unless you know exactly what you are doing (like caching), use None instead of [] or {} as default parameters.

Enclosing and Closure

  • Enclosing (Environment)

    : refers to the scope of the outer function in a nested structure; it is a lookup rule for variable resolution.
  • Closure (Entity)

    : an object created when an inner function references variables from its Enclosing Scope and is returned as a functional unit.
What happens in the Enclosing Scope?
  • When power_factory(2) executes, it creates an environment where the variable exp is assigned the value 2.
How is a Closure formed?
  • Even after power_factory finishes, the returned square function "carries" that environment (exp=2) with it. This "function-plus-environment" entity is the closure.
What's the necessity and why they are linked?
  • Without Enclosing Scope, the Closure has no place to store data.
  • Without the Closure, the Enclosing Variables would be destroyed the moment the function finishes.
  • The Closure is a way to "carry or memorize" the the Environment with it.
Key Takeaway
  • A Closure can leverage the Enclosing Scope to "persist" data without relying on global variables.

Scope and LEGB

  • LEGB

    : the lookup order Python follows for Name Resolution; when searching variable names, Python starts from your immediate vicinity and expands outward by order.
  • L (Local)

    : variables defined within a function or lambda; created at call time and destroyed once the function returns.
  • E (Enclousing)

    : scope of the outer function in a nested structure; accessible to the inner function but it doesn't own.
  • G (Global)

    : variables defined at the top level of a module (.py file); visible throughout the entire file.
  • B (Built-in)

    : names pre-defined by the Python interpreter, such as len, int, and print.
Scope Defined In Lifetime
Local (L) Current function or lambda Created at call; destroyed on return
Enclosing (E) Outer / Parent function Persists as long as the Closure instance exists
Global (G) Top level of the script or module Until the script ends
Built-in (B) Python Interpreter internals Always available while Python is running
  • global, nonlocal

    : in the L scope, you can read variables from G and E scopes directly; however, to modify them, you must explicitly specify global or nonlocal; otherwise, Python will treat the assignment as the creation of a new L variable.

Functional

  • lambda

    : a simple, one-time anonymous function defined with a single expression lambda arguments: expression.
  • lambda pitfall

    : enclosing scope variable reference.
  • Higher-Order Functions

    : functions that take other functions as inputs or return them.
  • Decorator

    : higher-order functions that take a function/object as an argument and return a new function/object to replace it; and add extra functionality (like putting on a "outer layer) without modifying the original function's source code.
  • Decorator w/ Arguments

    : by default, the @decorator syntax passes only the decorated function (func) to the decorator. If you write @timer_decorator("Log"), Python first executes timer_decorator("Log") and expects it to return the actual decorator.
  • Dotted Decorator

    : essentially decorators as class methods, allowing for more flexible and stateful behavior; commonly seen in frameworks such as Flask.
Method Code Feature
Decorator @my_decorator
def my_func(): pass
simple, elegant, readable
Assignment my_func = my_decorator(my_func) shows the decorator's underlying logic, function reassignment
  • Decorator for Classes

    : in principle, decorators are higher-order functions that map one object to another. Since functions and classes are both first-class citizens in Python, they are equally eligible for decoration; e.g., @dataclass is designed to decorate classes.

Pythonic

  • Introspection

    : methods to examine element properties at runtime such as locals(), globals(), hasattr(), and dir(), isinstance(), issubclass(), etc.
  • Recursion

    : a programming technique where a function calls itself to solve a smaller instance of the same problem until it reaches a base case; it's elegant, but memory intensive and difficult to debug.

Note: Python has a default recursion step limit, you can check and modify it as above.