[DB-SIG] spec: named parameters: clarification needed
Anthony Tuininga
anthony@computronix.com
Mon, 17 Feb 2003 08:16:52 -0700
On Sun, 2003-02-16 at 03:05, M.-A. Lemburg wrote:
> Anthony Tuininga wrote:
> > On Sat, 2003-02-15 at 09:22, M.-A. Lemburg wrote:
> >
> >>Anthony Tuininga wrote:
> >>
> >>>The problem is that the spec is not at all clear. Keyword arguments are
> >>>still arguments -- they are turned into a single dictionary which is the
> >>>"right" way in Python to pass arguments by name.
> >>
> >>I'm not sure I can follow you here. The spec talks about a
> >>single optional parameter which happens to be called parameters
> >>(plural) and then states -as Harald corrected me- that this
> >>parameter may either be a sequence or a mapping. That's as clear
> >>as can be.
> >
> > Ok, then the spec is deficient, in my opinion. Which is better?
> >
> > statement = """
> > select Column1, Column2, Column3
> > from SomeTable
> > where Column1 like :p_Arg1
> > and Column2 between :p_Arg2 and :p_Arg3
> > and Column3 > :p_Arg4"""
> >
> > Current Requirement (according to your reading)
> > args = {
> > "p_Arg1" : "FRED%",
> > "p_Arg2" : 1,
> > "p_Arg3" : 10,
> > "p_Arg4" : 25
> > }
> > cursor.execute(statement, args)
> >
> > My preference (and more Python like, in my opinion)
> > cursor.execute(statement,
> > p_Arg1 = "FRED%",
> > p_Arg2 = 1,
> > p_Arg3 = 10,
> > p_Arg4 = 25)
>
> If you like this better, then I'd suggest to add a new method
> to your implementation which implements this interface. The spec
> is clear about passing only one object in to hold the parameters
> for .execute() and as Stuart already explained fits in nicely
> with .executemany().
Right. And using keyword arguments passes __ONE__ argument to the
underlying function, but in a format that is __MUCH__ easier to read
than any of the formats you suggested below. Syntactic sugar (like the
ability to pass an undefined list of keyword arguments en masse) is not
strictly necessary, but it makes coding much simpler and easier to read.
And you still don't state why you think that consistency between
execute() and executemany() is so important to you. I use execute()
probably 99/100 times since executemany() is there solely for
performance reasons. The programmer new to the DB API will likely never
touch executemany() so having its function signature the same as
execute() is (in my opinion) a foolish consistency.
> Note: the spec is your friend -- you are always free to extend it
> to your taste.
Right. And that makes the spec much less useful. It seems to have been
developed in the Python 1.5 days and now refuses to be changed even
though better syntax has been developed.
> > If you are claiming that the spec requires a parameter and no keywords,
> > then I would very strongly suggest that it be amended. Regardless, I
> > have no intentions whatsoever of complying strictly with the standard as
> > you read it since it would lead to an annoying loss of functionality. I
> > think I can safely say that all others that used named parameters would
> > agree.
>
> I don't see an "annoying loss" of functionality. You could just
> as well use positional binding to the same effect, or you wrap
> up the named args using a helper:
>
> def named(**kws):
> return kws
>
> cursor.execute(statement,
> named(p_Arg1 = "FRED%",
> p_Arg2 = 1,
> p_Arg3 = 10,
> p_Arg4 = 25))
Yes. You __COULD__ do this. But that is much uglier than eliminated the
"named(" and ")" that surrounds the arguments. There is no way that I
would accept that in any code that I write against the driver. Just for
your amusement, I checked the DCOracle2 driver. They also use keyword
arguments when using named parameter binding. Specifically, they
support:
def execute(statement, *args) # positional binding
def execute(statement, **args) # named binding
def execute(statement, args) # positional binding for spec
So it would seem that I am not the only one who finds the spec
troublesome.
> >>>Creating a dictionary,
> >>>populating it with arguments and then passing it directly is against
> >>>normal Python syntax (in my opinion, anyway). I realize that until
> >>>Python 2.0 you couldn't pass a dictionary that you had prepared in
> >>>advance (the rare case) as keyword arguments but do we really need to
> >>>consider compatibility with Python 1.5 still?
> >>
> >>Hmm, I think you are talking about the apply() syntax
> >>which was added to Python in 2.0... fct(*args, **kws).
> >>That's syntactic sugar which exploits that arguments
> >>are treated internally as tuple and keyword arguments
> >>as dictionary.
> >>
> >>However, that's not how you normally call a function
> >>which has keywords or multiple parameters.
> >
> > No way. Take a look at the Python code in the wild. The number of times
> > that keyword arguments are used is amazing.
>
> I think you're misunderstand me here: calling a keyword
> parameter function using fct(**kws) is uncommon, not
> fct(keyword=value).
Yes it is. But having a dictionary already prepared to pass to an
execute function is also rare. The point is that the normal case is much
easier to write as keyword arguemnts and annoying to have to write with
a wrapper function (named) or by specifying the { and } closing braces
with strings and colons strewn throughout.
> > It happens to be one of
> > Python's strong points in my opinion. This is particularly common with
> > use of wxPython which has (often) reams of parameters of which only one
> > or two are of interest. Requiring a dictionary to be passed which
> > contains all of the arguments would make this unwieldy in a big hurry.
>
> Why ? Your statement will require to pass in *all* parameters
> anyway.
Syntactic sugar. None of the suggestions you gave above __LOOK__ good
but require all sorts of additional syntax. And I say -- why add the
extra syntax just for some foolish requirement of consistency?
> >>>Perhaps what needs to be specified is:
> >>>
> >>>execute(statement, *parameters) --> sequence (for non-named)
> >>>execute(statement, **parameters) --> mapping (for named)
> >>>
> >>>And this last one for backwards compatibility if necessary
> >>>
> >>>execute(statement, parameters) --> sequence or mapping depending on
> >>>module.paramstyle
> >>>
> >>>Any thoughts on that?
> >>
> >>IMHO, there's no need to change the spec, only clarify
> >>it where it is unclear.
> >
> > Definitely disagree. Let's change the spec to make it clear that keyword
> > arguments are to be preferred for named parameter passing. Anyone else
> > who has written drivers with named parameters want to chime in on this
> > one?
>
> I'm definitely -1 on changing the spec to make it more
> inconsitent. It has been around for a long time and proven its
> usability. I also don't think that the paramstyle idea was
> a good one and would rather like to go back to a sane single
> parameter style standard for DB API 3.0.
So you think that adding a parsing module to every driver is a __GOOD__
thing? Talk about adding overhead! The Oracle OCI already contains a
parsing module and you want me to add another one to convert from a
different parameter passing mechanism? Could you explain to me how this
might be beneficial?
--
Anthony Tuininga <anthony@computronix.com>