Jonathan Fine wrote:
Jeff Shannon wrote:
Jonathan Fine wrote:
Giudo has suggested adding optional static typing to Python.
(I hope suggested is the correct word.)
http://www.artima.com/weblogs/viewpost.jsp?thread=85551
An example of the syntax he proposes is:
> def f(this:that=other):
> print this
<snip>
I'm going to suggest a different use for a similar syntax.
In XML the syntax
> <element this:that='other'>
is used for name spaces.
Name spaces allow independent attributes to be applied to an
element. For example, 'fo' attributes for fonts and layout.
XSLT is of course a big user of namespaces in XML.
Namespaces seems to be a key idea in allow independent
applications to apply attributes to the same element.
[...]
Here's an example of how it might work. With f as above:
> f(this:that='value')
{'that': 'value'}
I fail to see how this is a significant advantage over simply using
**kwargs. It allows you to have multiple dictionaries instead of just
one, that's all. And as you point out, it's trivial to construct your
own nested dicts.
This argument could be applied to **kwargs (and to *args). In other
words, **kwargs can be avoided using a trivial construction.
The use of *args and **kwargs allows functions to take a variable
number of arguments. The addition of ***nsargs does not add
significantly. Note that *args and **kwargs should always be used
together, because to do otherwise would require the function caller to
know details of the function's implementation (i.e. which arguments
are expected to be positional and which must be keywords). Since we
*want* the caller to not need to know this, then ***nsargs would
always need to be used together with *args and **kwargs. (A function
defined 'def f(***nsargs): ...' could not be called with 'f(1)'. This
means that all you're gaining is an extra bag to put variable numbers
of arguments in. The value here is that it maintains a parallel with
*args and **kwargs when one allows 'namespaced' arguments -- if one
allows that, then ***nsargs is required for consistency's sake, but it
does not simplify anything by itself.
So really, we need to look at what gains we'd get from having
'namespaced' arguments. What's the real advantage here?
When using 'namespace' arguments, instead of standard keyword
arguments, the function body would be given a dictionary instead of a
set of local variables, right? 'def f1(arg1, arg2, arg3, arg4)'
creates four names in locals(), where 'def f2(ns1:arg1, ns1:arg2,
ns1:arg3, ns1:arg4) creates a single dict named ns1 in locals(), which
contains four items (keyed on 'arg1', 'arg2', etc.), and 'def
f3(ns1:arg1, ns1:arg2, ns2:arg3, ns2:arg4)' creates two dicts (ns1 and
ns2) with two entries each.
Okay, now, let's take a look at how these functions will be used.
f1(1, 2, 3, 4)
f1(arg1=1, arg2=2, arg3=3, arg4=4)
Note that f1 doesn't care which of these methods of calling is
employed -- both result in the same situation inside of f1().
So what's the intended way of calling f2()? I'd presume that it
shouldn't care whether keywords or namespaces are specified, so that
the following should all be equivalent:
f2(1, 2, 3, 4)
f2(1, 2, arg3=3, arg4=4)
f2(1, 2, arg3=3, ns1:arg4=4)
Note that this doesn't *add* any utility. The function caller hasn't
gained anything. Since arg4 is unambiguous regardless of whether it's
referred to as arg4 or ns1:arg4, the only time that the caller has any
reason to specify the namespace is if argnames within different
namespaces clash -- that is, if we allow something like 'def
f4(ns1:arg1, ns1:arg2, ns2:arg1, ns2:arg2)'.
Now, though, we've lost the ability to specify *only* the argname and
not the namespace as well -- that is, you *cannot* call f4 with
keywords but not namespaces. From the caller's vantage point, this
means that they need to know the full namespace spec of the function,
which makes it no different than simply using longer (but unique)
keyword names.
So, we can see that allowing namespaces and ***nsargs doesn't add any
utility from the caller's perspective. How much does the callee gain
from it?
Well, the following functions would be equivalent:
def g1(arg1, arg2, arg3, arg4):
ns1 = {'arg1':arg1, 'arg2':arg2, 'arg3':arg3, 'arg4':arg4}
return ns1
def g2(ns1:arg1, ns1:arg2, ns1:arg3, ns1:arg4):
return ns1
You might say "Wow, look at all that repetetive typing I'm saving!"
But that *only* applies if you need to stuff all of your arguments
into dictionaries. I suspect that this is a rather small subset of
functions. In most cases, it will be more convenient to use your
arguments as local variables than as dictionary entries.
def gcd1(a, b):
while a:
a, b = b%a, a
return b
def gcd2(ns1:a, ns1:b):
while ns1['a']:
ns1['a'], ns1['b'] = ns1['b']%ns1['a'], ns1['a']
return ns1['b']
Speaking of repetetive typing.... :P
Besides, another function equivalent to the above two would be:
def g3(arg1, arg2, arg3, arg4):
ns1 = locals()
return ns1
....which is quite a bit less repetetive typing than the 'namespace'
version.
So, you're looking at making the function-calling protocol
significantly more complex, both for caller and callee, for the rather
marginal gain of being able to get arguments prepackaged in a
dictionary or two, when there already exist easy ways of packaging
function arguments into a dict. Given the deliberate bias against
adding lots of new features to Python, one needs a *much* better
cost/benefit ratio for a feature to be considered worthwhile.
Besides, Python already uses the concept of namespaces by mapping them
to object attributes. [...]
Here, I don't understand. Could you give an example of two obvious ways
of doing the same thing, should my suggestion be adopted?
My main point here is that 'namespace' is a term/concept that is
already in use in Python, in different circumstances and using a
completely different mechanism. Functions already *have* namespaces,
whose contents can be inspected with locals() and modules have
namespaces that can be accessed through globals().
I'd note also that the usage you're drawing from, in XML/XSLT, isn't
really comparable to function parameters. It's a much closer parallel
to object attributes. Python *does* have this concept, but it's
spelled differently, using a '.' instead of a ':'. In other words,
the XML fragment you give,
<element this:that='other'>
.... would be more appropriate to render in Python as
e = Element()
e.this.that = 'other'
It's quite reasonable to suppose that some object of type Element may
have a set of font attributes and a set of image attributes, and that
some of these may have the same name. Python would use font objects
and image objects instead of 'namespaces' --
e.font.size = '14pt'
e.image.size = (640, 480)
So while these namespaces are probably a great thing for XML, XSLT,
they're not very useful in Python. Which, given the rather different
goals and design philosophies behind the languages, shouldn't really
be much of a surprise.
Jeff Shannon
Technician/Programmer
Credit International