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.
Minimal example:
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
dataclassses.fields()
- pydantic just uses
.dict()
,.json()
etc. and forbids those names for fields - django uses
model_instance.objects.whatever
which 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,
e.g. :
or ::
. 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!