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@python.org wrote:
Send Python-ideas mailing list submissions to
python-ideas@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@python.org
You can reach the person managing the list at
python-ideas-owner@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@gmail.com>
To: Chris Angelico <rosuav@gmail.com>
Cc: Python-Ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
iterables for augmented assignment]
Message-ID:
<CAB_e7iyjcFLCCmnbviUDKZY6mXdv0Hs7-_4kUQEpZe8mVTzvbg@mail.gmail.com>
Content-Type: text/plain; charset="UTF-8"
On Thu, Sep 6, 2018 at 2:23 PM Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Sep 7, 2018 at 4:11 AM, Franklin? Lee
<leewangzhong+python@gmail.com> wrote:
On Tue, Aug 28, 2018 at 6:37 PM Greg Ewing <greg.ewing@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@gmail.com>
To: Python-Ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
iterables for augmented assignment]
Message-ID:
<CAPTjJmrauU+GD+Utcm=zUGFqWX5QXOhWLg5PL94s5OH_O8jLrQ@mail.gmail.com>
Content-Type: text/plain; charset="UTF-8"
On Fri, Sep 7, 2018 at 4:38 AM, Franklin? Lee
<leewangzhong+python@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@gmail.com>
To: Anders Hovm?ller <boxed@killingar.net>
Cc: python-ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] Keyword only argument on function call
Message-ID:
<CALD=Yf8Ddn4MQnbLw+ouoac7YQedc_EsK8o5PyKuwetMuNMAbg@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@gmail.com>
To: Chris Angelico <rosuav@gmail.com>
Cc: Python-Ideas <python-ideas@python.org>
Subject: Re: [Python-ideas] On evaluating features [was: Unpacking
iterables for augmented assignment]
Message-ID:
<CAB_e7iyiM2ByZKxToNumtVRMTZr0S0K8-zyBykUbKYvv7AeQKQ@mail.gmail.com>
Content-Type: text/plain; charset="UTF-8"
n Thu, Sep 6, 2018 at 2:47 PM Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Sep 7, 2018 at 4:38 AM, Franklin? Lee
<leewangzhong+python@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@python.org
https://mail.python.org/mailman/listinfo/python-ideas
------------------------------
End of Python-ideas Digest, Vol 142, Issue 22
*********************************************