Я пишу серверное приложение, функция которого вызывается через RPC. Приложение имеет объекты, которые могут взаимодействовать друг с другом.Как объявить, какие методы могут быть применены к объектам
Предположим следующего упрощенного примера:
- Человек может проверить и исправить, и может быть проверен;
- Автомобиль может тормозить и может быть проверен и исправлен.
Непосредственная реализация ¹ (RPC вне области видимости):
class Car(object):
def __init__(self, broken=False):
self.name = 'car'
self.broken = broken
def breaks(self):
self.broken = True
print 'Car broke'
def inspected(self, by):
if by.pro:
if self.broken:
print '{}: It\'s a broken car'.format(by.name)
else:
print '{}: It\'s a working car'.format(by.name)
else:
print '{}: It\'s a car'.format(by.name)
def fixed(self, by):
if not self.broken:
print 'Car is not broken'
else:
self.broken = False
print by.name, 'fixed the car'
class Person(object):
def __init__(self, name, pro=False):
self.name = name
self.pro = pro
def inspect(self, target):
target.inspected(by=self)
def fix(self, target):
target.fixed(by=self)
def inspected(self, by):
if self.pro:
print '{}: {} is a pro'.format(by.name, self.name)
else:
print '{}: {} is not a pro'.format(by.name, self.name)
Создайте несколько объектов:
>>> car = Car()
>>> john = Person('John', pro=True)
>>> bob = Person('Bob', pro=False)
Теперь пользователь может взаимодействовать с ними ²:
>>> car.breaks()
'Car broke'
>>> john.inspect(car)
"John: It's a broken car"
>>> john.fix(car)
'John fixed the car'
>>> bob.inspect(john)
'Bob: John is a pro'
Проблема здесь, если мы позвоним john.fix(bob)
, тогда мы получим AttributeError: 'Person' object has no attribute 'fixed'
.
Итак, что такое хороший и/или «путинский» способ объявить/ограничить, какие методы могут быть применены к каким объектам?
До сих пор я придумал следующие идеи:
- Сделать раздутую базу (реферат) классом, который будет иметь заглушки для всех возможных методов и свойств. Недостатком здесь является то, что по мере роста проекта и добавления новых методов его следует обновлять отдельно; и у всех дочерних классов будет много несвязанных и неиспользуемых вещей. Кроме того, на самом деле проблема не решена.
- Оберните все звонки
try...except
. Не выглядит стабильным и «питоническим», и не решает проблему. - Вручную укажите, какие классы поддерживаются методами. Не поддерживается, поскольку проект растет, и строго не указывает, какие атрибуты должен иметь целевой класс.
- Множественное наследование. Устраняет проблему с # 3, когда при создании нового класса
FixAllRobot
с методом fix мы можем забыть добавить атрибутpro
, необходимый для проверок цели. Минусы:class Person(Inspecter, Fixer, ..., TwentyMoreOneFunctionHolder)
не выглядит заслуживающим доверия и удобочитаемым. И нам все равно нужно проверить, можно ли использовать действие по назначению. - Очень похоже на # 4, но наследуют также целевые классы. Минусы: Наследование ада:
class Person(Inspecter, CanBeInspected, Fixer, ..., FortyMoreOneFunctionHolder)
. Плюсы: Похоже на решение.
Примечание:
О инспектировать и осмотреть (и другие пары действий): Есть некоторые зависимые действия класса как для объекта и субъекта, который должен быть сделан, когда действие называется.
Пока что все объекты того же класса хранятся в словаре классов со своим ключом id. Мета-класс отслеживает, какие классы были созданы. Обычно пользователь контролирует только один объект.Когда пользователь отправляет RPC-запрос (фактически json-rpc), который может выглядеть как
{"jsonrpc": "2.0", "id": 77, "method": "inspect", "params": {"target": "car", "id": 1}}
,target
разрешен как целевой класс иid
как идентификатор экземпляра. Некоторые необязательные параметры также могут быть переданы черезparams
dict.
Sidenote: Я знаю систему сигнальных слотов QT и люблю ее, но я думаю, что это не так.
Sidenote2: Я застрял в Python 2.7
Ваш вопрос не имеет большого смысла. Что может быть ** ограничение ** на самом деле делать иначе, чем возбуждать исключение? Python уже делает правильную вещь, поднимая 'AttributeError', поэтому нет проблем для решения. Все, что вам нужно сделать, это предоставить соответствующую документацию для ваших API. – ekhumoro
Речь идет не о ограничении в использовании, а о проектировании его ядра, как будет очевидно, что нужно делать, чтобы правильно добавлять новые функции, например zope.interface. – mFoxRU
Пример «проблемы», который вы дали, является, в частности, ограничением в использовании - то есть вызовом 'john.fix' с неправильным типом аргумента. – ekhumoro