Deep vs. shallow copy?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu Mar 13 21:41:58 EDT 2014


On Fri, 14 Mar 2014 10:55:44 +1100, Chris Angelico wrote:

> On Fri, Mar 14, 2014 at 10:41 AM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> Are you trolling again?
>>
>> I'm sure that you know quite well that Python doesn't have a procedure
>> type. It uses a single keyword, def, for creating both functions and
>> functions-that-return-None.
> 
> I'm going to troll for a moment and give you a function that has no
> return value.

Heh, you're not trolling. You're just trying to be pedantic. But not 
pedantic enough... 


> def procedure():
>     raise Exception

This does have a return result, and it is None. It's just that the 
function never reaches the return, it exits early via an exception.

py> from dis import dis
py> dis(procedure)
  2           0 LOAD_GLOBAL              0 (Exception)
              3 RAISE_VARARGS            1
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE

That *may* be able to be optimized away by a smarter compiler, or perhaps 
it can't be. There may be some technical reason why code objects have to 
end with a return no matter what:

py> dis(compile("func()", "", "exec"))
  1           0 LOAD_NAME                0 (func)
              3 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
              6 POP_TOP
              7 LOAD_CONST               0 (None)
             10 RETURN_VALUE

Or maybe it's just an optimization that nobody has bothered with since 
the benefit is so trivial. But either way, all callables (sub-routines) 
in Python are functions, i.e. in principle they could, or should, return 
a result, even if in practice some of them don't. There is no callable 
type which lacks the ability to return a result.

Naturally they may not actually return a result if they never exit:

def this_is_a_function():
    while 1:
        pass
    return "You'll never see this!"

or if they exit via an exception:

def also_a_function():
    if 1:
        raise ValueError
    return "You'll never see this either!"

or if they just kill the running Python environment stone dead:

def still_a_function():
    import os
    os._exit(1)
    return "Have I beaten this dead horse enough?"


> But seriously, this is something that some functions do when they need
> to distinguish between returning something and not returning anything.
> Look at a dictionary's subscripting (which is effectively a function
> call):
> 
>>>> x={1:2}
>>>> x[1]
> 2
>>>> x[3]
> Traceback (most recent call last):
>   File "<pyshell#17>", line 1, in <module>
>     x[3]
> KeyError: 3

Yes, I'm aware that Python functions can raise exceptions :-)

 
> It can't return None to indicate "there was no such key in the
> dictionary", so it raises instead. There's only one way for a Python
> function to not have a return value: it has to not return.

Exactly my point. Functions return a value, and None is a value; 
procedures return, but not with a value. Python has the former, but not 
the later. Instead, we make do with the convention that something which 
is *intended* to be used as a procedure should return None to signal 
that, and the caller should just ignore the return result.




-- 
Steven D'Aprano
http://import-that.dreamwidth.org/



More information about the Python-list mailing list