Suggestions for good programming practices?

Bengt Richter bokr at oz.net
Wed Jun 26 15:53:44 EDT 2002


On Wed, 26 Jun 2002 10:20:38 +0100, Jonathan Hogg <jonathan at onegoodidea.com> wrote:

>On 26/6/2002 1:53, in article afb3a2$skm$0 at 216.39.172.122, "Bengt Richter"
><bokr at oz.net> wrote:
>
>> Well, I meant using *args to allow detecting actual "no default-overriding
>> argument passed", in place of x=None. The arg list items (only x here)
>> don't have to remain unnamed long. E.g.,
>> 
>>>>> def foo(*args):
>> ...     if len(args)==1:
>> ...         print "We know we have one non-default arg: %s" % `args[0]`
>> ...         x = args[0]
>> ...     elif len(args)==0:
>> ...         print "We can supply a default arg, even None"
>> ...         x = None
>> ...     else: raise TypeError,'foo() takes 0 or 1 arguments (%d given)' %
>> len(args)
>> ...     print 'Effective arg was: %s' % `x`
>> ...
>
>I find this stuff much easier to write with a helper function:
>
>>>> def shift():
>...     global _0
>...     __, _0 = _0[0], _0[1:]
>...     return __
>... 
>
>Then I can write the function 'foo' much more naturally as:
>
>>>> def foo( *args ):
>...     global _0; _0 = args
>...     try:
>...         x = shift()
>...     except IndexError:
>...         print 'We can supply a default arg, even None'
>...         x = None
>...     else:
>...         try:
>...             shift()
>...         except IndexError:
>...             print 'We know we have one non-default arg: %s' % `x`
>...         else:
>...             raise TypeError( 'foo() takes 0 or 1 arguments' )
>...     print 'Effective arg was: %s' % `x`
>...
>
>This can be further simplified by removing the '*args' nonsense altogether
>and defining another helper function:
>
>>>> def p( f ):
>...     def _p( *args ): global _0; _0 = args; f()
>...     return _p
>...
>>>> def foo():
>...     try:
>...         x = shift()
>[etc]
>...
>>>> p(foo)( 'hello world' )
>
LOL ;-)

>
>How did we get onto this from 'Suggestions for good programming practices'?
>
I guess from where I picked up: x=None usage => default args => alternatives => rambling on ...
=> *args use analogous to C++ void foo(const char* s){...}; and
void foo(const int x, const int y, const char* s){...}; to allow foo("s only") and
foo(123, 456, "s with ints") overloading via Python dynamic recognition instead of statically
via C++ ?foo@@YAXPBD at Z vs ?foo@@YAXHHPBD at Z => non-Python odor? => Bad Thing(tm) or caller-friendly?

ISTM caller-friendly is good, but the *args implementation of this overloading is not as nice
as it could be. Is it better to allow foo(x,y,s) and foo(s) via overloaded foo() than, e.g.,
to use separate names like fooxy(x,y,s) and foo(s), and have foo() call fooxy()?
(That, at least, is an OT question ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list