On Wed, Mar 04, 2020 at 12:19:25PM +0200, Alex Hall wrote:
> Can you explain where `except ParameterError` would produce better code
> than the best current alternative?

Serhiy came up with a good use-case that I hadn't considered: functions 
which take arbitrary callback functions as argument, e.g. sorted() with 
a key function.

Both of these calls raise TypeError, but for different reasons:

    # right number of arguments passed to the key function, 
    # but the wrong argument type
    sorted([3, 5, 1], key=len)

    # wrong number of arguments passed to the key function
    sorted([3, 5, 1], key=isinstance)

It might be useful to be able to distinguish the two cases.

My earlier use-case still stands: feature detection where a function has 
changed its parameter list. More on this below.


> It seems to me that using this is like
> stating "this code might be wrong" and would generally produce bad code.

It seems to me that your comment above could be equally said about *any* 
use of exceptions: "this code might be wrong, so we'll stick it in a 
try...except block". Only that's not how most of us actually use 
exceptions.


> For example if I wanted to use math.gcd on multiple values but I need to
> support Python versions that only allow two arguments, then I'll just apply
> it to two arguments at a time, maybe with functools.reduce.

I've done that myself. Not specifically with gcd, but with other 
functions, which I don't remember off the top of my head.

gcd is a particularly simple example because it is so easy to wrap. 
Excluding function header and docstring, the code is just six lines:

    if len(args) == 0:
        return 1
    elif len(args) == 1:
        return abs(args[0])
    else:
        return reduce(_gcd, args)

Not all cases will be that simple, or they may involve a serious 
performance cost. In general, the official version is going to be 
faster and better tested than the wrapper version.

Why shouldn't I use the fast, well-tested standard version if it is 
available? I just need a reliable way to detect the needed feature.


This is not specifically about gcd. It could be about functions of 
arbitrary complexity:

    try:
        # Test whether the aardvark function supports a 
        # `hovercraft` parameter.
        result = aardvark(
                     spam, eggs, cheese, hovercraft=1
                     )
    except ParameterError:
        # No hovercraft parameter allowed, create a wrapper.
        ...

TypeError is less satisfactory because I cannot easily distinguish the 
two cases:

1. The 'hovercraft' parameter is not available;

2. The 'hovercraft' parameter is available, but I have made some other 
error in the function call which results in a TypeError.


> And in general
> if I want to distinguish between versions I'd much rather just check the
> version and thus assert "this code is correct for this version".

Feature detection is more reliable.

What if the caller of my library has back-ported the new, advanced 
version of aardvark() to their Python? Instead of using the faster, 
better tested official backport, my code will use my wrapper.

What if the caller is using my library with another interpreter, say 
PyPy or Jython, which doesn't support the feature I need? With feature 
detection, my code will simply fall back to the wrapper. With version 
checking, it will wrongly assert the feature is available, and then 
crash later.

As far as I can tell, feature detection has more or less completely 
overshadowed version checks in the browser and Javascript space. In my 
opinion, checking the version should only be used when it is too hard to 
detect the feature.

> If you catch ParameterError, how do you know that it came directly from the
> line you caught it from and not deeper within?

Does it matter?

If the call aardvark(*args, hovercraft=1) leaks a ParameterError from 
deep inside its internals, then even if the feature is technically 
available according to a version check, it is too buggy to use and I 
need to use my wrapper.


> If you want to check that you're passing parameters properly, I suggest
> writing code like this:
> 
> import inspect
> 
> signature = inspect.signature(func)

And what if the function I'm checking doesn't support signature 
metadata?

https://docs.python.org/3/library/inspect.html#inspect.signature

I can wrap the call to signature() in try...except, but what's my 
fallback if I can't check the signature?

    py> inspect.signature(math.gcd)
    Traceback (most recent call last):
    [...]
    TypeError: 'feature_version' is an invalid keyword argument 
    for compile()


-- 
Steven
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/7SXIB2W7PJGWAM72MOXBWMI5G6OXKAMG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to