> In Python, mistyping a property of an object doesn't result in an exception.
Sure it does. It doesn't on assignment, as you can modify the object however you like, but it does have AttributeError for accessing a property that doesn't exist.
Which you can only use compile time - not dynamically. That said I recall the sqlalchemy orm reject fields that it did not recognize. A decent IDE (pycharm) will hilight these for you on the Django orm. Having now used both the Django orm and SQLAlchemy extensively I prefer SQLAlchemy a lot. The Django ORM is usable, but many of its behaviours are odd and I agree that writing more complex queries gets ugly fast, unlike with SQLA where you can write some really hairy sql in a composable manner that makes it just so much more legible.
There is no such distinction between compile time and run time in Python; everything can be done dynamically. Want to use a class with slots computed at runtime? No problem:
>>> def with_slots(**kwargs):
... class SlottedClass(object):
... __slots__ = kwargs.keys()
... def __init__(self, **kwargs):
... for k, v in kwargs.items():
... setattr(self, k, v)
... return SlottedClass(**kwargs)
...
>>> with_slots(foo=1, bar='qux').zork = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'SlottedClass' object has no attribute 'zork'
Of course there are many improvements that could be made to this approach (e.g. not creating a new class for each instance, or setting the __name__ to something meaningful) but I hope it shows that dynamic typing and robust error checking aren't contradictory.
Sure it does. It doesn't on assignment, as you can modify the object however you like, but it does have AttributeError for accessing a property that doesn't exist.