or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asynctools.mdbuiltins.mdcontextlib.mdfunctools.mdheapq.mdindex.mditertools.md

functools.mddocs/

0

# Functional Programming

1

2

Async versions of functools utilities including reduction, caching, and property decorators designed for async functions and methods. These tools enable functional programming patterns in async contexts.

3

4

## Capabilities

5

6

### Reduction Operations

7

8

Apply functions cumulatively to items in async iterables.

9

10

```python { .api }

11

async def reduce(function, iterable, initial=None):

12

"""

13

Apply function cumulatively to items in iterable.

14

15

Parameters:

16

- function: Callable[[T1, T2], T1] - Binary function to apply

17

- iterable: AnyIterable[T2] - Iterable to reduce

18

- initial: T1, optional - Initial value

19

20

Returns:

21

T1 - Final accumulated value

22

23

Raises:

24

TypeError - If iterable is empty and no initial value provided

25

"""

26

```

27

28

Usage example:

29

```python

30

async def reduction_example():

31

async def numbers():

32

for i in range(1, 6):

33

yield i

34

35

# Calculate factorial: 1 * 2 * 3 * 4 * 5

36

factorial = await reduce(lambda x, y: x * y, numbers()) # 120

37

38

# Sum with initial value

39

total = await reduce(lambda x, y: x + y, numbers(), 10) # 25

40

```

41

42

### Caching Decorators

43

44

Memoization decorators for async functions with LRU (Least Recently Used) eviction.

45

46

```python { .api }

47

def lru_cache(maxsize=128, typed=False):

48

"""

49

LRU cache decorator for async functions.

50

51

Parameters:

52

- maxsize: int or None - Maximum cache size (None for unlimited)

53

- typed: bool - If True, cache separate entries for different argument types

54

55

Returns:

56

Decorator function that wraps async callables with caching

57

58

Usage:

59

@lru_cache(maxsize=256)

60

async def expensive_async_operation(param):

61

# ... expensive computation

62

return result

63

"""

64

65

def cache(user_function):

66

"""

67

Simple cache decorator for async functions (equivalent to lru_cache(maxsize=None)).

68

69

Parameters:

70

- user_function: Async callable to cache

71

72

Returns:

73

Cached version of the function

74

75

Usage:

76

@cache

77

async def compute_value(x, y):

78

# ... expensive computation

79

return result

80

"""

81

```

82

83

### Cached Properties

84

85

Property descriptors that cache async computation results.

86

87

```python { .api }

88

class CachedProperty:

89

"""

90

Cached property descriptor for async getters.

91

"""

92

93

def __init__(self, getter, lock_type=...):

94

"""

95

Parameters:

96

- getter: Callable[[T], Awaitable[R]] - Async getter function

97

- lock_type: type[AsyncContextManager[Any]], optional - Lock type for thread safety

98

"""

99

100

def __set_name__(self, owner, name):

101

"""Set the attribute name on the owner class."""

102

103

def __get__(self, instance, owner):

104

"""

105

Get cached property value.

106

107

Returns:

108

Awaitable[R] - Awaitable that resolves to cached value

109

"""

110

111

def __set__(self, instance, value):

112

"""Set cached value directly."""

113

114

def __del__(self, instance):

115

"""Delete cached value."""

116

117

def cached_property(getter):

118

"""

119

Decorator to create cached property from async getter.

120

121

Parameters:

122

- getter: Callable[[T], Awaitable[R]] - Async getter function

123

124

Returns:

125

CachedProperty[T, R] - Cached property descriptor

126

127

Usage:

128

class MyClass:

129

@cached_property

130

async def expensive_property(self):

131

# ... expensive async computation

132

return result

133

"""

134

```

135

136

## Usage Examples

137

138

### Caching Expensive Operations

139

```python

140

from asyncstdlib import lru_cache, cache

141

import aiohttp

142

143

@lru_cache(maxsize=100)

144

async def fetch_user_data(user_id):

145

"""Cache user data fetches to avoid repeated API calls."""

146

async with aiohttp.ClientSession() as session:

147

async with session.get(f"/api/users/{user_id}") as response:

148

return await response.json()

149

150

@cache

151

async def compute_fibonacci(n):

152

"""Cache fibonacci computation (unlimited cache size)."""

153

if n <= 1:

154

return n

155

# Note: This creates a simple recursive cache

156

return await compute_fibonacci(n-1) + await compute_fibonacci(n-2)

157

158

async def caching_example():

159

# First call fetches from API

160

user1 = await fetch_user_data("123")

161

162

# Second call returns cached result

163

user1_cached = await fetch_user_data("123")

164

165

# Fibonacci with caching

166

result = await compute_fibonacci(10) # 55

167

```

168

169

### Cached Properties

170

```python

171

import asyncio

172

from asyncstdlib import cached_property

173

174

class DataProcessor:

175

def __init__(self, data_source):

176

self.data_source = data_source

177

178

@cached_property

179

async def processed_data(self):

180

"""Expensive data processing, cached after first access."""

181

print("Processing data...") # Only prints once

182

await asyncio.sleep(1) # Simulate expensive operation

183

return [item.upper() for item in self.data_source]

184

185

@cached_property

186

async def data_summary(self):

187

"""Summary depends on processed data."""

188

data = await self.processed_data # Uses cached value

189

return {

190

"count": len(data),

191

"first": data[0] if data else None,

192

"last": data[-1] if data else None

193

}

194

195

async def property_example():

196

processor = DataProcessor(["hello", "world", "async"])

197

198

# First access processes and caches

199

data1 = await processor.processed_data # "Processing data..." printed

200

201

# Second access uses cache

202

data2 = await processor.processed_data # No print, returns cached value

203

204

# Summary uses cached processed_data

205

summary = await processor.data_summary

206

print(summary) # {'count': 3, 'first': 'HELLO', 'last': 'ASYNC'}

207

```

208

209

### Advanced Reduction Operations

210

```python

211

async def advanced_reduction():

212

async def transactions():

213

data = [

214

{"type": "deposit", "amount": 100},

215

{"type": "withdrawal", "amount": 30},

216

{"type": "deposit", "amount": 50},

217

{"type": "withdrawal", "amount": 20}

218

]

219

for tx in data:

220

yield tx

221

222

# Calculate running balance

223

def apply_transaction(balance, transaction):

224

if transaction["type"] == "deposit":

225

return balance + transaction["amount"]

226

else:

227

return balance - transaction["amount"]

228

229

final_balance = await reduce(apply_transaction, transactions(), 0)

230

print(f"Final balance: ${final_balance}") # Final balance: $100

231

232

# Find maximum value with custom comparison

233

async def values():

234

for x in [3, 1, 4, 1, 5, 9, 2, 6]:

235

yield x

236

237

maximum = await reduce(lambda a, b: a if a > b else b, values())

238

print(f"Maximum: {maximum}") # Maximum: 9

239

```

240

241

### Custom Lock Types for Thread Safety

242

```python

243

import asyncio

244

from asyncstdlib import cached_property

245

246

class ThreadSafeProcessor:

247

@cached_property(asyncio.Lock) # Use asyncio.Lock for thread safety

248

async def shared_resource(self):

249

"""Thread-safe cached property."""

250

await asyncio.sleep(0.1)

251

return "computed value"

252

253

# For trio users:

254

# @cached_property(trio.Lock)

255

# async def trio_safe_property(self): ...

256

```