The `functor` package uses Python black magic to turn functions into objects (functors), letting them access their own instance via `functor.self`.
Project description
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.selfinside 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
functormodule 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 toFalse.
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:
RuntimeErrorif accessed outside of a valid context.
⚠️ Caveats
- Performance: Because the library relies on
sys._getframeand 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. - Debugging: Since the function's
__globals__are swapped for a proxy during execution, some debuggers might display the environment differently than expected.
License: MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file functor-0.0.1b1.dev0.tar.gz.
File metadata
- Download URL: functor-0.0.1b1.dev0.tar.gz
- Upload date:
- Size: 9.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc3d7a029b408dc337b76a67514c03bfd354f96807e69481a2c0fef26eed7dd1
|
|
| MD5 |
d3c0eafb3be323ec8658356a26d23667
|
|
| BLAKE2b-256 |
96768472371631deb19ea6f657b00f0e9684b6bde44d2a767b0c99a8311676da
|
File details
Details for the file functor-0.0.1b1.dev0-py3-none-any.whl.
File metadata
- Download URL: functor-0.0.1b1.dev0-py3-none-any.whl
- Upload date:
- Size: 7.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdbc54678a174e22e5a0d803b52191c0afa308a056b10af8d898715a7f471f70
|
|
| MD5 |
d7a923b61b46f4ae205178f1466a3965
|
|
| BLAKE2b-256 |
43baf348377b0250f7440f0a23cc501416ff6d02f8734f831c5a3f60f14e47b4
|