1
1
from functools import reduce , partial
2
2
import inspect
3
3
import operator
4
+ import sys
4
5
5
6
6
7
__all__ = ('identity' , 'thread_first' , 'thread_last' , 'memoize' , 'compose' ,
@@ -84,6 +85,13 @@ def evalform_back(val, form):
84
85
return reduce (evalform_back , forms , val )
85
86
86
87
88
+ # This is a kludge for Python 3.4.0 support
89
+ # currently len(inspect.getargspec(map).args) == 0, a wrong result.
90
+ # As this is fixed in future versions then hopefully this kludge can be
91
+ # removed.
92
+ known_numargs = {map : 2 , filter : 2 , reduce : 2 }
93
+
94
+
87
95
def _num_required_args (func ):
88
96
""" Number of args for func
89
97
@@ -99,6 +107,8 @@ def _num_required_args(func):
99
107
>>> print(_num_required_args(bar))
100
108
None
101
109
"""
110
+ if func in known_numargs :
111
+ return known_numargs [func ]
102
112
try :
103
113
spec = inspect .getargspec (func )
104
114
if spec .varargs :
@@ -142,8 +152,10 @@ def __init__(self, func, *args, **kwargs):
142
152
raise TypeError ("Input must be callable" )
143
153
144
154
# curry- or functools.partial-like object? Unpack and merge arguments
145
- if (hasattr (func , 'func' ) and hasattr (func , 'args' )
146
- and hasattr (func , 'keywords' )):
155
+ if (hasattr (func , 'func' )
156
+ and hasattr (func , 'args' )
157
+ and hasattr (func , 'keywords' )
158
+ and isinstance (func .args , tuple )):
147
159
_kwargs = {}
148
160
if func .keywords :
149
161
_kwargs .update (func .keywords )
@@ -219,6 +231,45 @@ def __setstate__(self, state):
219
231
self .__dict__ .update (userdict )
220
232
221
233
234
+ def has_kwargs (f ):
235
+ """ Does a function have keyword arguments?
236
+
237
+ >>> def f(x, y=0):
238
+ ... return x + y
239
+
240
+ >>> has_kwargs(f)
241
+ True
242
+ """
243
+ if sys .version_info [0 ] == 2 : # pragma: no cover
244
+ spec = inspect .getargspec (f )
245
+ return bool (spec and (spec .keywords or spec .defaults ))
246
+ if sys .version_info [0 ] == 3 : # pragma: no cover
247
+ spec = inspect .getfullargspec (f )
248
+ return bool (spec .defaults )
249
+
250
+
251
+ def isunary (f ):
252
+ """ Does a function have only a single argument?
253
+
254
+ >>> def f(x):
255
+ ... return x
256
+
257
+ >>> isunary(f)
258
+ True
259
+ >>> isunary(lambda x, y: x + y)
260
+ False
261
+ """
262
+ try :
263
+ if sys .version_info [0 ] == 2 : # pragma: no cover
264
+ spec = inspect .getargspec (f )
265
+ if sys .version_info [0 ] == 3 : # pragma: no cover
266
+ spec = inspect .getfullargspec (f )
267
+ return bool (spec and spec .varargs is None and not has_kwargs (f )
268
+ and len (spec .args ) == 1 )
269
+ except TypeError : # pragma: no cover
270
+ return None # in Python < 3.4 builtins fail, return None
271
+
272
+
222
273
@curry
223
274
def memoize (func , cache = None , key = None ):
224
275
""" Cache a function's result for speedy future evaluation
@@ -260,12 +311,10 @@ def memoize(func, cache=None, key=None):
260
311
cache = {}
261
312
262
313
try :
263
- spec = inspect .getargspec (func )
264
- may_have_kwargs = bool (not spec or spec .keywords or spec .defaults )
314
+ may_have_kwargs = has_kwargs (func )
265
315
# Is unary function (single arg, no variadic argument or keywords)?
266
- is_unary = (spec and spec .varargs is None and not may_have_kwargs
267
- and len (spec .args ) == 1 )
268
- except TypeError :
316
+ is_unary = isunary (func )
317
+ except TypeError : # pragma: no cover
269
318
may_have_kwargs = True
270
319
is_unary = False
271
320
0 commit comments