Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

functor

The package functor is a Python black magic library that bridges the gap between functions and objects. It upgrades standard functions into Function Objects (Functors), allowing them to access their own instance via functor.self from within their own scope.

This enables state persistence, self-reference (recursion), and metadata management without needing to pass an explicit self argument or write boilerplate class structures.

✨ Key Features

  • Implicit Context Injection: Access the current function instance directly via functor.self inside the decorated function.
  • State Persistence: Functions are objects. You can attach attributes to them just like class instances.
  • Module as a Class: The library leverages the "Module as a Class" pattern. The functor module itself is callable and acts as the factory.

📦 Installation

pip install functor

🚀 Quick Start

1. Stateful Functions

Standard Python functions cannot easily retain state without using global or nonlocal. With @functor, functions behave like single-method classes:

import functor


@functor
def counter():
    # Initialize state on the function instance itself
    if not hasattr(functor.self, 'count'):
        functor.self.count = 0
    
    functor.self.count += 1
    return functor.self.count


print(counter()) # Output: 1
print(counter()) # Output: 2
print(counter.count) # Output: 2

2. Recursion & Self-Reference

Recursion usually requires hardcoding the function name. functor allows you to decouple the logic from the name:

import functor


@functor
def factorial(n):
    if n == 0:
        return 1
    # Use functor.self to call the function recursively
    # This works even if the function is assigned to a different variable name
    return n * functor.self(n - 1)


print(factorial(5)) # Output: 120

3. Bound Mode

functor can also be used inside classes. By using bound=True, you can control how the instance binding works.

import functor


@functor(bound=True)
def factorial(self, n):
    if n == 0:
        return 1
    # Use self to call the function recursively
    return n * self(n - 1)


print(factorial(5)) # Output: 120

4. Inheritance of functor

functor can also be used inside classes. By using bound=True, you can control how the instance binding works.

from functor import functor


class Factorial(functor):
    def minus(self, n, value):
        return self(n - value)


@Factorial
def factorial(n):
    if n == 0:
        return 1
    return n * Factorial.self.minus(n, 1)


print(factorial(5)) # Output: 120

Module as a Class

It can be noticed that import functor can be used simply for @functor. This is because the library replaces the standard module object in sys.modules with a custom FunctorModule instance.

import functor


# 'functor' is a module which is callable
print(type(functor))  # <class 'functor.FunctorModule'>

Nonetheless, from functor import functor can also be used.

from functor import functor


# 'functor' is a type
print(type(functor))  # <class 'type'>

📝 API Reference

@functor / @functor(bound=True)

The core decorator/constructor.

  • function (FunctionType): The function to wrap. It should contain a valid __code__ attribute in principle.
  • bound (bool): Whether to bind the first argument to the current functor instance. Defaults to False.

Returns: A callable functor instance that proxies the original function while enabling state management.

functor.self

A magic accessor valid only inside a function decorated with @functor when not bound. It returns the current functor instance.

  • Raises: RuntimeError if accessed outside of a valid context.

⚠️ Caveats

  1. Performance: Because the library relies on sys._getframe and global variable proxying, there is a slight overhead compared to standard function calls. It is best used for logic-heavy or stateful operations, not tight loops in critical paths.
  2. Debugging: Since the function's __globals__ are swapped for a proxy during execution, some debuggers might display the environment differently than expected.

License: MIT

Metadata

Release files for functor 0.0.1b1.dev0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for functor 0.0.1b1.dev0
File Size Uploaded
functor-0.0.1b1.dev0.tar.gz 9.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for functor 0.0.1b1.dev0
File Interpreter ABI Platform
functor-0.0.1b1.dev0-py3-none-any.whl Python 3 none any Details

Total release size: 16.9 kB

Release files / functor-0.0.1b1.dev0.tar.gz

Download URL functor-0.0.1b1.dev0.tar.gz
Size 9.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bc3d7a029b408dc337b76a67514c03bfd354f96807e69481a2c0fef26eed7dd1
BLAKE2b-256 checksum
How to use checksums
96768472371631deb19ea6f657b00f0e9684b6bde44d2a767b0c99a8311676da
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.10.18

Release files / functor-0.0.1b1.dev0-py3-none-any.whl

Download URL functor-0.0.1b1.dev0-py3-none-any.whl
Size 7.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bdbc54678a174e22e5a0d803b52191c0afa308a056b10af8d898715a7f471f70
BLAKE2b-256 checksum
How to use checksums
43baf348377b0250f7440f0a23cc501416ff6d02f8734f831c5a3f60f14e47b4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.10.18

Release history Release notifications | RSS feed

This release

0.0.1b1.dev0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page