Several requests for a specific use case. This is something I have been working 
on just to practice getting a deeper understanding of Python metaprogramming, 
so whether this is something that someone should be trying to do is, of course, 
a matter of opinion.

The idea is to use a class as a singleton collection of choices where every 
choice appears both as an attribute of the class/singleton and as a value/label 
pair when treating it as a sequence.

Usage example:

    class Colors(Choices):
        with choices():
            RED
            GREEN
            BLUE
    
    Colors.RED -> 'Red'
    Colors.GREEN -> 'Green'
    Colors.BLUE -> 'Blue'
    
    tuple(Colors) -> (('RED', 'Red'), ('GREEN', 'Green'), ('BLUE', 'Blue'))

This can be implemented using a mapping object (classdict) returned from the 
metaclass' `__prepare__` class method. The classdict is checked prior to 
checking the surrounding context and takes priority unless its `__getitem__` 
method raises `KeyError`.

The problem in this case is that the classdict generates results dynamically, 
and it has no way of knowing whether a variable reference would have been 
resolved in the surrounding context or not. Therefore, it will ALWAYS take 
precedence, even masking builtins like `print`, `range`, etc. This is 
surprising behavior and generally undesirable.

As I mentioned already, it is possible to work around the problem for builtins 
by having the classdict object specifically test for those, but that doesn't 
solve the problem of masking other variables from the surrounding context. 
Masking those is also surprising behavior.

Steve Jorgensen wrote:
> When using a custom classdict to implement a DSL or use in the body of a class
> definition, from what I can tell by experiment, the classdict takes priority, 
> and the
> surrounding context is only referenced if trying to get an item from the 
> classdict raises
> KeyError.
> There is at least one case in which I would like to do the reverse, and have 
> the
> classdict be secondary to (masked by) any variables defined in the context 
> surrounding the
> execution of the class body.
> I have been able to at least unmask builtins by having the classdict object 
> first try
> to get a result from __builtins__ and then fall back to itself. Also, in the
> actual class body, declaring a variable as global seems to be a workaround
> for global variables, but that has to be done explicitly in the body of any 
> subclass that
> needs it. Also, that does not handle non-globals in its surrounding context.
> I'm not sure what the best way to deal with this would be, but my first 
> thought is to
> maybe have a property that can be set on the metaclass type such as
> `metacls.reluctant_classdict = True` [typo corrected from original post].
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/HATKS2TRWGA2XLDKEGMBSEO7FLLTLQKJ/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to