Actually, there is a good motive IMO for a partial function to have
__name__ and __qualname__: the code one is passing a partial function
might expect these attributes to be presented in the callable it get.

It is just a matter of unifying the interface for callables that are often
used as arguments in calls, and as such, even
if __name__ and __qualname__ are fixed and immutable strings, this would be
an improvement.
(say, a partial callable __name__ could be fixed to "<partial>" just as a
lambda's __name__ is  "<lambda>")

On Tue, Aug 30, 2022 at 4:29 PM Wes Turner <wes.tur...@gmail.com> wrote:

> Would a property or a copy be faster for existing and possible use cases?
> In practice, how frequently will __qual/name__ be called on partials?
>
> - Copying __qual/name__ would definitely be a performance regression
>
> - There are probably as many use cases for partials as other methods of
> functional composition,
> - __qual/name__ support is not yet extant
>
> - it's faster to run e.g. a grid search *without* partials, due to
> function call overhead, due to scope allocation on the stack in stackful
> pythons [1]
>
> [1] Hyper Parameter Search > Scaling hyperparameter searches
>
> https://ml.dask.org/hyper-parameter-search.html#scaling-hyperparameter-searches
>
> [2] Pipeline caching in TPOT
> http://epistasislab.github.io/tpot/using/#pipeline-caching-in-tpot
> #parallel-training-with-dask ; TPOT generates  actual python source code
> instead of an ensemble of partials
>
>
>
>
>
> On Tue, Aug 30, 2022, 12:07 PM Charles Machalow <csm10...@gmail.com>
> wrote:
>
>> We may be able to do __name__/__qualname__ as a property to make it
>> evaluate when called as opposed to computed once on creation. That way we
>> just work with .func upon call so no need for extra references, etc.
>>
>> As for documentation generation tools, it may be different at first,
>> though I believe the existing ispartial checks would catch partials still.
>> If they want to (in a new version) swap to using __name__/__qualname__ that
>> should be fine, but this likely wouldn't inherently break existing tools.
>>
>> - Charlie Scott Machalow
>>
>>
>> On Mon, Aug 29, 2022 at 11:08 PM Wes Turner <wes.tur...@gmail.com> wrote:
>>
>>> Is there a non-performance regressive way to proxy attr access to
>>> func.__name__ of the partial function (or method; Callable)?
>>>
>>> Would this affect documentation generation tools like e.g.
>>> sphinx-spidoc, which IIRC use __name__ and probably now __qualname__ for
>>> generating argspecs in RST for HTML and LaTeX?
>>>
>>>
>>> - https://docs.python.org/3/library/inspect.html
>>>   - functions and methods have __name__ and __qualname__
>>>   - see: sphinx.utils.inspect
>>>
>>> - https://docs.python.org/3/library/functools.html#functools.partial
>>> -
>>> https://docs.python.org/3/library/functools.html#functools.partialmethod
>>> - https://docs.python.org/3/library/functools.html#partial-objects
>>>
>>> > partial Objects¶
>>> > partial objects are callable objects created by partial(). They have
>>> three read-only attributes:
>>> >
>>> > partial.func
>>> > A callable object or function. Calls to the partial object will be
>>> forwarded to func with new arguments and keywords.
>>> >
>>> > partial.args
>>> > The leftmost positional arguments that will be prepended to the
>>> positional arguments provided to a partial object call.
>>> >
>>> > partial.keywords
>>> > The keyword arguments that will be supplied when the partial object is
>>> called.
>>>
>>> > partial objects are like function objects in that they are callable,
>>> weak referencable, and can have attributes. There are some important
>>> differences. For instance, the __name__ and __doc__ attributes are not
>>> created automatically. Also, partial objects defined in classes behave like
>>> static methods and do not transform into bound methods during instance
>>> attribute look-up.
>>>
>>>
>>> - https://www.sphinx-doc.org/en/master/man/sphinx-apidoc.html
>>> - https://www.sphinx-doc.org/en/master/_modules/sphinx/ext/autodoc.html
>>> : 18 references to __qualname__,
>>>
>>>
>>> https://github.com/sphinx-doc/sphinx/blob/5.x/sphinx/util/inspect.py#L49-L66
>>> :
>>>
>>> ```python
>>> def unwrap_all(obj: Any, *, stop: Optional[Callable] = None) -> Any:
>>>     """
>>>     Get an original object from wrapped object (unwrapping partials,
>>> wrapped
>>>     functions, and other decorators).
>>>     """
>>>     while True:
>>>         if stop and stop(obj):
>>>             return obj
>>>         elif ispartial(obj):
>>>             obj = obj.func
>>>         elif inspect.isroutine(obj) and hasattr(obj, '__wrapped__'):
>>>             obj = obj.__wrapped__  # type: ignore
>>>         elif isclassmethod(obj):
>>>             obj = obj.__func__
>>>         elif isstaticmethod(obj):
>>>             obj = obj.__func__
>>>         else:
>>>             return obj
>>> ```
>>>
>>> From
>>> https://github.com/sphinx-doc/sphinx/blob/5.x/sphinx/util/inspect.py#L173-L186
>>> :
>>>
>>> ```python
>>> def unpartial(obj: Any) -> Any:
>>>     """Get an original object from partial object.
>>>     This returns given object itself if not partial.
>>>     """
>>>     while ispartial(obj):
>>>         obj = obj.func
>>>
>>>     return obj
>>>
>>>
>>> def ispartial(obj: Any) -> bool:
>>>     """Check if the object is partial."""
>>>     return isinstance(obj, (partial, partialmethod))
>>> ```
>>>
>>> -
>>> https://github.com/sphinx-doc/sphinx/issues/4826#issuecomment-808699254
>>>
>>>
>>> https://docs.python.org/3/library/stdtypes.html#definition.__name__
>>>
>>>
>>> https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy
>>> > Callable types > User defined functions does list both __name__ and
>>> __qualname__
>>>
>>> Is there a non-performance regressive way to proxy attr access to
>>> __name__ of the partially curried (?) function?
>>>
>>> From "PEP 3155 – Qualified name for classes and functions"
>>> https://peps.python.org/pep-3155/#limitations :
>>>
>>> > ### Limitations
>>> > With nested functions (and classes defined inside functions), the
>>> dotted path will not be walkable programmatically as a function’s namespace
>>> is not available from the outside. It will still be more helpful to the
>>> human reader than the bare __name__.
>>> >
>>> > As the __name__ attribute, the __qualname__ attribute is computed
>>> statically and it will not automatically follow rebinding.
>>>
>>> From
>>> https://wrapt.readthedocs.io/en/latest/wrappers.html#proxy-object-attributes
>>> :
>>>
>>> > Proxy Object Attributes
>>> > When an attempt is made to access an attribute from the proxy, the
>>> same named attribute would in normal circumstances be accessed from the
>>> wrapped object. When updating an attributes value, or deleting the
>>> attribute, that change will also be reflected in the wrapped object.
>>>
>>> From https://docs.python.org/3/library/weakref.html#weakref.proxy :
>>>
>>> > weakref.proxy(object[, callback])¶
>>> > Return a proxy to object which uses a weak reference. This supports
>>> use of the proxy in most contexts instead of requiring the explicit
>>> dereferencing used with weak reference objects. The returned object will
>>> have a type of either ProxyType or CallableProxyType, depending on whether
>>> object is callable. Proxy objects are not hashable regardless of the
>>> referent; this avoids a number of problems related to their fundamentally
>>> mutable nature, and prevent their use as dictionary keys. callback is the
>>> same as the parameter of the same name to the ref() function.
>>>
>>> On Tue, Aug 30, 2022, 1:14 AM Charles Machalow <csm10...@gmail.com>
>>> wrote:
>>>
>>>> 1: There are cases where one may need the __name__/__qualname__ of a
>>>> given callable. If someone uses partial to create a new callable, there is
>>>> no __name__/__qualname__ given. In my particular case, I'm logging what
>>>> callback function is passed to a different function... if someone uses
>>>> partial, there is no __name__/__qualname__ which leads to a current
>>>> traceback... of course i can work around it but still was an odd case to 
>>>> me.
>>>>
>>>> Per the docs on functools.partial:
>>>> "Return a new partial object which when called will behave like func
>>>> called with the positional arguments args and keyword arguments keywords"
>>>> ... which made me initially think that in order to behave like the
>>>> passed in function: it should have __name__ and __qualname__... like the
>>>> func did.
>>>>
>>>> 2: I would say have both __qualname__ and __name__. Both could be based
>>>> off of __name__/__qualname__ of the passed in func.
>>>>
>>>> 3: This would be more difficult since you would have to disassemble the
>>>> lambda to figure out the called method (or methods)... We can table the
>>>> lambda discussion for the purpose of this idea. I recall that typically it
>>>> is preferred to use partial over lambdas, so this could be an additional
>>>> functionality/benefit of using partial over lambda.
>>>>
>>>> Notes:
>>>> ... __name__ being something like partial(foo, "x") would be fine with
>>>> me... I just feel as though something should be there.
>>>>
>>>> - Charlie Scott Machalow
>>>>
>>>>
>>>> On Mon, Aug 29, 2022 at 9:56 PM Paul Bryan <pbr...@anode.ca> wrote:
>>>>
>>>>> +0
>>>>>
>>>>> Questions:
>>>>>
>>>>> 1. What's the use case for partial having __name__?
>>>>> 2. Does this imply it should have __qualname__ as well?
>>>>> 3. What name would be given to (an inherently anonymous) lambda?
>>>>>
>>>>> Notes:
>>>>>
>>>>> 1. I would prefer __name__ to be more qualifying like its repr (e.g.
>>>>> partial(foo, "x") → "<partial foo>")
>>>>>
>>>>>
>>>>> On Mon, 2022-08-29 at 21:31 -0700, Charles Machalow wrote:
>>>>>
>>>>> Hey folks,
>>>>>
>>>>> I propose adding __name__ to functools.partial.
>>>>>
>>>>> >>> get_name = functools.partial(input, "name: ")
>>>>> >>> get_name()
>>>>> name: hi
>>>>> 'hi'
>>>>> >>> get_name.__name__
>>>>> Traceback (most recent call last):
>>>>>   File "<stdin>", line 1, in <module>
>>>>> AttributeError: 'functools.partial' object has no attribute '__name__'
>>>>> >>> get_name.func
>>>>> <built-in function input>
>>>>> >>> get_name.func.__name__
>>>>> 'input'
>>>>>
>>>>> We could set __name__ based off of partial.func.__name__ or we could
>>>>> try to set it to something like 'partial calling func.__name__'
>>>>>
>>>>> If the callable doesn't have a name, we could fall back to a None
>>>>> __name__ or set it to something generic.
>>>>>
>>>>> Even lambdas have __name__ set:
>>>>>
>>>>> >>> l = lambda: input('name: ')
>>>>> >>> l.__name__
>>>>> '<lambda>'
>>>>>
>>>>> This proposal makes __name__ on partial objects more useful than the
>>>>> current behavior of __name__ on lambda objects as well. We could port over
>>>>> similar functionality to lambda if we'd like.
>>>>>
>>>>> - Charlie Scott Machalow
>>>>> _______________________________________________
>>>>> 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/WK3FO357ORPVAD3XRUBRH6IHIYSPS3G2/
>>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>>>
>>>>>
>>>>> _______________________________________________
>>>> 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/ONAEBCIEJ4DJNWUNWE2ESJ6SBB4O7O6W/
>>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>>
>>> _______________________________________________
> 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/YGARINTBW6W32V7YELNEX4VPD7YMPFMR/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
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/HJEMHZWHSTPOTWJVNERNLXTBDXOWGPC2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to