pep 336: Make None Callable

  • Thread starter The Eternal Squire
  • Start date
T

The Eternal Squire

PEP: 336
Title: Make None Callable
Version: $Revision: 1.1 $
Last-Modified: $Date: 2004/11/03 16:58:30 $
Author: Andrew McClelland
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 28-Oct-2004
Post-History:


Abstract

None should be a callable object that when called with any
arguments has no side effect and returns None.


Motivation

To allow a programming style for selectable actions that is more
in accordance with the minimalistic functional programming goals
of the Python language.


Rationale

Allow the use of None in method tables as a universal no effect
rather than either (1) checking a method table entry against None
before calling, or (2) writing a local no effect method with
arguments similar to other functions in the table.

The semantics would be effectively,

class None:

def __call__(self, *args):
pass


How To Use

Before, checking function table entry against None:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
function = { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, None)
if function: return function(input)

Before, using a local no effect method:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def nop(self, input):
pass

def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, self.nop)(input)

After:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, None)(input)


References

[1] Python Reference Manual, Section 3.2,
http://docs.python.org/ref/ref.html


Copyright

This document has been placed in the public domain.



Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
 
T

Terry Reedy

The Eternal Squire said:
PEP: 336
Abstract

None should be a callable object that when called with any
arguments has no side effect and returns None.

Please no. The None object, by definition, is an object with no value, no
behavior (except compares), and no specific attributes (other than those
common to all descendents of object). That one can currently compare None
to other objects can be considered a bug, and this might go away in the
future.

Anyone who wants a null function can write it in about 20 keypresses, and
include it in a utility module if one has one.

It would be more sensible to promote the addition to builtins of a
predefined null function -- one somewhat equivalent to 0, [], and {}.

Terry J. Reedy
 
B

Bengt Richter

PEP: 336
Title: Make None Callable
Version: $Revision: 1.1 $
Last-Modified: $Date: 2004/11/03 16:58:30 $
Author: Andrew McClelland
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 28-Oct-2004
Post-History:


Abstract

None should be a callable object that when called with any
arguments has no side effect and returns None.


Motivation

To allow a programming style for selectable actions that is more
in accordance with the minimalistic functional programming goals
of the Python language.
IMO in the context of selectable actions, the noop should be a noop function,
not None, e.g.,

def Noop(*args, **kwargs): pass
Rationale

Allow the use of None in method tables as a universal no effect
rather than either (1) checking a method table entry against None
before calling, or (2) writing a local no effect method with
IMO (3) using a global def Noop should take care of it.
arguments similar to other functions in the table.

The semantics would be effectively,

class None:

def __call__(self, *args):
^-- ,**kw # otherwise it might bomb ;-)
pass


How To Use

Before, checking function table entry against None:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
function = { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, Noop)
return function(input)

#XXX> }.get(input, None)
#XXX> if function: return function(input)
Before, using a local no effect method:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'
#XXX> def nop(self, input):
#XXX> pass
def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, Noop)(input)

#XXX> }.get(input, self.nop)(input)
After:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, Noop)(input)

#XXX> }.get(input, None)(input)
References

[1] Python Reference Manual, Section 3.2,
http://docs.python.org/ref/ref.html


Copyright

This document has been placed in the public domain.



Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:

I'd rather not complicate the meaning of None, I think ;-)

Regards,
Bengt Richter
 
T

The Eternal Squire

Terry said:
Please no. The None object, by definition, is an object with no value, no
behavior (except compares), and no specific attributes (other than those
common to all descendents of object).

I always saw None not as an object without value, but as the universal
false or ground symbol, similar to NIL in Lisp.

That one can currently compare None
to other objects can be considered a bug, and this might go away in the
future.

Anyone who wants a null function can write it in about 20 keypresses, and
include it in a utility module if one has one.

But isn't the point of Pythonic style to write something as tersely
elegant as possible? I'd rather not see a bunch of null methods
sprinkled thru the classes in the libraries that I have to write, and
I'd rather not to have to import it either.
It would be more sensible to promote the addition to builtins of a
predefined null function -- one somewhat equivalent to 0, [], and {}.

I'd like to see it standardized, and I'd like to see it intuitively
obvious. That's why None appears to me to be such an obvious candidate.
If None is seen as the ground symbol that happens to evaluated to false
in logical expressions, that it would seem to make sense to say that
calling the symbol is another form of evaluation of the symbol, and so
if evaluating None as a value results in None, then evaluating None as
a call should also result in None.
 
A

Aahz

Title: Make None Callable

No, *no*, *NO*, and *HELL NO*.

OTOH, once the BDFL Pronounces, we can return to laughing and pointing
the next time this comes up.
 
T

Terry Hancock

Please no. The None object, by definition, is an object with no value, no
behavior (except compares), and no specific attributes (other than those
common to all descendents of object). That one can currently compare None
to other objects can be considered a bug, and this might go away in the
future.

Maybe. But all this requires, really, is to make None fail silently when
called instead of raising an error as it does now. That could be seen
as quite consistent with its null nature, IMHO.
Anyone who wants a null function can write it in about 20 keypresses, and
include it in a utility module if one has one.

True, and I have done so. But that's "20 keypresses" repeated a lot. And
what's it called? "do_nothing()" (my usual name), "null_function()",
"null()", "empty()", "NoneFunc()" etc? Furthermore, it's much more obvious
to store "None" when you want nothing to happen. I usually instead
provide code in the caller to check for a None (or generic "False")
state before calling, like so:

if func: func()

Is there a good use case where this rather concise idiom won't do?
It would be more sensible to promote the addition to builtins of a
predefined null function -- one somewhat equivalent to 0, [], and {}.

Maybe, but I think it's worth asking -- what use is the traceback from
the None object when it is called? Does it help in QA of code? Is
there a common idiom that would be broken by a callable None?
 
T

The Eternal Squire

Why not?
No, *no*, *NO*, and *HELL NO*.

OTOH, once the BDFL Pronounces, we can return to laughing and pointing
the next time this comes up.
 
S

Steven Bethard

The Eternal Squire said:
Before, checking function table entry against None:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
function = { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, None)
if function: return function(input)

Another possibility:
.... def a(self, input):
.... print 'a'
.... def b(self, input):
.... print 'b'
.... def c(self, input):
.... print 'c'
.... def __call__(self, input):
.... try:
.... return {1:self.a,
.... 2:self.b,
.... 3:self.c}[input](input)
.... except KeyError:
.... pass
....
I find this one much more useful. Rarely do I truly want a no-op if I get a
value that isn't in my dict, in which case there is something other than pass in
the except block.

Steve
 
R

Roman Suzi

I'd rather not complicate the meaning of None, I think ;-)

Regards,
Bengt Richter

I completely agree. As a note, I can remind a
PEP 312 -- Simple Implicit Lambda. So with implicit lambda this is just

:None

For example:

do_something(a, visitor1, visitor2, :None, :None)

which roughly translates to:

do_something(a, visitor1, visitor2, lambda:None, lambda:None)

Is it right time to start PEP 312

Anyway, please refer to PEP 312 in PEP 336


Sincerely yours, Roman A.Suzi
 
M

Mike C. Fletcher

Bengt said:
....
....

IMO in the context of selectable actions, the noop should be a noop function,
not None, e.g.,

def Noop(*args, **kwargs): pass
IMO this (defining an object (e.g. a function)) which is explicitly
intended to be used for such a thing is far better than adding to the
semantics of None at this late date. For instance, the original
proposal would completely change the semantics of this code:

method = methods.get( someKey )
try:
method( my, arguments, are=here)
except TypeError, err:
pass

it would also alter the results of this:

callable( None )

so that any code which is using the exception-raising or callable to
catch an undefined method-table-lookup will now fail (silently, I might
add).

Defining a function/object for use in such situations is fine, but
altering such commonly referenced functionality of one of the most
"core" objects in Python is, I would suggest, a seriously sub-optimal
forward path. The path forward, I would think, would be to find a good
place for such a function/object to live and slotting it in there so
that it's naturally available. If there were, for instance, a
"functional" module, with such an object in it, it would make perfect
sense to write:

methods.get( somekey, functional.noop )

and you would get the functionality without muddying the semantics of
None at this late date.

Just MHO,
Mike

________________________________________________
Mike C. Fletcher
Designer, VR Plumber, Coder
http://www.vrplumber.com
http://blog.vrplumber.com
 
D

Dave Benjamin

The said:
None should be a callable object that when called with any
arguments has no side effect and returns None.

This is how ActionScript works, and to be honest I strongly dislike this
behavior. It hides bugs, and to make things worse, the null often
bubbles up someplace entirely different from where the error initially
occurred. This makes debugging a pain in the ass.

I'd prefer to just write a NullObject if I need one. Otherwise, I like
Python's behavior, which is more fail-fast and less error-prone. IMHO.

But thanks for putting the idea out. I think Objective C does something
similar--is this the case? It does have the convenient effect of
allowing you to pass null as an event listener if you just want to
ignore events from a GUI object, for instance, but it's just not worth
the price.

Dave
 
P

Peter Otten

The said:
None should be a callable object that when called with any
arguments has no side effect and returns None.

Why would you stop there?
.... def __call__(self, *args, **kw):
.... return BusyNone
.... __getattr__ = __getitem__ = __add__ = __call__
.... def __str__(self):
.... return "BusyNone"
.... __repr__ = __str__
....
BusyNone = BusyNone()
BusyNone("a", 1) BusyNone
BusyNone[1:2] BusyNone
BusyNone.busyAttr BusyNone
BusyNone + 42 BusyNone
len(BusyNone)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: len() of unsized object

Still room for improvement, but you should get the idea...

Peter
 
A

Alex Martelli

Terry Hancock said:
It would be more sensible to promote the addition to builtins of a
predefined null function -- one somewhat equivalent to 0, [], and {}.

Maybe, but I think it's worth asking -- what use is the traceback from
the None object when it is called? Does it help in QA of code? Is

Yes: it wards against the reasonably common bug of forgetting a return
statement, for example --

def make_adder(addend):
def adder(augend): return addend + augend

the programmer forgot a 'return adder' as the last line -- oops, no big
deal, it will be caught extremely soon, thanks to None not being
callable.
there a common idiom that would be broken by a callable None?

None I can think of, but then, the same could be said of many possible
loosenings -- accepting, say, " 2 + '23' " and returning either '223' or
25 would break no common idioms, either... it would just make Python
less good at catching some common bugs. Errors should not pass
silently...

"Null Object" is a great Design Pattern (not in the Gof4 book, but still
a classic, from a reasonably early PLOP), and I would love it if Python
embodied it, as it embodies so many other useful ones. But we should
not overload None to play the role of Null, I think. Rather, Null
should be another object, either built-in or in some module. Besides
the equivalent of a 'def __call__(self, *a,**k): return self', it should
have many other "do-nothing" special methods -- including a __getattr__,
btw. We should also have type(Null) is Null -- and Null should be
subclassable too, because there are a few design choices which, however
we make them in the Null class, may need tweaking in a user-coded
subclass (e.g., should str(Null) be 'Null' or ''?).

There are Null Object classes in the cookbook -- all the way from a
simple 'donuttincallable' to a full-fledged Null Object -- and that's
where I'm putting all of my considerations on the issue, but I'll be
glad to have them embodied in a PEP if needed.

But the Null should NOT be None, the DEFAULT return value of functions
without a return statement etc etc. Explicit is better than implicit.


Alex
 
J

John Roth

This is simply propagating the
effect of a null pointer in C.
That's what the null object
pattern is for.

John Roth
 
A

Aahz

Before I respond:

A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet?
 
G

Grant Edwards

But isn't the point of Pythonic style to write something as
tersely elegant as possible?

Nope. You seem to have completely missed the Zen of Python.

The "point" of Python is to write something in the manner most
easily read, understood, and maintained. If that takes more
lines of souce code than a "terse and elelgent" one-liner
that's impossible to read the next day, so be it.
I'd rather not see a bunch of null methods sprinkled thru the
classes in the libraries that I have to write, and I'd rather
not to have to import it either.

Then create a single, global Noop object.
 
C

Chris Cioffi

At first I really liked this idea, however as I thought about it I
really came to dislike it.

None isn't Null. I write a lot of dispatch style code and I use the
fact that None isn't callable to speed up debugging. I'll do
something like this:

if __debug__:
noop = None
else:
noop = DoNothing
methods.get(value, noop)()

This lets me catch errors quickly while debugging, and lets my
DoNothing function (which may just log the fact that a error occured)
keep the program running as long as possible. I suspect that this
idiom is fairly common.

While I would support the addition of a builtin Null object (I stole
the one from then cookbook for my use), I don't like the idea of
extending None.

While right now it's more of a viseral gut feeling, I really like the
idea that None is the anti-object. It is itself and nothing more.
Even when we type it: None. it's the only builtin that is
capitalized. Not just a none, but the None. The definate article.
The alpha and omega, unchanging and unwilling to act.

My vote is -1.

Chris

PEP: 336
Title: Make None Callable
Version: $Revision: 1.1 $
Last-Modified: $Date: 2004/11/03 16:58:30 $
Author: Andrew McClelland
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 28-Oct-2004
Post-History:

Abstract

None should be a callable object that when called with any
arguments has no side effect and returns None.

Motivation

To allow a programming style for selectable actions that is more
in accordance with the minimalistic functional programming goals
of the Python language.

Rationale

Allow the use of None in method tables as a universal no effect
rather than either (1) checking a method table entry against None
before calling, or (2) writing a local no effect method with
arguments similar to other functions in the table.

The semantics would be effectively,

class None:

def __call__(self, *args):
pass

How To Use

Before, checking function table entry against None:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
function = { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, None)
if function: return function(input)

Before, using a local no effect method:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def nop(self, input):
pass

def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, self.nop)(input)

After:

class Select:

def a(self, input):
print 'a'

def b(self, input):
print 'b'

def c(self, input);
print 'c'

def __call__(self, input):
return { 1 : self.a,
2 : self.b,
3 : self.c
}.get(input, None)(input)

References

[1] Python Reference Manual, Section 3.2,
http://docs.python.org/ref/ref.html

Copyright

This document has been placed in the public domain.

Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
 
T

Terry Hancock

Terry Hancock said:
It would be more sensible to promote the addition to builtins of a
predefined null function -- one somewhat equivalent to 0, [], and {}.

Maybe, but I think it's worth asking -- what use is the traceback from
the None object when it is called? Does it help in QA of code? Is

Yes: it wards against the reasonably common bug of forgetting a return
statement, for example --

def make_adder(addend):
def adder(augend): return addend + augend

the programmer forgot a 'return adder' as the last line -- oops, no big
deal, it will be caught extremely soon, thanks to None not being
callable.
"Null Object" is a great Design Pattern (not in the Gof4 book, but still
a classic, from a reasonably early PLOP), and I would love it if Python
embodied it, as it embodies so many other useful ones. But we should
not overload None to play the role of Null, I think. Rather, Null
should be another object, either built-in or in some module.
[...]

Yeah, you're probably right. I kind of liked the lambda idiom that was
suggested up-thread (by Roman Suzi), though it's not clear to me that
replacing "lambda:" with ":" is that important:

Setting null functions to lambda seems useful.

I just noticed though, that:

noop = lambda *a, **kw: None

is illegal (apparently lambda doesn't support argument indirection (or
whatever that "*" syntax is properly called)). Never tried it before.

Still, most of the time when you want to follow this pattern, you
probably want a consistent calling profile, and if you do use a
function to generate these functions, you can easily:

return lambda a,b, spam=None: None

for example, following the particular profile you need.

Maybe there should be a noop built-in, though?

Cheers,
Terry
 
A

Alex Martelli

Terry Hancock said:
I just noticed though, that:

noop = lambda *a, **kw: None

is illegal (apparently lambda doesn't support argument indirection (or
whatever that "*" syntax is properly called)). Never tried it before.

??? it's quite OK:

kallisti:~/cb/cha/oop/cba alex$ python2.3
Python 2.3 (#1, Sep 13 2003, 00:49:11)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1495)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Maybe there should be a noop built-in, though?

A Null object, whether built-in on in the stdlib, sounds better to me.
Calling is just one of N operations you may want to do on it, after all!
Indexing, slicing, and so forth -- why not cover those, too?


Alex
 
D

Daniel Fackrell

[snip lots of good stuff]
Maybe there should be a noop built-in, though?

Cheers,
Terry

If it were possible, pass() would seem to make sense to me for this purpose,
as it's already a no-op. Too bad 'pass' is a reserved word and not likely
to be capable of being overloaded in this way.

----
def a():
return 1

def b():
return 2

funcs = [a, pass, b]

for func in funcs:
func()
----

Maybe this comes from my recent wonderings about the separation between
reserved words and callables, though. I was thinking along the lines that
def and class in particular could be interesting (though not necessarily
useful) with callable versions and hacked together the following:

----
def class_(args, code, name='__anon__'):
'''Class generator'''
code = code.split('\n')
for index in range(len(code)):
code[index] = ' %s' % code[index]
code.insert(0, 'class C(%s):' % args )
code = '\n'.join(code)
exec(code)
C.__name__ = name
return C

def def_(args, code, name='__anon__'):
'''Function generator'''
code = code.split('\n')
for index in range(len(code)):
code[index] = ' %s' % code[index]
code.insert(0, 'def F(%s):' % args )
code = '\n'.join(code)
exec(code)
F.__name__ = name
return F

def lambda_(args, expression):
return def_(args, 'return %s' % expression, '<lambda>')
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top