[Python-ideas] Python-ideas Digest, Vol 142, Issue 22

James Lu jamtlu at gmail.com
Fri Sep 7 15:09:01 EDT 2018


What if * and ** forwarded all unnamed arguments to a function? Example: 

import traceback
def print_http_response(request, color=True):
    ...
def print_invalid_api_response(error, *, show_traceback=False, **):
    print_http_response(*, **)
    if show_traceback:
        traceback.print_last()
    else:
        print(error)

This would essentially allow * and ** to be used to call a function without having to give a name: *args or **kwargs.

However in this scenario, the client function is more likely to be “inheriting from” the behavior of the inner function, in a way where all or most of the arguments of the inner function are valid on the client function. Example: requests.get creates a Request object and immediately sends the response while blocking for it.

> On Sep 6, 2018, at 3:27 PM, python-ideas-request at python.org wrote:
> 
> Send Python-ideas mailing list submissions to
>    python-ideas at python.org
> 
> To subscribe or unsubscribe via the World Wide Web, visit
>    https://mail.python.org/mailman/listinfo/python-ideas
> or, via email, send a message with subject or body 'help' to
>    python-ideas-request at python.org
> 
> You can reach the person managing the list at
>    python-ideas-owner at python.org
> 
> When replying, please edit your Subject line so it is more specific
> than "Re: Contents of Python-ideas digest..."
> 
> 
> Today's Topics:
> 
>   1. Re: On evaluating features [was: Unpacking iterables for
>      augmented assignment] (Franklin? Lee)
>   2. Re: On evaluating features [was: Unpacking iterables for
>      augmented assignment] (Chris Angelico)
>   3. Re: Keyword only argument on function call (Jonathan Fine)
>   4. Re: On evaluating features [was: Unpacking iterables for
>      augmented assignment] (Franklin? Lee)
> 
> 
> ----------------------------------------------------------------------
> 
> Message: 1
> Date: Thu, 6 Sep 2018 14:38:26 -0400
> From: "Franklin? Lee" <leewangzhong+python at gmail.com>
> To: Chris Angelico <rosuav at gmail.com>
> Cc: Python-Ideas <python-ideas at python.org>
> Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
>    iterables for augmented assignment]
> Message-ID:
>    <CAB_e7iyjcFLCCmnbviUDKZY6mXdv0Hs7-_4kUQEpZe8mVTzvbg at mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
> 
>> On Thu, Sep 6, 2018 at 2:23 PM Chris Angelico <rosuav at gmail.com> wrote:
>> 
>> On Fri, Sep 7, 2018 at 4:11 AM, Franklin? Lee
>> <leewangzhong+python at gmail.com> wrote:
>>>> On Tue, Aug 28, 2018 at 6:37 PM Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
>>>> 
>>>> Guido van Rossum wrote:
>>>>> we might propose (as the OP did) that this:
>>>>> 
>>>>>  a, b, c += x, y, z
>>>>> 
>>>>> could be made equivalent to this:
>>>>> 
>>>>>  a += x
>>>>>  b += y
>>>>>  c += z
>>>> 
>>>> But not without violating the principle that
>>>> 
>>>>    lhs += rhs
>>>> 
>>>> is equivalent to
>>>> 
>>>>    lhs = lhs.__iadd__(lhs)
>>> 
>>> (Corrected: lhs = lhs.__iadd__(rhs))
>>> 
>>> Since lhs here is neither a list nor a tuple, how is it violated? Or
>>> rather, how is it any more of a special case than in this syntax:
>>> 
>>>    # Neither name-binding or setitem/setattr.
>>>    [a,b,c] = items
>>> 
>>> If lhs is a Numpy array, then:
>>>    a_b_c += x, y, z
>>> is equivalent to:
>>>    a_b_c = a_b_c.__iadd__((x,y,z))
>>> 
>>> We can translate the original example:
>>>    a, b, c += x, y, z
>>> to:
>>>    a, b, c = target_list(a,b,c).__iadd__((x,y,z))
>>> where `target_list` is a virtual (not as in "virtual function") type
>>> for target list constructs.
>> 
>> What is the virtual type here, and what does its __iadd__ method do? I
>> don't understand you here. Can you go into detail? Suppose I'm the
>> author of the class that all six of these objects are instances of;
>> can I customize the effect of __iadd__ here in some way, and if so,
>> how?
> 
> I shouldn't have used jargon I had to look up myself.
> 
> The following are equivalent and compile down to the same code:
>    a, b, c = lst
>    [a, b, c] = lst
> 
> The left hand side is not an actual list (even though it looks like
> one). The brackets are optional. The docs call the left hand side a
> target list: https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
> 
> "Target list" is not a real type. You can't construct such an object,
> or hold one in memory. You can't make a class that emulates it
> (without interpreter-specific hacks), because it is a collection of
> its names, not a collection of values.
> 
> target_list.__iadd__ also does not exist, because target_list does not
> exist. However, target_list can be thought of as a virtual type, a
> type that the compiler compiles away. We can then consider
> target_list.__iadd__ as a virtual operator, which the compiler will
> understand but hide from the runtime.
> 
> I was making the point that, because the __iadd__ in the example does
> not refer to list.__iadd__, but rather a virtual target_list.__iadd__,
> there is not yet a violation of the rule.
> 
> 
> ------------------------------
> 
> Message: 2
> Date: Fri, 7 Sep 2018 04:46:36 +1000
> From: Chris Angelico <rosuav at gmail.com>
> To: Python-Ideas <python-ideas at python.org>
> Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
>    iterables for augmented assignment]
> Message-ID:
>    <CAPTjJmrauU+GD+Utcm=zUGFqWX5QXOhWLg5PL94s5OH_O8jLrQ at mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
> 
> On Fri, Sep 7, 2018 at 4:38 AM, Franklin? Lee
> <leewangzhong+python at gmail.com> wrote:
>> The following are equivalent and compile down to the same code:
>>    a, b, c = lst
>>    [a, b, c] = lst
>> 
>> The left hand side is not an actual list (even though it looks like
>> one). The brackets are optional. The docs call the left hand side a
>> target list: https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
>> 
>> "Target list" is not a real type. You can't construct such an object,
>> or hold one in memory. You can't make a class that emulates it
>> (without interpreter-specific hacks), because it is a collection of
>> its names, not a collection of values.
> 
> A target list is a syntactic element, like a name, or an operator, or
> a "yield" statement. You can't construct one, because it isn't an
> object type. It's not a "virtual type". It's a completely different
> sort of thing.
> 
>> target_list.__iadd__ also does not exist, because target_list does not
>> exist. However, target_list can be thought of as a virtual type, a
>> type that the compiler compiles away. We can then consider
>> target_list.__iadd__ as a virtual operator, which the compiler will
>> understand but hide from the runtime.
>> 
>> I was making the point that, because the __iadd__ in the example does
>> not refer to list.__iadd__, but rather a virtual target_list.__iadd__,
>> there is not yet a violation of the rule.
> 
> What you're suggesting is on par with trying to say that:
> 
> for += 5
> 
> should be implemented as:
> 
> current_loop.__iadd__(5)
> 
> where "current_loop" doesn't really exist, but it's a virtual type
> that represents a 'for' loop. That doesn't make sense, because there
> is no object in Python to represent the loop. There is no class/type
> that represents all loops, on which a method like this could be added.
> The word 'for' is part of the grammar, not the object model. And
> "target list" is the same. There's no way to attach an __iadd__ method
> to something that doesn't exist.
> 
> So for your proposal to work, you would need to break that rule, and
> give a *different* meaning to this.
> 
> ChrisA
> 
> 
> ------------------------------
> 
> Message: 3
> Date: Thu, 6 Sep 2018 20:10:49 +0100
> From: Jonathan Fine <jfine2358 at gmail.com>
> To: Anders Hovm?ller <boxed at killingar.net>
> Cc: python-ideas <python-ideas at python.org>
> Subject: Re: [Python-ideas] Keyword only argument on function call
> Message-ID:
>    <CALD=Yf8Ddn4MQnbLw+ouoac7YQedc_EsK8o5PyKuwetMuNMAbg at mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
> 
> Summary: I addressed the DEFINING problem. My mistake. Some rough
> ideas for the CALLING problem.
> 
> Anders has kindly pointed out to me, off-list, that I solved the wrong
> problem. His problem is CALLING the function fn, not DEFINING fn.
> Thank you very much for this, Anders.
> 
> For calling, we can use https://docs.python.org/3/library/functions.html#locals
> 
>>>> lcls = locals()
> 
>>>> a = 'apple'
>>>> b = 'banana'
>>>> c = 'cherry'
> 
>>>> dict((k, lcls[k]) for k in ('a', 'b', 'c'))
>      {'b': 'banana', 'c': 'cherry', 'a': 'apple'}
> 
> So in his example
> 
>       foo(a=a, b=b, c=c, d=3, e=e)
> 
> one could instead write
> 
>      foo(d=3, **helper(locals(), ('a', 'b', 'c', 'e')))
> 
> or perhaps better
> 
>    helper(locals(), 'a', 'b', 'c', 'e')(foo, d=3)
> 
> where the helper() picks out items from the locals(). And in the
> second form, does the right thing with them.
> 
> Finally, one might be able to use
> 
>>>> def fn(*, a, b, c, d, e): f, g, h = 3, 4, 5
>>>> fn.__code__.co_kwonlyargcount
>      5
>>>> fn.__code__.co_varnames
>      ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h')
>>>> fn.__code__.co_argcount
>     0
> 
> to identify the names of all keyword arguments of the function foo(),
> and they provide the values in locals() as the defaults. Of course,
> this is somewhat magical, and requires strict conformance to
> conventions. So might not be a good idea.
> 
> The syntax could then be
> 
>    localmagic(foo, locals())(d=3)
> 
> which, for magicians, might be easier. But rightly in my opinion,
> Python is reluctant to use magic.
> 
> On the other hand, for a strictly controlled Domain Specific Language,
> it might, just might, be useful. And this list is for "speculative
> language ideas" (see
> https://mail.python.org/mailman/listinfo/python-ideas).
> 
> -- 
> Jonathan
> 
> 
> ------------------------------
> 
> Message: 4
> Date: Thu, 6 Sep 2018 15:26:47 -0400
> From: "Franklin? Lee" <leewangzhong+python at gmail.com>
> To: Chris Angelico <rosuav at gmail.com>
> Cc: Python-Ideas <python-ideas at python.org>
> Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
>    iterables for augmented assignment]
> Message-ID:
>    <CAB_e7iyiM2ByZKxToNumtVRMTZr0S0K8-zyBykUbKYvv7AeQKQ at mail.gmail.com>
> Content-Type: text/plain; charset="UTF-8"
> 
> n Thu, Sep 6, 2018 at 2:47 PM Chris Angelico <rosuav at gmail.com> wrote:
>> 
>> On Fri, Sep 7, 2018 at 4:38 AM, Franklin? Lee
>> <leewangzhong+python at gmail.com> wrote:
>>> The following are equivalent and compile down to the same code:
>>>    a, b, c = lst
>>>    [a, b, c] = lst
>>> 
>>> The left hand side is not an actual list (even though it looks like
>>> one). The brackets are optional. The docs call the left hand side a
>>> target list: https://docs.python.org/3/reference/simple_stmts.html#assignment-statements
>>> 
>>> "Target list" is not a real type. You can't construct such an object,
>>> or hold one in memory. You can't make a class that emulates it
>>> (without interpreter-specific hacks), because it is a collection of
>>> its names, not a collection of values.
>> 
>> A target list is a syntactic element, like a name, or an operator, or
>> a "yield" statement. You can't construct one, because it isn't an
>> object type. It's not a "virtual type". It's a completely different
>> sort of thing.
> 
> I didn't think I gave the impression that I was complaining about not
> being able to construct it. I gave an explanation for how it isn't a
> real type, because you asked how you could modify the behavior, and
> because I wanted to give an explanation for more than just you.
> 
> There are constructs that correspond to types (such as slices and
> functions). There are those that don't. We call `3:2` (in the right
> context) a slice, even though it's technically a construct which is
> compiled down to a `slice` object. I see no problem there.
> 
> I called it a "virtual type" and explained why I called it that. You
> reject the use of that term, but you don't even acknowledge that I
> gave reasons for it.
> 
>>> target_list.__iadd__ also does not exist, because target_list does not
>>> exist. However, target_list can be thought of as a virtual type, a
>>> type that the compiler compiles away. We can then consider
>>> target_list.__iadd__ as a virtual operator, which the compiler will
>>> understand but hide from the runtime.
>>> 
>>> I was making the point that, because the __iadd__ in the example does
>>> not refer to list.__iadd__, but rather a virtual target_list.__iadd__,
>>> there is not yet a violation of the rule.
>> 
>> What you're suggesting is on par with trying to say that:
>> 
>> for += 5
>> 
>> should be implemented as:
>> 
>> current_loop.__iadd__(5)
>> 
>> where "current_loop" doesn't really exist, but it's a virtual type
>> that represents a 'for' loop.
> 
> I explained how target_list could be thought of as a special imaginary
> type which only exists in the compiler's "mind", and then extended
> that to an imaginary method on that type. Of course your example shows
> absurdity: you didn't try to say how a for-loop is like an object in
> the first place.
> 
>> That doesn't make sense, because there
>> is no object in Python to represent the loop. There is no class/type
>> that represents all loops, on which a method like this could be added.
>> The word 'for' is part of the grammar, not the object model. And
>> "target list" is the same. There's no way to attach an __iadd__ method
>> to something that doesn't exist.
> 
> But I'm not using the word `for`. I am using constructs like `[a,b,c]`
> (where it is not a list). At least use `(for x in y: z) += 5` as your
> example. You're effectively accusing me of trying to make `[` (a
> single token, not a full construct) an object.
> 
> Your argument here is that there is no Python object to represent a
> loop, but that really means there's no _runtime_ object to represent a
> loop. I already said that target lists don't exist in memory (i.e.
> runtime).
> 
> "Target list" does exist, just not as a runtime type. It exists as an
> abstraction not available to the runtime, and we can extend that
> abstraction in ways not available to the runtime. That means that you
> can't attach it during the runtime. It does not mean you can't reason
> with it during compile-time.
> 
>> So for your proposal to work, you would need to break that rule, and
>> give a *different* meaning to this.
> 
> It is not my proposal. I was questioning how there was a rule
> violation about x+=y translating to `x = x.__iadd__(y)`. You're
> talking about a different, made-up rule about how syntactical
> constructs can't correspond to compile-time imaginary objects or
> runtime objects. But there are syntactical constructs that DO
> correspond to runtime types (slice, list, class), there are those
> which don't but can (let's not get into that), there are those which
> can stay compile-time (f-strings, target lists), and there are those
> which probably can't be thought of as types at all (import).
> 
> 
> ------------------------------
> 
> Subject: Digest Footer
> 
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> 
> 
> ------------------------------
> 
> End of Python-ideas Digest, Vol 142, Issue 22
> *********************************************


More information about the Python-ideas mailing list