[Python-ideas] pep-0484 - Forward references and Didactics - be orthogonal
Terry Reedy
tjreedy at udel.edu
Tue Aug 25 17:15:08 CEST 2015
On 8/24/2015 12:19 AM, 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
As you should know, at least after reading previous responses, making
this work would require one of two major changes to Python class statements.
1. The class name has special (context sensitive) meaning in enclosed
def statements. The compiler would have to compile def statements
differently than it would the same def statements not in a Tree class.
It would then have to patch all methods after the class is created. See
the annoclass function below.
A proposal to make the definition name of a function special within its
definition has already been rejected.
2. Class statements would initially create an empty class bound to the
class name. This could break back compatibility, and would require
cleanup in case of a syntax error in the body. This would be similar to
import statements initially putting a empty module in sys.modules to
support circular imports. This is messy and still bug prone is use.
> what students have to write instead:
>
> #-------------bad workaround----------------------------\
> class Tree:
> def __init__(self, left: 'Tree', right: 'Tree'):
> self.left = left
> self.right = right
You did not say why you think this is bad. Is it a) students have to
type "'"s?, or b) the resulting annotations are strings instead of the
class? The latter can easily be fixed.
---
from types import FunctionType
def annofix(klass):
classname = klass.__name__
for ob in klass.__dict__.values():
if type(ob) is FunctionType:
annotations = ob.__annotations__
for arg, anno in annotations.items():
if anno == classname:
annotations[arg] = klass
return klass
@annofix
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
print(Tree.__init__.__annotations__)
# {'left': <class '__main__.Tree'>, 'right': <class '__main__.Tree'>}
---
An alternative is to use a placeholder object instead of the class name.
This is less direct, not repeating the name of the class throughout the
definition makes it easier to rename the class or copy methods to
another class.
---
class Klass: pass
# An annotation object meaning 'the class this method is defined in'
def annofix2(klass):
for ob in klass.__dict__.values():
if type(ob) is FunctionType:
annotations = ob.__annotations__
for arg, anno in annotations.items():
if anno == Klass:
annotations[arg] = klass
return klass
@annofix2
class Tree2:
def __init__(self, left: Klass, right: Klass):
self.left = left
self.right = right
print(Tree2.__init__.__annotations__)
{'right': <class '__main__.Tree2'>, 'left': <class '__main__.Tree2'>}
--
Terry Jan Reedy
More information about the Python-ideas
mailing list