questo è un paio di anni di ritardo, ma qui è il modo in cui l'ho fatto:
import abc
class MetaClass(object):
__metaclass__ = abc.ABCMeta
[...]
@classmethod
def __subclasshook__(cls, C):
if C.__abstractmethods__:
print C.__abstractmethods__
return False
else:
return True
Se C
è un tentativo di classe di MetaClass
, allora C.__abstractmethods__
sarà solo vuoto se C
implementa tutti i metodi astratti.
Vedi qui per i dettagli: https://www.python.org/dev/peps/pep-3119/#the-abc-module-an-abc-support-framework (è sotto "Implementazione", ma una ricerca di __abstractmethods__
dovrebbe arrivare al punto giusto)
Qualora sia presente funzionato per me:
posso creare MetaClass
. Posso quindi creare sottoclasse BaseClass
e MetaClass
per creare SubClass
che richiede alcune funzionalità aggiuntive.Ma ho bisogno di trasmettere un'istanza di a SubClass
modificando l'attributo __cls__
poiché non possiedo BaseClass
ma ottengo istanze di esso che voglio eseguire il cast down.
Tuttavia, se impropriamente implementare SubClass
, posso ancora gettato giù a meno che io uso il sopra __subclasshook__
e basta aggiungere un controllo sottoclasse quando faccio il processo gettato giù (che devo fare comunque perché voglio solo cercare di lanciare una classe genitore verso il basso). Se qualcuno richiede, posso fornire un MWE per questo.
ETA: ecco un MWE. Penso che ciò che stavo suggerendo prima fosse scorretto, quindi sembra che ciò che segue abbia fatto ciò che intendevo.
L'obiettivo è essere in grado di convertire un oggetto in SubClass
e viceversa. Da SubClass
a BaseClass
è facile. Ma da BaseClass
a SubClass
non così tanto. La cosa standard da fare è aggiornare l'attributo __class__
ma lascia un'apertura quando SubClass
non è in realtà una sottoclasse o deriva da una meta class astratta ma non è implementata correttamente.
Sotto, la conversione viene eseguita nel metodo convert
che BaseMetaClass
implementa. Tuttavia, in questa logica, controllo due cose. Uno, per convertirlo in sottoclasse, controllo se è effettivamente una sottoclasse. Secondo, controllo l'attributo __abstractmethods__
per vedere se è vuoto. Se lo è, allora è anche un metaclasse correttamente implementato. L'errore porta a un errore TypeError. Altrimenti l'oggetto viene convertito.
import abc
class BaseMetaClass(object):
__metaclass__ = abc.ABCMeta
@classmethod
@abc.abstractmethod
def convert(cls, obj):
if issubclass(cls, type(obj)):
if cls.__abstractmethods__:
msg = (
'{0} not a proper subclass of BaseMetaClass: '
'missing method(s)\n\t'
).format(
cls.__name__
)
mthd_list = ',\n\t'.join(
map(
lambda s: cls.__name__ + '.' + s,
sorted(cls.__abstractmethods__)
)
)
raise TypeError(msg + mthd_list)
else:
obj.__class__ = cls
return obj
else:
msg = '{0} not subclass of {1}'.format(
cls.__name__,
type(obj).__name__
)
raise TypeError(msg)
@abc.abstractmethod
def abstractmethod(self):
return
class BaseClass(object):
def __init__(self, x):
self.x = x
def __str__(self):
s0 = "BaseClass:\n"
s1 = "x: {0}".format(self.x)
return s0 + s1
class AnotherBaseClass(object):
def __init__(self, z):
self.z = z
def __str__(self):
s0 = "AnotherBaseClass:\n"
s1 = "z: {0}".format(self.z)
return s0 + s1
class GoodSubClass(BaseMetaClass, BaseClass):
def __init__(self, x, y):
super(GoodSubClass, self).__init__(x)
self.y = y
@classmethod
def convert(cls, obj, y):
super(GoodSubClass, cls).convert(obj)
obj.y = y
def to_base(self):
return BaseClass(self.x)
def abstractmethod(self):
print "This is the abstract method"
def __str__(self):
s0 = "SubClass:\n"
s1 = "x: {0}\n".format(self.x)
s2 = "y: {0}".format(self.y)
return s0 + s1 + s2
class BadSubClass(BaseMetaClass, BaseClass):
def __init__(self, x, y):
super(BadSubClass, self).__init__(x)
self.y = y
@classmethod
def convert(cls, obj, y):
super(BadSubClass, cls).convert(obj)
obj.y = y
def __str__(self):
s0 = "SubClass:\n"
s1 = "x: {0}\n".format(self.x)
s2 = "y: {0}".format(self.y)
return s0 + s1 + s2
base1 = BaseClass(1)
print "BaseClass instance"
print base1
print
GoodSubClass.convert(base1, 2)
print "Successfully casting BaseClass to GoodSubClass"
print base1
print
print "Cannot cast BaseClass to BadSubClass"
base1 = BaseClass(1)
try:
BadSubClass.convert(base1, 2)
except TypeError as e:
print "TypeError: {0}".format(e.message)
print
print "Cannot cast AnotherBaseCelass to GoodSubClass"
anotherbase = AnotherBaseClass(5)
try:
GoodSubClass.convert(anotherbase, 2)
except TypeError as e:
print "TypeError: {0}".format(e.message)
print
print "Cannot cast AnotherBaseCelass to BadSubClass"
anotherbase = AnotherBaseClass(5)
try:
BadSubClass.convert(anotherbase, 2)
except TypeError as e:
print "TypeError: {0}".format(e.message)
print
# BaseClass instance
# BaseClass:
# x: 1
# Successfully casting BaseClass to GoodSubClass
# SubClass:
# x: 1
# y: 2
# Cannot cast BaseClass to BadSubClass
# TypeError: BadSubClass not a proper subclass of BaseMetaClass: missing method(s)
# BadSubClass.abstractmethod
# Cannot cast AnotherBaseCelass to GoodSubClass
# TypeError: GoodSubClass not subclass of AnotherBaseClass
# Cannot cast AnotherBaseCelass to BadSubClass
# TypeError: BadSubClass not subclass of AnotherBaseClass
'No, non posso semplicemente non utilizzare le interfacce in questo progetto. Perché? (Non sono sarcastico, sinceramente curioso di sapere quale potrebbe essere il caso d'uso) –