@classmethod с абстрактным базовым классом - PullRequest
2 голосов
/ 05 марта 2012

У меня есть абстрактный базовый класс и подклассы, определенные следующим образом (Python 2.7):

import abc
import MyDatabaseModule

class _DbObject(object):
    __metaclass__ = abc.ABCMeta

    def _GetObjectType(self):
        raise NotImplementedError, "Please override in the derived class"

    ObjectType = abc.abstractproperty(_GetObjectType, None)

class Entry(_DbObject):
    _objectTypeID = 'ENTRY'

    def _GetObjectType(self):
        return MyDatabaseModule.DoesSomethingWith(self._objectTypeID)

    ObjectType = property(_GetObjectType, None)

Это прекрасно работает, это означает, что базовый класс _DbObject не может быть создан, поскольку он имеет только абстрактную версию метода получения свойства.

try:
    dbObject = _DbObject()
    print "dbObject.ObjectType: " + dbObject.ObjectType
except Exception, err:
    print 'ERROR:', str(err) 

Теперь я могу сделать:

entry = Entry()
print entry.ObjectType

чтобы получить доступ к свойству ObjectType. Однако то, что я хотел бы сделать, это просто:

print Entry.ObjectType

Однако, куда бы я ни пытался вставить @classmethod, я получаю ошибку classmethod object is not callabale.

Ответы [ 2 ]

1 голос
/ 06 марта 2012

Итак, магия в том, как «свойство» работает в Python, реализована с использованием протокола дескриптора - самого свойства, если мощная встроенная функция, предоставляющая дескриптор, который хорошо работает для экземпляров, а не классов, как вы видели.

Итак, вам нужно «свойство класса» - встроенное свойство не может дать вам этого, но протокол дескриптора может.Протокол дескриптора говорит, что всякий раз, когда атрибут извлекается из класса, если это объект с методом __get__, этот метод вызывается с помощью «self, instance, owner» - если он извлекается из класса, вместо этогоиз экземпляра у вас параметр "instance" равен None -

Btw, как указано @Constantinius, это вообще не имеет отношения к ABC, просто вам нужно "свойство класса".

class classproperty(object):
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, owner):
        return self.func(owner)


class Entry(_DbObject):
    _objectTypeID = 'ENTRY'

    def _GetObjectType(cls):
        return MyDatabaseModule.DoesSomethingWith(cls._objectTypeID)
    ObjectType = classproperty(_GetObjectType, None)
1 голос
/ 05 марта 2012

Проблема не в вашем ABC, а в простом факте, что в python нет такого понятия, как classproperty, вы должны создать его самостоятельно.На самом деле есть хороший вопрос + ответ на SO об этом.На самом деле это не должно быть проблемой при использовании его с вашей ABC.

...