Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Tue, Aug 9, 2016 at 12:29 AM Guido van Rossum wrote: > On Mon, Aug 8, 2016 at 2:11 PM, אלעזר wrote: > >> Feels like named parameters are better off being an OrderedDict in the >> first place. >> > > PEP 468. > > Sorry, I should have read this PEP before. > NamedTuple pushes OrderedDict to become kind of builtin. >> > > Why? Having both in the collections module is good enough. > What I meant in becoming builtin is not the accessibility of the name, but the parallel incremental support of namedtuple, OrderedDict and (as I find out) order of **kwargs. In much the same way that class is made out of dict (and keeps one), namedtuple is an OrderedDict (and keeps one). Much like dict has a constructor `dict(a=1, b=2.0)` and a literal `{'a' : 1, 'b' : 2.0}`, OrderedDict has its OrderedDict(a=1, b=2.0) and should have the literal ('a': 1, 'b': 2.0). Replace 1 and 2 with int and float and you get a very natural syntax for a NamedTuple that is the type of a matching OrderedDict. And in my mind, the requirement for type names matches nicely the enforcement of immutability. Continuing this thought, the annotations for the class is actually its structural type. It opens the door for future requests for adding e.g. an operator for structural equivalence. This is all very far from the current language, so it's only thoughts and not really ideas; probably does not belong here. Sorry about that. ~Elazar ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Mon, Aug 8, 2016 at 3:08 PM, אלעזר wrote: > On Tue, Aug 9, 2016 at 12:29 AM Guido van Rossum wrote: > >> On Mon, Aug 8, 2016 at 2:11 PM, אלעזר wrote: >> >>> Feels like named parameters are better off being an OrderedDict in the >>> first place. >>> >> >> PEP 468. >> >> > Sorry, I should have read this PEP before. > No problem, it's fine to participate before reading *everything*! > NamedTuple pushes OrderedDict to become kind of builtin. >>> >> >> Why? Having both in the collections module is good enough. >> > > What I meant in becoming builtin is not the accessibility of the name, but > the parallel incremental support of namedtuple, OrderedDict and (as I find > out) order of **kwargs. > Well, they're all already in the stdlib, although namedtuple is written in Python, OrderedDict in C (recently), and **kwarg is ancient. > In much the same way that class is made out of dict (and keeps one), > namedtuple is an OrderedDict (and keeps one). > I'm not sure if you're talking about the class or the instances. A class instance usually has a dict (unless if it has __slots__ and all its base classes have __slots__). But a namedtuple instance does not have a dict or OrderedDict -- it is a tuple at heart. > Much like dict has a constructor `dict(a=1, b=2.0)` and a literal `{'a' : > 1, 'b' : 2.0}`, OrderedDict has its OrderedDict(a=1, b=2.0) and should > have the literal ('a': 1, 'b': 2.0). > That's debatable at least, and probably there are better solutions. > Replace 1 and 2 with int and float and you get a very natural syntax for a > NamedTuple that is the type of a matching OrderedDict. > And in my mind, the requirement for type names matches nicely the > enforcement of immutability. > > Continuing this thought, the annotations for the class is actually its > structural type. It opens the door for future requests for adding e.g. an > operator for structural equivalence. > > This is all very far from the current language, so it's only thoughts and > not really ideas; probably does not belong here. Sorry about that. > > ~Elazar > -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
אלעזר wrote: class Starship(tuple): damage: int = 0 captain: str = "Kirk" Is an obvious syntax for Starship = NamedTuple('Starship', [('damage', int), ('captain', str)]) But the untyped version of that already has a meaning -- it's a tuple subclass with two extra class attributes that are unrelated to its indexable items. I thought that type annotations weren't meant to change runtime semantics? -- Greg ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Mon, Aug 8, 2016 at 11:17 PM, Greg Ewing wrote: > אלעזר wrote: > >> class Starship(tuple): >> damage: int = 0 captain: str = "Kirk" >> >> Is an obvious syntax for >> Starship = NamedTuple('Starship', [('damage', int), ('captain', str)]) >> > > But the untyped version of that already has a meaning -- > it's a tuple subclass with two extra class attributes > that are unrelated to its indexable items. > > I thought that type annotations weren't meant to change > runtime semantics? Correct, but we can invent a new base class that has these semantics. It's no different from Enum. Anyway, I think this will have to be an add-on to be designed after the basics are done. -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
It's already possible to overload NamedTuple, in a way that will allow the following abuse of notation: @NamedTuple def Starship(damage:int, captain:str): pass The 'def' is unfortunate and potentially confusing (although it *is* a callable definition), and the ": pass" is meaningless. But I think it is clear and concise if you know what NamedTuple is. Introducing new keyword will of course solve both problems (if there's "async def", why not "type def"? :) ). case class Starship(damage:int, captain:str) Possible variations on the decorator theme: "unordered" namedtuple (note the *) @Value def Starship(*, damage:int, captain:str): pass self-describing (another level of notation abuse): @Type def Starship(damage:int, captain:str) -> NamedTuple: pass On Mon, Aug 8, 2016 at 11:25 PM Guido van Rossum wrote: > That's a very interesting idea and one that deserves pursuing (though I > agree it's not a blocker for the PEP I'm hoping to write). I think the next > step is to prototype this -- which can only happen once we have an > implementation of the PEP. Though perhaps you could start by writing a > prototype that works by having the user write the following: > > class Starship(PrototypeNamedTuple): > damage = 0 > captain = "Kirk" > __annotations__ = dict(damage=int, captain=str) > > It could also benefit from PEP 520 (Preserving Class Attribute Definition > Order). > > Who's game? > > --Guido > > On Mon, Aug 8, 2016 at 1:13 PM, אלעזר wrote: > >> class Starship: >>> stats: class Dict[str, int] = {} # Pure class variable >>> damage: class int = 0 # Hybrid class/instance variable >>> captain: str # Pure instance variable >>> >> >> I can't avoid noting that there is an opportunity here to insert >> NamedTuple into the core language. The above example is almost there, >> except it's mutable and without convenient methods. But >> >> class Starship(tuple): >> damage: int = 0 >> captain: str = "Kirk" >> >> Is an obvious syntax for >> >> Starship = NamedTuple('Starship', [('damage', int), ('captain', >> str)]) >> >> Only much more available and intuitive to read, use, and of course - type >> check. >> (Of course, it does mean adding semantics to the declaration syntax in >> general) >> >> I'm not really suggesting to make this change now, but I believe it will >> be done, sooner or later. My brief experience with mypy convinced me that >> it must be the case. The new declaration syntax only makes it easier. >> >> ~Elazar >> >> ___ >> Python-ideas mailing list >> Python-ideas@python.org >> https://mail.python.org/mailman/listinfo/python-ideas >> Code of Conduct: http://python.org/psf/codeofconduct/ >> > > > > -- > --Guido van Rossum (python.org/~guido) > ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Tue, Aug 9, 2016 at 3:47 PM, אלעזר wrote: > It's already possible to overload NamedTuple, in a way that will allow the > following abuse of notation: > > @NamedTuple > def Starship(damage:int, captain:str): pass > > The 'def' is unfortunate and potentially confusing (although it *is* a > callable definition), and the ": pass" is meaningless. But I think it is > clear and concise if you know what NamedTuple is. > > Introducing new keyword will of course solve both problems (if there's > "async def", why not "type def"? :) ). If we're dealing with classes then we should be using the class syntax. There are a number of options here for identifying attributes in a definition and even auto-generating parts of the class (e.g. __init__). Let's look at several (with various objectives): # For the sake of demonstration, we ignore opportunities for type inference. # currently (with comments for type info) class Bee(namedtuple('Bee', 'name ancient_injury managerie')): """can a bee be said to be...""" # name: str # ancient_injury: bool # menagerie: bool def __new__(cls, name='Eric', ancient_injury=False, menagerie=False): return super().__new__(cls, name, ancient_injury, menagerie) def half_a(self): return self.ancient_injury or self.menagerie # using attribute annotations and a decorator (and PEP 520) @as_namedtuple class Bee: """...""" name: str = 'Eric' ancient_injury: bool = False menagerie: bool = False def half_a(self): ... # using attribute annotations and a metaclass (and PEP 520) class Bee(metaclass=NamedtupleMeta): """...""" name: str = 'Eric' ancient_injury: bool = False menagerie: bool = False def half_a(self): ... # using one class decorator and PEP 520 and comments for type info @as_namedtuple class Bee: name = 'Eric' # str ancient_injury = False # bool menagerie = False # bool def half_a(self): ... # using one class decorator and comments for type info @as_namedtuple('name ancient_injury managerie', name='Eric', ancient_injury=False, menagerie=False) class Bee: """...""" # name: str # ancient_injury: bool # menagerie: bool def half_a(self): ... # using one class decorator (and PEP 468) and comments for type info # similar to the original motivation for PEP 468 @as_namedtuple(name='Eric', ancient_injury=False, menagerie=False) class Bee: """...""" # name: str # ancient_injury: bool # menagerie: bool def half_a(self): ... # using a class decorator for each attribute @as_namedtuple('name ancient_injury managerie') @attr('name', str, 'Eric') @attr('ancient_injury', bool, False) @attr('menagerie', bool, False) class Bee: """...""" def half_a(self): ... Those are simple examples and we could certainly come up with others, all using the class syntax. For me, the key is finding the sweet spot between readability/communicating intent and packing too many roles into the class syntax. To be honest, the examples using attribute annotations seem fine to me. Even if you don't need attr type info (which you don't most of the time, particularly with default values), my favorite solution (a class decorator that leverages PEP 520) is still the most readable and in-line with the class syntax, at least for me. :) -eric p.s. The same approaches could also be applied to generating non-namedtuple classes, e.g. SimpleNamespace subclasses. ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
With PEP 520 accepted, would it be possible to iterate over __definition_order__? class PrototypeNamedTuple: cache = {} def __new__(cls, *args): P = PrototypeNamedTuple if cls not in P.cache: P.cache[cls] = typing.NamedTuple(cls.__name__, [(definition, cls.__annotations__[definition]) for definition in cls.__definition_order__] ) return P.cache[cls](*args) On Monday, August 8, 2016 at 5:09:50 PM UTC-4, Guido van Rossum wrote: > > Hm, overlooking the ordering is kind of a big deal for something with > "tuple" in its name. :-) > > Also it feels like it needs a metaclass instead of a cache. > > Maybe from this we can learn though that __anotations__ should be an > OrderedDict? > > On Mon, Aug 8, 2016 at 1:58 PM, אלעזר > > wrote: > >> class PrototypeNamedTuple: >> cache = {} >> def __new__(cls, *args): >> P = PrototypeNamedTuple >> if cls not in P.cache: >> P.cache[cls] = typing.NamedTuple(cls.__name__, >> cls.__annotations__.items()) >> return P.cache[cls](*args) >> >> Works modulo ordering, though I'm not sure that's the right way to do it. >> >> The ordering part of namedtuple is orthogonal to the >> value-type/immutability part. So I would imagine making "Value" for the >> latter, "tuple" for the former, and namedtuple is mixing both (possibly >> given a convenient name, such as PrototypeNamedTuple). "Value" can also >> seen as mixing "Struct" and "Immutable", but that's overdoing it I guess. >> >> ~Elazar >> >> On Mon, Aug 8, 2016 at 11:25 PM Guido van Rossum > > wrote: >> >>> That's a very interesting idea and one that deserves pursuing (though I >>> agree it's not a blocker for the PEP I'm hoping to write). I think the next >>> step is to prototype this -- which can only happen once we have an >>> implementation of the PEP. Though perhaps you could start by writing a >>> prototype that works by having the user write the following: >>> >>> class Starship(PrototypeNamedTuple): >>> damage = 0 >>> captain = "Kirk" >>> __annotations__ = dict(damage=int, captain=str) >>> >>> It could also benefit from PEP 520 (Preserving Class Attribute >>> Definition Order). >>> >>> Who's game? >>> >>> --Guido >>> >>> On Mon, Aug 8, 2016 at 1:13 PM, אלעזר > >>> wrote: >>> class Starship: > stats: class Dict[str, int] = {} # Pure class variable > damage: class int = 0 # Hybrid class/instance variable > captain: str # Pure instance variable > I can't avoid noting that there is an opportunity here to insert NamedTuple into the core language. The above example is almost there, except it's mutable and without convenient methods. But class Starship(tuple): damage: int = 0 captain: str = "Kirk" Is an obvious syntax for Starship = NamedTuple('Starship', [('damage', int), ('captain', str)]) Only much more available and intuitive to read, use, and of course - type check. (Of course, it does mean adding semantics to the declaration syntax in general) I'm not really suggesting to make this change now, but I believe it will be done, sooner or later. My brief experience with mypy convinced me that it must be the case. The new declaration syntax only makes it easier. ~Elazar ___ Python-ideas mailing list python...@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/ >>> >>> >>> >>> -- >>> --Guido van Rossum (python.org/~guido) >>> >> > > > -- > --Guido van Rossum (python.org/~guido) > ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
Sounds like you're thinking with your runtime hat on, not your type checker hat. :-) On Tue, Aug 9, 2016 at 9:46 PM, Neil Girdhar wrote: > With PEP 520 accepted, would it be possible to iterate over > __definition_order__? > > class PrototypeNamedTuple: > cache = {} > def __new__(cls, *args): > P = PrototypeNamedTuple > if cls not in P.cache: > P.cache[cls] = typing.NamedTuple(cls.__name__, > > [(definition, cls.__annotations__[definition]) > for definition in cls.__definition_order__] > > ) > return P.cache[cls](*args) > > On Monday, August 8, 2016 at 5:09:50 PM UTC-4, Guido van Rossum wrote: >> >> Hm, overlooking the ordering is kind of a big deal for something with >> "tuple" in its name. :-) >> >> Also it feels like it needs a metaclass instead of a cache. >> >> Maybe from this we can learn though that __anotations__ should be an >> OrderedDict? >> >> On Mon, Aug 8, 2016 at 1:58 PM, אלעזר wrote: >> >>> class PrototypeNamedTuple: >>> cache = {} >>> def __new__(cls, *args): >>> P = PrototypeNamedTuple >>> if cls not in P.cache: >>> P.cache[cls] = typing.NamedTuple(cls.__name__, >>> cls.__annotations__.items()) >>> return P.cache[cls](*args) >>> >>> Works modulo ordering, though I'm not sure that's the right way to do it. >>> >>> The ordering part of namedtuple is orthogonal to the >>> value-type/immutability part. So I would imagine making "Value" for the >>> latter, "tuple" for the former, and namedtuple is mixing both (possibly >>> given a convenient name, such as PrototypeNamedTuple). "Value" can also >>> seen as mixing "Struct" and "Immutable", but that's overdoing it I guess. >>> >>> ~Elazar >>> >>> On Mon, Aug 8, 2016 at 11:25 PM Guido van Rossum >>> wrote: >>> That's a very interesting idea and one that deserves pursuing (though I agree it's not a blocker for the PEP I'm hoping to write). I think the next step is to prototype this -- which can only happen once we have an implementation of the PEP. Though perhaps you could start by writing a prototype that works by having the user write the following: class Starship(PrototypeNamedTuple): damage = 0 captain = "Kirk" __annotations__ = dict(damage=int, captain=str) It could also benefit from PEP 520 (Preserving Class Attribute Definition Order). Who's game? --Guido On Mon, Aug 8, 2016 at 1:13 PM, אלעזר wrote: > class Starship: >> stats: class Dict[str, int] = {} # Pure class variable >> damage: class int = 0 # Hybrid class/instance variable >> captain: str # Pure instance variable >> > > I can't avoid noting that there is an opportunity here to insert > NamedTuple into the core language. The above example is almost there, > except it's mutable and without convenient methods. But > > class Starship(tuple): > damage: int = 0 > captain: str = "Kirk" > > Is an obvious syntax for > > Starship = NamedTuple('Starship', [('damage', int), ('captain', > str)]) > > Only much more available and intuitive to read, use, and of course - > type check. > (Of course, it does mean adding semantics to the declaration syntax in > general) > > I'm not really suggesting to make this change now, but I believe it > will be done, sooner or later. My brief experience with mypy convinced me > that it must be the case. The new declaration syntax only makes it easier. > > ~Elazar > > ___ > Python-ideas mailing list > python...@python.org > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ > -- --Guido van Rossum (python.org/~guido) >>> >> >> >> -- >> --Guido van Rossum (python.org/~guido) >> > -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Wed, Aug 10, 2016 at 11:56 AM, Guido van Rossum wrote: > Sounds like you're thinking with your runtime hat on, not your type checker > hat. :-) > > On Tue, Aug 9, 2016 at 9:46 PM, Neil Girdhar wrote: >> >> With PEP 520 accepted, would it be possible to iterate over >> __definition_order__? Still, it would be really nice to be able to introspect a class's instance attributes at run-time. A stdlib helper for that would be great, e.g. "inspect.get_inst_attrs(cls)". At one point a few years back I wrote something like that derived from the signature of cls.__init__() and in the spirit of inspect.signature(). It turned out to be quite useful. Relatedly, it may make sense to recommend in PEP 8 that all instance attribute declarations in a class definition be grouped together and to do so right before the methods (right before __new__/__init__?). (...or disallow instance attribute declarations in the stdlib for now.) -eric ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Wed, Aug 10, 2016 at 4:04 PM, Eric Snow wrote: [...] > > Still, it would be really nice to be able to introspect a class's > instance attributes at run-time. A stdlib helper for that would be > great, e.g. "inspect.get_inst_attrs(cls)". At one point a few years > back I wrote something like that derived from the signature of > cls.__init__() and in the spirit of inspect.signature(). It turned > out to be quite useful. > Yes, the proposal will store variable annotations for globals and for classes in __annotations__ (one global, one per class). Just not for local variables. > Relatedly, it may make sense to recommend in PEP 8 that all instance > attribute declarations in a class definition be grouped together and > to do so right before the methods (right before __new__/__init__?). > (...or disallow instance attribute declarations in the stdlib for > now.) > Let's wait until we have some experience with how it's used before updating PEP 8... :-) -- --Guido van Rossum (python.org/~guido) ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
Re: [Python-ideas] Trial balloon: adding variable type declarations in support of PEP 484
On Tue, Aug 9, 2016 at 5:32 PM, Eric Snow wrote: > There are a number of options here for identifying attributes > in a definition and even auto-generating parts of the class (e.g. > __init__). Let's look at several (with various objectives): > > # currently (with comments for type info) > # using attribute annotations and a decorator (and PEP 520) > # using attribute annotations and a metaclass (and PEP 520) > # using one class decorator and PEP 520 and comments for type info > # using one class decorator and comments for type info > # using one class decorator (and PEP 468) and comments for type info > # using a class decorator for each attribute Another approach that I've used in the past (along with a derivative): # using a non-data descriptor @as_namedtuple class Bee: """...""" name = Attr(str, 'Eric', doc='the bee's name') ancient_injury = Attr(bool, False) menagerie = Attr(bool, False) def half_a(self): ... # using a non-data descriptor along with PEP 487 class Bee(Namedtuple): """...""" name = Attr(str, 'Eric', doc='the bee's name') ancient_injury = Attr(bool, False) menagerie = Attr(bool, False) def half_a(self): ... While the descriptor gives you docstrings (a la property), I expect it isn't as static-analysis-friendly as the proposed variable annotations. -eric ___ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/