namedtuples, dataclasses, pydantic, django models, SQLAlchemy and many others suffer from a problem:
How do you allow arbitrary field names without the risk that they clash with library provided properties and functions.
from whatever_library import orm_decorator @orm_decorator class Fisherman: name: str seas: List[str] fisherman = Fisherman(name='Fred', seas=['atlantic', 'pacific']) print(fisherman.seas) -> ['atlantic', 'pacific'] # here "fields" is a method which returns the field names print(fisherman.fields()) -> ['name', 'seas'] @orm_decorator class Farmer: name: str fields: List[str] # !!! this breaks, either now or later
This is not a new problem, it’s been around for years. Existing libraries deal with it with
a variety of hacks:
- namedtuples provides a
._dict()method - uses private variables
- dataclasses provides
- pydantic just uses
.json()etc. and forbids those names for fields
- django uses
model_instance.objects.whateverwhich is slightly different (table vs. row) but is used for a similar purpose
All these approaches have significant drawbacks.
I therefore propose that a new character is allowed at the start of an identifier
(2. Lexical analysis — Python 3.10.3 documentation) which is available
on most keyboards, and by convention that character is used in field names
within ORM/dataclass like contexts.
Two obvious options are “@” or “$”.
The above example would therefore become:
from whatever_library import orm_decorator @orm_decorator class Farmer: $name: str $fields: List[str] # this works fine farmer = Farmer(name='Jones', fields=['meadow', 'highlands']) print(farmer.$fields) -> ['meadow', 'highlands']
The other potiential solution to this would be to create a new “accessor” method,
::. So fields could be accessed via
farmer::fields while the method is
still available via
farmer.fields (or visa versa).
IMHO this would be more confusing and might require a bigger language change and is
therefore a less good solution.
Here’s a discussion about potential workarounds in pydantic: pydantic#1001 (sorry, I can only include 2 links in this post as I’m a new user)
What do people think?
Is there another option I haven’t through about?
Since we’re near April 1st, there’s also the idea of using a random, rarely used unicode character (https://twitter.com/samuel_colvin/status/1472283581087158273):
from whatever_library import orm_decorator @orm_decorator class Farmer: ᚑname: str ᚑfields: List[str] # this works fine farmer = Farmer(name='Jones', fields=['meadow', 'highlands']) print(farmer.ᚑfields) -> ['meadow', 'highlands']
This already works, but don’t do it!