[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Introducing the "for" loop

On 6 October 2017 at 13:44, ROGER GRAYDON CHRISTMAN <dvl at psu.edu> wrote:
> Despite the documentation, I would still be tempted to say that range is a
> function.
> Taking duck-typing to the meta-level, every time I use range, I use its name
> followed
> by a pair of parentheses enclosing one to three parameters, and I get back an
> immutable sequence object.   It sure looks like a function to me.
> I would similarly say that map is a function, or an iterator generator I write
> myself
> with yield statements is a function, both of which also return sequences.
> It is not clear to me what the difference really is between my conception
> and the official definition -- is it a question about whether it returns a
> first-class object?
> Or more simply, what is the clear and obvious distinction that I can give to my
> non-scientific laypeople about why range isn't a function, if it looks like one?

Technically, range (and the other examples you mentioned) is a
"callable". The concept of a callable is closer to the intuitive
meaning of "function" than the things Python technically calls
functions. And most code accepts callables rather than functions
(i.e., there's little if anything that rejects range because it's a
callable not a function).

Duck typing means that you can take

    class C:

    c = C()

and replace it with

    class C_impl:
    def C():
        return C_impl()

    c = C()

and there's little or no difference. In the first, C is a class. In
the second it's a (factory) function. You can tell the difference, via
introspection. But it's unlikely you'd care in practice.

As to the technical differences, you can use type() to tell:

>>> def f(): pass
>>> class F: pass
>>> type(f)
<class 'function'>
>>> type(F)
<class 'type'>
>>> type(range)
<class 'type'>
>>> type(map)
<class 'type'>
>>> type(open)
<class 'builtin_function_or_method'>

Note the last - built in functions are implemented in C, and behave
slightly differently than *either* functions or classes. But you're
unlikely to ever care. One example:

>>> f.attr = 1
>>> open.attr = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'builtin_function_or_method' object has no attribute 'attr'

functions defined in Python can have user-defined attributes, builtins can't.

Embrace duck typing, and only care about what you can do, not what
type of object you're doing it to ;-)