Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Idiom gone, or did it really ever exist? () is ()

0 views
Skip to first unread message

Mike C. Fletcher

unread,
Apr 17, 2001, 11:59:43 PM4/17/01
to Python List (E-mail)
Over the years, I've occasionally used this idiom:

NULLARGUMENT = ()

def someFunctionOrMethod (argument = NULLARGUMENT ):
if argument is NULLARGUMENT:
doSomething()
else:
doSomethingElse()

That is, I was attempting to distinguish between a call where argument is
passed a NULL tuple and a call where argument is passed nothing at all.
When I was working on unit tests for my current piece of code, however, I
discovered that this no longer works (Python 1.5.2). No idea for how long
it hasn't worked. Now, of course, I could have used:

class NULL: pass
NULLARGUMENT = NULL() # a particular instance

or

NULLARGUMENT = NULL # use the class itself

or

NULLARGUMENT = []

or I could've used an approach where I used *arguments and **namedarguments
to determine whether the argument was really passed. There are all sorts of
other ways to do this. Apparently optimisation has come to the tuples of
the world, so using tuple identities is now a no-no.

All those who have used null-tuple identities should now go and fix their
code.
Mike

__________________________________
Mike C. Fletcher
Designer, VR Plumber
http://members.home.com/mcfletch


Delaney, Timothy

unread,
Apr 18, 2001, 2:34:59 AM4/18/01
to Steve Purcell, Mike C. Fletcher, Python List (E-mail)
> > Over the years, I've occasionally used this idiom:
> >
> > NULLARGUMENT = ()
> >
> > def someFunctionOrMethod (argument = NULLARGUMENT ):
> > if argument is NULLARGUMENT:
> > doSomething()
> > else:
> > doSomethingElse()
> >
> > That is, I was attempting to distinguish between a call
> where argument is
> > passed a NULL tuple and a call where argument is passed
> nothing at all.
> > When I was working on unit tests for my current piece of
> code, however, I
> > discovered that this no longer works (Python 1.5.2). No
> idea for how long
> > it hasn't worked. Now, of course, I could have used:
>
>
> The convention is to use 'None' for this purpose. 'None'
> never changes, so
> 'argument is None' will work correctly for you.

This will not actually work for the purpose though. The idea is to
distinguish between whether a parameter was passed, or whether the default
parameter is being used. Note: I've never tried this myself ...

If you have a default of None, it is impossible to determine this if the
user passes None - because it will be the same instance of None in almost
all cases.

Obviously, previously all tuples were distinct objects, even if they
compared the same. Thus this technique worked. However, some tuples are now
obviously being interned (the empty tuple for example), meaning that if a
user passes an empty tuple you can no longer distinguish the two.

# Will never work

def func (p=None):
if p is None:
print 'Default parameter'
else:
print 'Parameter passed'

func() # prints 'Default parameter'
func(None) # prints 'Default parameter'

# Will work if empty tuple is not interned

__nullArgument = ()

def func (p=__nullArgument):
if p is __nullArgument:
print 'Default parameter'
else:
print 'Parameter passed'

func() # prints 'Default parameter'
func(()) # we want it to print 'Parameter passed',
# will probably print 'Default parameter'

# Should always work

class nullArgument:
""""""

__nullArgument = nullArgument()

def func (p=__nullArgument):
if p is __nullArgument:
print 'Default parameter'
else:
print 'Parameter passed'

func() # prints 'Default parameter'
func(nullArgument()) # prints 'Parameter passed'

# There is a better way to do this one though ...

class __nullArgument:
""""""

__nullArgument = __nullArgument()

def func (p=__nullArgument):
if p is __nullArgument:
print 'Default parameter'
else:
print 'Parameter passed'

# Now *can't* pass an instance of the class, so it will never compare true

Tim Delaney

Steve Purcell

unread,
Apr 18, 2001, 2:11:47 AM4/18/01
to Mike C. Fletcher, Python List (E-mail)
Mike C. Fletcher wrote:
> Over the years, I've occasionally used this idiom:
>
> NULLARGUMENT = ()
>
> def someFunctionOrMethod (argument = NULLARGUMENT ):
> if argument is NULLARGUMENT:
> doSomething()
> else:
> doSomethingElse()
>
> That is, I was attempting to distinguish between a call where argument is
> passed a NULL tuple and a call where argument is passed nothing at all.
> When I was working on unit tests for my current piece of code, however, I
> discovered that this no longer works (Python 1.5.2). No idea for how long
> it hasn't worked. Now, of course, I could have used:


The convention is to use 'None' for this purpose. 'None' never changes, so
'argument is None' will work correctly for you.

-Steve


--
Steve Purcell, Pythangelist
Get testing at http://pyunit.sourceforge.net/
Any opinions expressed herein are my own and not necessarily those of Yahoo

Mike C. Fletcher

unread,
Apr 18, 2001, 4:36:00 AM4/18/01
to Tim Peters, Python List (E-mail)
Hmm, checking my code, you are right, the idiom I was actually using (in one
very old module still in my codebase, and which still works ;) ) was
(paraphrased):

NULL = (1,) # why doesn't () work? Get with it Guido ;)

As for cheating... no, actually, I didn't feel guilty, I was thinking of ()
and [] as being calls to constructors which returned shiny new tuple and/or
list objects (with the contents being arguments to those constructors).
I've learned a lot since then; now I know that the list gnomes and the tuple
fairies sneak in and replace the bracket characters with billows of cotton
candy. Problems arise when the cotton candy is soaked by over optimisation
by the evil language wizards, though I discovered that the resulting
solution is quite tasty when carbonated.

In some weird way, I like the is statement. It appears in thousands of
places throughout my code. I check object identity far more often than
object equivalence, as many of my libraries, in order to do a decent
equality check might have to do a recursive search through thousands of
nodes (and since they can have references to their parents, the equality
becomes quite ugly). Still, carbonation makes it all quite palatable.

Just because something is explicitly forbidden, goes against all laws of
nature, offends half the population, destroys one's life and family, and
casts one into the deepest pits of Tartarus doesn't necessarily mean that
thing should be avoided...

Or so I tell myself...
Mike

PS: Pointing out that it's in a document with the official disclaimer: "for
language lawyers" , is like pointing out ''There's no point in acting all
surprised about it. All the planning charts and demolition orders have been
on display in your local planning department on Alpha Centauri for fifty of
your Earth years, so you've had plenty of time to lodge any formal complaint
and it's far too late to start making a fuss about it now.'' ;)

-----Original Message-----
From: Tim Peters [mailto:tim...@home.com]
Sent: Wednesday, April 18, 2001 03:51
To: Python List (E-mail)
Subject: RE: Idiom gone, or did it really ever exist? () is ()
...
It has never worked by design. It stopped working by accident when Guido
added empty-tuple caching in revision 2.9 of tupleobject.c. He did that in
October of 1993. Have you been in a time warp <wink>?

Any code relying on unique object identity for literals of any object of any
immutable type is simply wrong. The language doesn't guarantee anything
here, and the implementation can & does vary across releases, or even
bugfixes. The Reference Manual has always said (section "Objects, values
and
types"):
...
I don't know what accounts for this. Do users not understand how object
identity works in Python, or are they so fanatically devoted to tricks that
they're willing to chance it despite knowing it isn't safe? 'Fess up, Mike:
my bet is that when you *started* using this trick, you knew you were
cheating.
...
More generally, people using "is" without knowing what they're doing should
simply stop using it, tuples or not. How to tell if you're one of them: if
when you use "is", you feel a twinge of pride in being clever <0.5 wink>.
Safe (intended, documented and supported) uses for "is" are dull as dog
food.
...


Duncan Booth

unread,
Apr 18, 2001, 5:17:39 AM4/18/01
to
"Mike C. Fletcher" <mcfl...@home.com> wrote in
<mailman.987578846...@python.org>:

> You want this kind of construct when creating "generic services" that
> can process any object type (including None), so need to be able to
> determine whether the object passed is, in fact, the value None, or
> merely the absence of a value.
>
>
So why not use the portable and safe way of finding out whether your
function was called with a particular argument or not?
def foo(**kw):
validargs = { 'bar': None }
validargs.update(kw)
assert len(validargs)==1

if kw.has_key('bar'):
print "Have bar"
else:
print "No bar"

--
Duncan Booth
dun...@dales.rmplc.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?

Alex Martelli

unread,
Apr 18, 2001, 7:00:43 AM4/18/01
to
"Mike C. Fletcher" <mcfl...@home.com> wrote in message
news:mailman.987583046...@python.org...

> Hmm, checking my code, you are right, the idiom I was actually using (in
one
> very old module still in my codebase, and which still works ;) ) was
> (paraphrased):
>
> NULL = (1,) # why doesn't () work? Get with it Guido ;)

Why not

_NULL = []

and then
def x(y=_NULL):
if y is _NULL: print "no argument"

i.e., your original trick, but with a _mutable_ object. This
way it should keep working forever, I believe.


Alex

Mike C. Fletcher

unread,
Apr 18, 2001, 11:37:57 AM4/18/01
to Python List (E-mail)
Yup, I mentioned that in the original article ;) (same with the *args,
**namedargs approaches). I actually switched to using this:

class NULLARGUMENT: pass

Then I use the class as the default value for is-checking.
Which I'm told is evil :) .
Mike

-----Original Message-----
From: Alex Martelli [mailto:ale...@yahoo.com]
Sent: Wednesday, April 18, 2001 07:01
To: pytho...@python.org
Subject: Re: Idiom gone, or did it really ever exist? () is ()
...

Why not

_NULL = []

and then
def x(y=_NULL):
if y is _NULL: print "no argument"

i.e., your original trick, but with a _mutable_ object. This
way it should keep working forever, I believe.

...


D-Man

unread,
Apr 18, 2001, 11:24:44 AM4/18/01
to Python List (E-mail)
On Wed, Apr 18, 2001 at 03:26:12AM -0400, Mike C. Fletcher wrote:
| You want this kind of construct when creating "generic services" that can
| process any object type (including None), so need to be able to determine
| whether the object passed is, in fact, the value None, or merely the absence
| of a value.

Umm, I might be missing something but I think the following does that
:


def my_func( an_arg ) :
do_something( an_arg )


If it is called with the absence of a value, an error will be raised
by the interpreter, otherwise it is passed an object (possibly None).

-D


Russell E. Owen

unread,
Apr 18, 2001, 12:53:49 PM4/18/01
to
In article <mailman.987566424...@python.org>,

"Mike C. Fletcher" <mcfl...@home.com> wrote:

>Over the years, I've occasionally used this idiom:
>
>NULLARGUMENT = ()
>
>def someFunctionOrMethod (argument = NULLARGUMENT ):
> if argument is NULLARGUMENT:
> doSomething()
> else:
> doSomethingElse()
>
>That is, I was attempting to distinguish between a call where argument is
>passed a NULL tuple and a call where argument is passed nothing at all.
>When I was working on unit tests for my current piece of code, however, I
>discovered that this no longer works (Python 1.5.2).

I like your idiom and often use it, but you have a minor bug. You say
you wish to distinguish between two cases:
- passing an empty tuple
- passing no argument at all
yet your default value for "argument" *is* an empty tuple, so your code
cannot do the job. If you really want to do this job, pick any other
default value, such as None or "".

A good choice of default depends on what values you expect. An example:
in some of my GUI coding I want to distinguish between three cases:
- use a user-specified label
- use a default label
- no label

In that case I tend to code things as follows:

def myFunc(label=None):
"""A demonstration of default arguments
Inputs:
- label: if omitted, a default is supplied; if "" then no label
"""
if label:
print "label =:", label
elif label is None:
print "default label"
else:
print "no label"

-- Russell

Stephen

unread,
Apr 18, 2001, 3:39:01 PM4/18/01
to
I _really_ just don't get why you're going through all the trouble.
IMHO the below looks cleaner, and works, and can't possibly be considered
evil. :)

def fun(*args):
if args == ((),):
print 'We passed an empty tuple'
elif args == ():
print 'We didn't pass any arguments'
else:
print 'We passed the following arguments:' % args

--Stephen
(replace 'NOSPAM' with 'seraph' to respond in email)
"Mike C. Fletcher" <mcfl...@home.com> wrote in message
news:mailman.987608307...@python.org...


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 80,000 Newsgroups - 16 Different Servers! =-----

Neil Schemenauer

unread,
Apr 18, 2001, 7:13:56 PM4/18/01
to Python List (E-mail)
Mike C. Fletcher wrote:
> NULL = (1,) # why doesn't () work? Get with it Guido ;)

That is another immutable object. CPython doesn't cache those
objects yet but its better to use:

NULL = []

instead. Or:

class NULL:
pass

if you think that's more clear.

Neil

Remco Gerlich

unread,
Apr 18, 2001, 8:23:02 PM4/18/01
to
D-Man <dsh...@rit.edu> wrote in comp.lang.python:

His function should also work when no argument was given. Except it should
do something special then.

--
Remco Gerlich

Michael Haggerty

unread,
Apr 19, 2001, 5:04:12 PM4/19/01
to
"Delaney, Timothy" <tdel...@avaya.com> writes:
> > > That is, I was attempting to distinguish between a call where
> > > argument is passed a NULL tuple and a call where argument is
> > > passed nothing at all.
>
> # Should always work
>
> class nullArgument:
> """"""
>
> __nullArgument = nullArgument()
>
> def func (p=__nullArgument):
> if p is __nullArgument:
> print 'Default parameter'
> else:
> print 'Parameter passed'

When I first faced this problem, I started typing in code that was
equivalent to yours, until it occurred to me that there is no reason
to instantiate the class--the class itself serves as a fine default
argument. In other words,

class __nullArgument:
pass # Isn't this what pass is for?

def func (p=__nullArgument):
if p is __nullArgument:
print 'Default parameter'
else:
print 'Parameter passed'

Cheers,
Michael

--
Michael Haggerty
mha...@alum.mit.edu

0 new messages