Verbose and flexible args and kwargs syntax
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Tue Dec 13 06:13:16 EST 2011
On Tue, 13 Dec 2011 01:15:46 -0800, Eelco wrote:
> On Dec 13, 3:43 am, Steven D'Aprano <steve
> +comp.lang.pyt... at pearwood.info> wrote:
>> On Mon, 12 Dec 2011 04:21:15 -0800, Eelco wrote:
>> >> No more, or less, explicit than the difference between "==" and
>> >> "is".
>>
>> > == may be taken to mean identity comparison; 'equals' can only mean
>> > one thing.
[...]
> We are not talking mathemathics, we are talking programming languages.
What *I* am talking about is your assertion that there is only one
possible meaning for "equals" in the context of a programing language.
This is *simply not correct*.
You don't have to believe me, just look at the facts. It's hard to find
languages that use the word "equals" (or very close to it) rather than
equals signs, but here are four languages which do:
(1) OpenXION:
Equals in OpenXION is weakly typed, like Perl:
>1 + 1.0 equals "2"
true
(2) C# uses method notation: a.Equals(b) can be overridden, but for many
types it defaults to value equality, that is, the equivalent to Python's
a == b.
(3) Ruby uses a.equal?(b) for "reference equality", that is, the
equivalent of Python's "is" operator:
irb(main):001:0> a = "abc"
=> "abc"
irb(main):002:0> b = "abc"
=> "abc"
irb(main):003:0> a.equal?(b)
=> false
irb(main):004:0> a == b
=> true
(4) Mathematica's Equal[x, y] can test values and expressions for
equality. It may return true, false, or unevaluated (i.e. itself).
Four languages that use Equals (or close to it) with four different
behaviours.
> Identity versus value equality is a well established concept within its
> jargon. Within this context, 'equals' and 'is' have clearly defined
> meanings.
Incorrect. Most programming languages do not even have a concept of
identity: identity is only(?) relevant to reference languages, like
Python, where variables are references to objects.
Even for languages that have a concept of identity, most don't don't call
it "is". Objective-C calls it "==", PHP calls it "===", C# calls it
object.ReferenceEquals. (Python, Algol 68, and VB .NET are three which do
call it "is".)
For stack-based languages like Forth, it doesn't even make sense to talk
about identity, since values aren't variables: they're just values on a
stack, not values in a fixed location, or bound to a known name.
Again, all this goes to demonstrate that the language designer is free to
choose any behaviour they like, and give it any name they like.
[...]
> So 'frequency of use' is no valid interpretation of 'obscurity'? Im not
> a native speaker, but im pretty sure it is.
No. Things which are obscure are used in language infrequently, because
if they were common they would not be obscure. But things which are used
infrequently are not necessarily obscure.
An example in common language: "Napoleon Bonaparte" does not come up in
conversation very frequently, but he is not an obscure historical figure.
An example from programming: very few people need to use the
trigonometric functions sin, cos, tan in their code. But they are not
obscure functions: most people remember them from school. People who have
forgotten almost everything about mathematics except basic arithmetic
probably remember sin, cos and tan. But they never use them.
>> >> And you can blame C for the use of % instead of mod or modulo.
>>
>> > I didnt know one of Python's design goals was backwards compatibility
>> > with C.
>>
>> Don't be silly. You know full well Python is not backwards compatible
>> with C, even if they do share some syntactical features.
>
> Of course I was being silly; I know this use is following a historical
> precedent; but id rather see it rectified in the previous version of
> python rather than the next. My sillyness was prompted by the percieved
> pointlessness of your remark. Of course python is not trying to be
> backwards compatible with C; so why bring it up then?
Because you asked why Python uses the % operator for remainder.
[...]
> They are bad ideas because they truely do not lead to the execution of
> different code, but are merely a reordering, mixing statements in with a
> function declaration. I am proposing no such thing; again, the type(arg)
> notation I have dropped, and never was meant to have anything to do with
> function calling; it is a way of supplying an optional type constraint,
> so in analogy with function annotations, I changed that to arg::type.
> Again, this has nothing to do with calling functions on arguments.
You have not thought about this carefully enough. Consider what happens
when this code gets called:
def f(*args): pass
f(a, b, c)
The Python virtual machine (interpreter, if you prefer) must take three
arguments a, b, c and create a tuple from them. This must happen at
runtime, because the value of the objects is not known at compile time.
So at some point between f(a, b, c) being called and the body of f being
entered, a tuple must be created, and the values of a, b, c must be
collated into a single tuple.
Now extend this reasoning to your proposal:
def f(args:FOO): pass
At runtime, the supplied arguments must be collated into a FOO, whatever
FOO happens to be. Hence, the function that creates FOO objects must be
called before the body of f can be entered. This doesn't happen for free.
Whether you do it manually, or have the Python interpreter do it, it
still needs to be done.
> First off, type constraints must have some use; all those languages cant
> be wrong.
But you're not talking about type constraints. You're not instructing the
function to reject arguments which have the wrong type, you are
instructing it to collate multiple arguments into a list (instead of a
tuple like Python currently does). def f(*args) *constructs* a tuple, it
doesn't perform a type-check.
--
Steven
More information about the Python-list
mailing list