Да, конечно, в этой ситуации лучше бы использовать exec. Это был просто пример, показывающий возможнности конструкции class. И, естественно, прежде чем так писать в реальной жизни стоит очень и очень сильно подумать, а действительно ли оно надо.
«New-style classes were introduced in Python 2.2 to unify classes and types. A new-style class is neither more nor less than a user-defined type. If x is an instance of a new-style class, then type(x) is typically the same as x.__class__ (although this is not guaranteed — a new-style class instance is permitted to override the value returned for x.__class__).»
Потому что реально за присвоение специальных атрибутов отвечает класс, и ментальная модель «класс можно поменять» несколько отличается от того, как это все происходит на самом деле. На самом деле это вот так:
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"can't delete __class__ attribute");
return -1;
}
if (!PyType_Check(value)) {
PyErr_Format(PyExc_TypeError,
"__class__ must be set to new-style class, not '%s' object",
Py_TYPE(value)->tp_name);
return -1;
}
newto = (PyTypeObject *)value;
if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
!(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))
{
PyErr_Format(PyExc_TypeError,
"__class__ assignment: only for heap types");
return -1;
}
if (compatible_for_assignment(newto, oldto, "__class__")) {
Py_INCREF(newto);
Py_TYPE(self) = newto;
Py_DECREF(oldto);
return 0;
}
else {
return -1;
}
}
Прежде чем как-то поменять __class__ происходит несколько проверок. И если старый класс и новый более или менее «однотипны», то все — ок, иначе — будет ругаться.
К сожалению, руки не дошли до многих вкусных вещей: дескрипторов, наследования — алгоритм C3, абстрактных базовых классов, слотов, отличия __getattr__ и __getattribute__ и прочее.
Опять же лисп совсем разный бывает. CL — не функциональный, а вот Scheme, clojure — да, все из себя функциональные.
> а такие вещи которые возможны в функциональных ЯП не возможны в структурных
Это весьма спорно, учитывая еще к тому же и аргумент от тьюринг полноты.
Нет.
> Поправь «c() <=> type©.__call__(с)» на «c() <=> type(с).__call__(с)».
Спс. Поправил.
>>> Dict = {}.__class__
>>> class Foo(Dict):
... pass
...
>>> f = Foo()
>>> f['herp']='derp'
>>> f
{'herp': 'derp'}
>>>
«New-style classes were introduced in Python 2.2 to unify classes and types. A new-style class is neither more nor less than a user-defined type. If x is an instance of a new-style class, then type(x) is typically the same as x.__class__ (although this is not guaranteed — a new-style class instance is permitted to override the value returned for x.__class__).»
Ну собственно, чтобы сделать типы похожими на классы, а точнее все свести к одному, и были введены new-style classes, для которых это так и есть.
static int
object_set_class(PyObject *self, PyObject *value, void *closure)
{
PyTypeObject *oldto = Py_TYPE(self);
PyTypeObject *newto;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError,
"can't delete __class__ attribute");
return -1;
}
if (!PyType_Check(value)) {
PyErr_Format(PyExc_TypeError,
"__class__ must be set to new-style class, not '%s' object",
Py_TYPE(value)->tp_name);
return -1;
}
newto = (PyTypeObject *)value;
if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
!(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))
{
PyErr_Format(PyExc_TypeError,
"__class__ assignment: only for heap types");
return -1;
}
if (compatible_for_assignment(newto, oldto, "__class__")) {
Py_INCREF(newto);
Py_TYPE(self) = newto;
Py_DECREF(oldto);
return 0;
}
else {
return -1;
}
}
Прежде чем как-то поменять __class__ происходит несколько проверок. И если старый класс и новый более или менее «однотипны», то все — ок, иначе — будет ругаться.