[Python-ideas] pep-0484 - Forward references and Didactics - be orthogonal

Steven D'Aprano steve at pearwood.info
Tue Aug 25 04:52:09 CEST 2015


On Mon, Aug 24, 2015 at 06:19:47AM +0200, Prof. Dr. L. Humbert wrote:
[...]

> What students should be able to code:
> 
> 1. varinat
> #-------------wishful----------------------------------\
> class Tree:
>     def __init__(self, left: Tree, right: Tree):
>         self.left = left
>         self.right = right

That would be very nice, but I don't see how it would be possible in a 
dynamic language with Python's rules. Can you explain how you expect 
this to work? In particular, what happens if Tree already has a value?

Tree = "This is my Tree!"

class Tree:
    def __init__(self, left: Tree, right: Tree):
        ...


What happens if you use Tree outside of an annotation?

# somehow, we enable forward declarations
class Tree:
    x = Tree  # What is the value of x here?


The difficulty is that annotations are not merely declarations to the 
compiler, they have runtime effects as well.

If they were pure declarations, we could invent some ad hoc rule like 
"if an annotation is an unbound name, inside a class, and that name is 
the same as the class, then treat it as a forward declaration". But we 
can't, because the __init__ function object needs to set the annotations 
before the Tree class exists. So the annotation needs to be something 
that actually exists. In order for the annotation to use Tree (without 
quotation marks) the name Tree needs to be bound to some existing value, 
and that value is used as the annotation, not the Tree class.

If you can think of some way around this restriction, preferably one 
which is backwards-compatible (although that is not absolutely required) 
then please suggest it.


> what students have to write instead:
> 
> #-------------bad workaround----------------------------\
> class Tree:
>     def __init__(self, left: 'Tree', right: 'Tree'):
>         self.left = left
>         self.right = right

I don't think this is a "bad" work-around. I think it is quite a good 
one. It is sad that we need a work-around, but given that we do, this is 
simple to use and learn:

If the type already exists, you can annotate variables with the type 
itself. But if the type doesn't yet exist (say you are still 
constructing it), you will get a NameError, so you can use the name of 
the class as a string as a forward declaration:

class Tree:
    # At this point, Tree is still being constructed, and the class
    # doesn't yet exist, so we need to use a forward reference.
    def __eq__(self, other: 'Tree') -> Bool:
        ...

# At this point, the Tree class exists and no forward reference 
# is needed.
def builder(data: List) -> Tree:
    ...



> /
> Please enable:
> from __future__ import annotations
> 
> so the *first* variant should be possible
> \
> At this very moment (python 3.5rc1), it is not possible, but we need it,
> so the construction will be orthogonal from the point of view for
> students(!) - _one_ concept should work in different circumstances.

I agree that is desirable, but surely many languages have some sort of 
forward declaration syntax? I know that both the Pascal and C families 
of languages do.



-- 
Steve


More information about the Python-ideas mailing list