[Python-Dev] PEP 487: Simpler customization of class creation
nikita at nemkin.ru
Mon Jun 20 14:31:54 EDT 2016
On Mon, Jun 20, 2016 at 9:48 PM, Guido van Rossum <guido at python.org> wrote:
> On Thu, Jun 16, 2016 at 3:24 PM, Nikita Nemkin <nikita at nemkin.ru> wrote:
>> I didin't know that PyPy has actually implemented packed ordered dicts!
>> This old idea by Raymond Hettinger is vastly superior to
>> __definition_order__ duct tape (now that PyPy has validated it).
>> It also gives kwarg order for free, which is important in many
>> metaprogramming scenarios.
>> Not to mention memory usage reduction and dict operations speedup...
> That idea is only vastly superior if we want to force all other Python
> implementations to also have an order-preserving dict with the same
> semantics and API.
Right. Ordered by default is a very serious implementation constraint.
It's only superior in a sense that it completely subsumes/obsoletes
> I'd like to hear more about your metaprogramming scenarios -- often such
> things end up being code the author is ashamed of. Perhaps they should stay
> in the shadows? Or could we do something to make it so you won't have to be
> ashamed of it?
What I meant is embedding declarative domain-specific languages
in Python. Examples of such languages include SQL table
definitions, binary data definitions (in-memory C structs or
wire protocol), GUI definitions (look up enaml for an interesting
example), etc. etc. DSLs are a well defined field and the point
of embedding into Python is to implement in Python and to
empower DSL with Python constructs for generation and logic.
Basic blocks for a declarative language are lists and "objects" -
groups of ordered, named fields.
Representing lists is easy and elegant, commas make a tuple
and  makes a list.
It's when trying to represent "objects" the issues arise.
Literal dicts are "ugly" (for DSL purposes) and unordered.
Lists of 2-tuples are even uglier. Py3 gave us __prepare__ for
ordered class bodies, and this became a first valid option.
For example, SQL table:
field1 = Type1(options...)
field2 = Type2()
Unfortunately, class declarations don't look good when nested,
and nesting is a common thing.
caption = "Window"
label1 = Label(...)
text1 = Text(...)
You get the idea.
Another option for expressing "objects" are function calls with kwargs:
packet = Struct(type=uint8,
Looks reasonably clean, but more often than not requires kwargs
to be ordered. THIS is the scenario I was talking about.
Function attributes also have a role, but being
attached to function definitions, their scope is somewhat limited.
Of course, all of the above is largely theoretical, for two basic
1) Python syntax/runtime is too rigid for a declarative DSL.
(Specifically, _embedded_ DSL. The syntax alone can be re-used
with ast.parse, but it's a different scenario.)
2) DSLs in general are grossly unpythonic, hiding loads of magic
and unfamiliar semantics behind what looks like a normal Python.
It's not something to be ashamed of, but the benefit
rarely justifies the (maintenance) cost.
To be clear: I'm NOT advocating for ordered kwargs. Embedding
DSLs into Python is generally a bad idea.
PS. __prepare__ enables many DSL tricks. In fact, it's difficult to
imagine a use case that's not related to some attempt at DSL.
Keyword-only args also help: ordered part of the definition can go
into *args, while attributes/options are kw-only args.
More information about the Python-Dev