Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   function argument dependent on another function argument? (http://www.velocityreviews.com/forums/t666112-function-argument-dependent-on-another-function-argument.html)

Reckoner 01-18-2009 02:19 PM

function argument dependent on another function argument?
 

I would like to do:

def foo(self,x,y=self.a)

where the default value for y=self.a. Since this is not possible, I
wind up doing


def foo(self,x,y=None)
if not y:
y=self.a

but that seems kind of clumsy.

Is there a better way to do this?

Thanks in advance

Aaron Brady 01-18-2009 02:41 PM

Re: function argument dependent on another function argument?
 
On Jan 18, 8:19*am, Reckoner <recko...@gmail.com> wrote:
> I *would like to do:
>
> def foo(self,x,y=self.a)
>
> where the default value for y=self.a. Since this is not possible, I
> wind up doing
>
> def foo(self,x,y=None)
> * if not y:
> * * y=self.a
>
> but that seems kind of clumsy.
>
> Is there a better way to do this?
>
> Thanks in advance


No. The only alternative is really niche and probably not what you
want. You'd use a decorator (which I don't have, btw):

@defval( y= selfattrget( 'a' ) )
def foo( self, x, y ).




Steven D'Aprano 01-18-2009 03:26 PM

Re: function argument dependent on another function argument?
 
On Sun, 18 Jan 2009 06:19:03 -0800, Reckoner wrote:

> I would like to do:
>
> def foo(self,x,y=self.a)
>
> where the default value for y=self.a. Since this is not possible, I wind
> up doing
>
>
> def foo(self,x,y=None)
> if not y:
> y=self.a
>
> but that seems kind of clumsy.


It's also incorrect, because if you pass y=0 as an argument, or any other
false value, it will be replaced by self.a.


> Is there a better way to do this?


def foo(self, x, y=None):
if y is None:
y = self.a


I don't find that clumsy in the least. I find it perfectly readable and a
standard idiom.


--
Steven

Paul Rubin 01-18-2009 03:36 PM

Re: function argument dependent on another function argument?
 
Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> def foo(self, x, y=None):
> if y is None:
> y = self.a
>
> I don't find that clumsy in the least. I find it perfectly readable and a
> standard idiom.


That has the same problem as the earlier version. If the person
passes None, they get self.a. I prefer:

sentinel = object()
...

def foo(x, y=sentinel):
if y is sentinel:
y = self.a

Aaron Brady 01-18-2009 03:49 PM

Re: function argument dependent on another function argument?
 
On Jan 18, 9:36*am, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
> > def foo(self, x, y=None):
> > * * if y is None:
> > * * * * y = self.a

>
> > I don't find that clumsy in the least. I find it perfectly readable and a
> > standard idiom.

>
> That has the same problem as the earlier version. *If the person
> passes None, they get self.a. *I prefer:
>
> * * sentinel = object()
> * * ...
>
> * * def foo(x, y=sentinel):
> * * * if y is sentinel:
> * * * * * y = self.a


It is too bad that it is so much work to detect whether 'y' was passed
in the function call directly. However, sentinel is just as good (or
nearly); at worst, you need one sentinel per argument per function,
which is possible to create, which has a specific meaning. If you are
making systematic function calls, e.g. with a dictionary or list, you
can just use the sentinel in the dictionary.

Aaron Brady 01-18-2009 05:16 PM

Re: function argument dependent on another function argument?
 
On Jan 18, 10:44*am, Rob Williscroft <r...@freenet.co.uk> wrote:
> Aaron Brady wrote innews:6a10378f-addb-4d56-bc1b-0c382b3cb957@t26g2000prh..googlegroups.com
> in comp.lang.python:
>
>
>
> > On Jan 18, 9:36*am, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> >> Steven D'Aprano <st...@REMOVE-THIS-cybersource.com.au> writes:
> >> > def foo(self, x, y=None):
> >> > * * if y is None:
> >> > * * * * y = self.a

>
> >> > I don't find that clumsy in the least. I find it perfectly readable
> >> > and

> > *a
> >> > standard idiom.

>
> >> That has the same problem as the earlier version. *If the person
> >> passes None, they get self.a. *I prefer:

>
> >> * * sentinel = object()
> >> * * ...

>
> >> * * def foo(x, y=sentinel):
> >> * * * if y is sentinel:
> >> * * * * * y = self.a

>
> > It is too bad that it is so much work to detect whether 'y' was passed
> > in the function call directly. *However, sentinel is just as good (or
> > nearly); at worst, you need one sentinel per argument per function,

>
> One per Module should be good enough. The only reason None doesen't
> suffice is that it has other legitimate uses. *Though to be honest
> I would always use None as the sentinel if it wasn't a legitimate
> argument.
>
> > which is possible to create, which has a specific meaning. *If you are
> > making systematic function calls, e.g. with a dictionary or list, you
> > can just use the sentinel in the dictionary.

>
> IIUYC then, one sentinel is still only needed as the missing argument
> is indicated by *both* position and value or by name and value (in the
> case of a keyword-dictionary), so seperate distinct sentinel objects
> aren't required, for example:
>
> SENTINEL = object()
>
> def f( a, b, c = SENTINEL, d = SENTINEL ):
> * print( "values: %r" % ( ( a, b, c, d ), ) )
> * if c is SENTINEL:
> * * print( "c is missing" )
> * if d is SENTINEL:
> * * print( "d is missing" )
>
> f( *( 1, 2, SENTINEL, SENTINEL ) )
>
> f( **dict( a = 1 , b = 2, d = 4 ) )
>
> f( **dict( a = 1 , b = 2, d = 4, c = SENTINEL ) )
>
> Rob.
> --http://www.victim-prime.dsl.pipex.com/


I don't have a concrete example, so you may prove to be right, but I'm
not convinced.

If you have one function with an argument that defaults to an empty
list, and calls another with an argument that defaults to an empty
dict, then what is the meaning of passing sentinel to the first one?
Whereas, if each had their own, then passing the first one's default
would mean the empty list, and passing the second one's default would
mean the dict.

(Or, even if that evaluates correctly, perhaps there is no such useful
program.)

andrew cooke 01-18-2009 06:42 PM

Re: function argument dependent on another function argument?
 
> * * sentinel = object()
> * * ...
>
> * * def foo(x, y=sentinel):
> * * * if y is sentinel:
> * * * * * y = self.a


it just struck me you could also do:

def foo(self, x, *y_args)
y = y_args[0] if y_args self.a

which more directly checks whether an argument was passed, but has the
downside of making the method signature less clear in the declaration.

andrew

Steven D'Aprano 01-18-2009 10:28 PM

Re: function argument dependent on another function argument?
 
On Sun, 18 Jan 2009 07:36:53 -0800, Paul Rubin wrote:

> Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
>> def foo(self, x, y=None):
>> if y is None:
>> y = self.a
>>
>> I don't find that clumsy in the least. I find it perfectly readable and
>> a standard idiom.

>
> That has the same problem as the earlier version.


No it doesn't. The earlier version had the problem that *any* false
object is replaced by self.a. I'm just following the standard Python
idiom of using None as a sentinel. Have a look through the standard
library and see how many times it is used.

Built-ins rarely accept None as a sentinel, slice() being a conspicuous
exception. This is sometimes a nuisance when writing wrappers:

def my_find(S, sub, start=None, end=None):
"""Like string.find() only with pre-processing."""
pre_process() # stub for something complicated
if end is None and start is None:
return S.find(sub)
elif end if None:
return S.find(sub, start)
else:
return S.find(sub, start, end)

or if you prefer:

def my_find(S, sub, start=None, end=None):
"""Like string.find()"""
pre_process()
args = [sub]
if start is not None:
args.append(start)
if end is not None:
args.append(end)
return S.find(*args)


Having said that, there are times where you need to pass None as a
legitimate argument and not as a sentinel. In that case, your solution:

> If the person passes
> None, they get self.a. I prefer:
>
> sentinel = object()
> ...
>
> def foo(x, y=sentinel):
> if y is sentinel:
> y = self.a


is an excellent one.


--
Steven

Paul Rubin 01-18-2009 10:47 PM

Re: function argument dependent on another function argument?
 
Steven D'Aprano <steve@REMOVE-THIS-cybersource.com.au> writes:
> Having said that, there are times where you need to pass None as a
> legitimate argument and not as a sentinel.


I don't think it's worth trying to figure out which those times are.
The conclusion can be wrong, or can become wrong later because of
some faraway change in the code. I prefer using the bulletproof
method from the beginning, whether it is needed or not.

Aaron Brady 01-19-2009 02:45 AM

Re: function argument dependent on another function argument?
 
On Jan 18, 12:42*pm, andrew cooke <and...@acooke.org> wrote:
> > * * sentinel = object()
> > * * ...

>
> > * * def foo(x, y=sentinel):
> > * * * if y is sentinel:
> > * * * * * y = self.a

>
> it just struck me you could also do:
>
> * * *def foo(self, x, *y_args)
> * * * *y = y_args[0] if y_args self.a
>
> which more directly checks whether an argument was passed, but has the
> downside of making the method signature less clear in the declaration.
>
> andrew


Also, if you need to change your calling signature down the line, this
alternative really ties your hands with regard to it. You also lose
the ability to pass 'y' by keyword.

George Sakkis, who I only know from the NG, has a recipe that tests a
call against a function signature to determine what arguments are
being passed. The 'inspect' module also has the 'getargvalues'
function, which does something similar.


All times are GMT. The time now is 02:57 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.