On Wed, May 06, 2020 at 09:17:15PM -0400, Eric V. Smith wrote:

> I think David is right: itertools.chain.from_iterable() is the only 
> place I know of with an attribute on a function that's another function.

Functions decorated with `functools.wrap` have an attribute that gives 
the original function:

    py> def f(): return True
    ...
    py> g = wraps(f)(lambda: False)
    py> g()
    False
    py> g.__wrapped__()
    True

Likewise `functools.partial` objects have a `func` attribute that gives 
the original function:

    py> h = partial(lambda a, b: a + b)
    py> h = partial(lambda a, b: a + b, 1000)
    py> h(1)
    1001
    py> h.func(1, 2)
    3

Functions which have been decorated with lru_cache are given two 
function attributes, `cache_clear` and `cache_info`.

I believe that there is also an example in mock, but I don't remember 
the details.

I wanted to use this attributes on the median() function in the 
statistics module to spell the less-important variations:

    median()  # standard version as taught in schools

with the specialist versions as attributes:

    median.lower()
    median.upper()

but I was talked out of it in favour of three separate functions:

    median, median_lower, median_upper

I still regret giving in on this point. IMO the lower and upper medians 
are useful but not important enough to be top-level functions.


"Namespaces are one honking great idea -- let's do more of those!"

Functions are namespaces! They have internal `__dicts__` and can hold 
arbitrary attributes. Why are we so reluctant to follow the Zen and use 
those namespaces?

 
> Alternate constructors are generally classmethods.

The fact that chain.from_iterable is, in a sense, an alternative 
constructor is an implementation detail. `chain` happens to be a class 
that returns an instance of `chain`, but it could have simply returned a 
generic generator, or some other kind of instance.

> And it's the documentation that I'm concerned about: I don't think 
> itertools.chain.from_iterable() is very discoverable. Plenty of people 
> don't know it exists. That's my concern with this approach.

It isn't hard to add a "See also..." line to the chain docstring 
pointing to the existence of chain.from_iterable, and we should do that.

Also, help() should be enhanced to give better support for function 
attributes.

Your point about discoverability is taken, but it is no less 
discoverable than other namespaces. If I know a package:

    import package
    package.function(arg)

that knowledge doesn't give me any insight into any subpackages that I 
haven't imported and may not even know about:

    # How do I learn to do this?
    from package.subpackage import anotherfunction



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

Reply via email to