On 7/17/06, Andrew Koenig <[EMAIL PROTECTED]> wrote: > I note in PEP 3000 the proposal to remove callable(), with the comment "just > call the object and catch the exception." > > I think that's a bad idea, because it takes away the ability to separate the > callability test from the first call. As a simple example, suppose you're > writing a function that you expect to be given a function as one of its > arguments: > > def foo(bar, fun): > assert callable(fun) > # ... > > It might be that foo doesn't actually call fun until much later. > Nevertheless, from a testing viewpoint, it would be better to detect the > error immediately of passing something that can't be called. > > If you didn't have callable, how would you write this example?
I might equivalently hasattr(type(fun), '__call__') [[net of oldstyle classes, which won't be around in py3k anyway:-)]] and it would be just as feeble -- essentially because when the time comes to CALL fun, it will be called with specific signature[s], not "in a void". IOW, callable as it stands is feeble because it tries to check for some too-wide category of types -- all types whose instances may be called in SOME way or other, while in fact the call[s] when they come will use *specific* signatures. This general kind of problem is of course familiar to users of compile-time-checked languages, who may be able e.g. to specify "x is an int" when what they really need is to assert "x is an even positive int" and the like -- but being a familiar evil does not make it any more sensible to me. If 'callable' is to stay, then in order to pull its weight it needs to grow to provide a way to check "callable with the following signature" -- at the very least in terms of numbers and names of arguments, though (if py3k does gain some syntax for specifying argument types) it might do more. E.g., just "callable(fun)" should mean "fun appears to be callable without arguments, e.g. I believe that doing 'fun()' will not result in a TypeError from the call operation itself", while "callable(fun, int, zap=list[int])" should mean "fun appears to be callable with one positional argument that's an int and an argument named zap that is a list of ints", i.e. the apparently-acceptable call is of some form such as "fun(23, [4, 5])" [[presumably using object as a placeholder for unchecked-types]] -- so that for example a def fun(zip, zap): would be OK (the name of the 2nd arg is correct, and fun doesn't check argument types so passing int and list of int looks like it should be OK), as would, say, def fun(zip: float, **k): assuming int->float is intrinsically accepted, since **k accepts arbitrary named arguments, but for example def fun(zip, zop): would not pass the check, since the misnamed 2nd argument would produce a type error at calltime; etc, etc. The def statement (or __init__/__new__ for callability of classes, or __call__ for callability of instances) should record enough information about acceptable signatures to make this enriched "callable" conceptually feasible, as long as we accept some false positives (we probably should be ready to accept them, since it's unfeasible to say exactly what further constraints fun's code body could place on acceptable arguments, sigh). Perhaps the best syntax for the functionality in question might be different: e.g., callable(<list of arguments, which are types and may be named>) could be some kind of type or interface, so that one would check with isinstance(fun, callable()) to check if fun is callable without arguments, etc, etc; this should have the advantage of playing well with functions specifying constraints on their arguments, so that e.g. def foo(bar, fun: callable()): would be the vastly-preferred way to express the code snippet you give (assuming that you want fun to be "callable _without arguments_" specifically, of course -- but then, I've already argued that being "callable in SOME ways that nobody can guess" is not a sensible constraint to check for, hm?-). Putting typechecks in foo's signature records them for posterity and eases somebody else's task of checking if *foo* itself is callable in the way they'd like to call it... Alex _______________________________________________ Python-3000 mailing list Python-3000@python.org http://mail.python.org/mailman/listinfo/python-3000 Unsubscribe: http://mail.python.org/mailman/options/python-3000/archive%40mail-archive.com