updated 2010-06-15T09:45:00Z
:
- добавлен пример подхода «классы как экземпляры» и объяснение подхода «экземпляры как классы»;включил и сослался на ответ Алекса Мартелли;
Мне интересно, как реализовать наследование прототипов в Python.Казалось бы, есть два разных подхода к этой проблеме: классы как экземпляры и экземпляры как классы.
Второй метод может показаться более гибким в том смысле, что его можно применять к существующим объектам различных типов,в то время как первый, вероятно, был бы более удобен для типичных случаев использования.
классы как экземпляры
Идея здесь состоит в том, чтобы использовать метакласс, чтобы экземпляры на самом деле были классами, а не объектами.Этот подход выглядит примерно так:
class ClassAsInstance(type):
""" ClassAsInstance(type)\n
>>> c = ClassAsInstance()
>>> c.prop = 6
It's sort of annoying to have to make everything a class method.
>>> c.jef = classmethod(lambda self: self.prop)
>>> c.jef()
6
>>> cc = c()
>>> cc.jef()
6
But it works.
>>> c.prop = 10
>>> cc.jef()
10
>>> c.jef = classmethod(lambda self: self.prop * 2)
>>> cc.jef()
20
"""
def __new__(self):
return type(self.__name__ + " descendant", (self, ), {})
Я действительно не тестировал никаких сложных вещей с этим подходом, поэтому он может иметь ограничения.
экземпляры как классы
При таком подходе идея заключается в использовании конструктора type
для создания классов из объектов.Это иллюстрируется в ответе Алекса Мартелли , хотя пример, который он использует для этого подхода, реализует копирование прототипов, а не позволяет потомкам наследовать более поздние изменения в своих прототипах.
Мой подход заключался в том, чтобы что-то делатькак это:
def createDescendant(obj):
return type(obj.__class__.__name__ + " descendant", (obj.__class__, ), obj.__dict__)()
, который будет работать в виде javascript-y: изменения в данном объекте не будут влиять на его потомков, но изменения в родительском объекте __class__
(как в javascriptprototype
) будет.Я понял, что это потому, что конструктор type
копирует obj.__dict__
, а не ссылается на него в какой-то схеме mro-ish.
Я попытался реализовать улучшенную версию, которая позволила быистинное наследование прототипа, при котором объекты наследуют обновления родительских объектов.Идея заключалась в том, чтобы назначить свойство __dict__
объекта-прототипа тому же свойству вновь созданного класса, которое становится классом объекта-потомка.
Однако это не сработало, так какЯ обнаружил, что __dict__
из type
нельзя назначить;это ограничение также относится к классам, производным от type
.Мне все еще любопытно, можно ли обойти эту проблему, создав объект, который «реализует протокол типов», как это делается с итерациями, последовательностями и т. Д., Но на самом деле не наследуется от type
.Это может создать другие проблемы, такие как те, которые свойственны делегатскому подходу, который Алекс упоминает в первой части своего ответа.
делегирование
Алекс также предлагает третий подход, делегирование, при которомсостояние объекта распространяется на объекты-потомки с помощью магического метода __getattr__
.Опять же, см. Ответ Алекса для примера, а также подробности об ограничениях этого подхода.
Требуется дополнительная информация о практичности этих подходов, а также альтернативные предложения.