este es un par de años de retraso, pero aquí está la forma en que lo hice:
import abc
class MetaClass(object):
__metaclass__ = abc.ABCMeta
[...]
@classmethod
def __subclasshook__(cls, C):
if C.__abstractmethods__:
print C.__abstractmethods__
return False
else:
return True
Si C
es un intento de la clase de MetaClass
, entonces C.__abstractmethods__
estará vacía solamente si C
implementa todos los métodos abstractos.
Vea aquí los detalles: https://www.python.org/dev/peps/pep-3119/#the-abc-module-an-abc-support-framework (que está bajo "Aplicación" sino una búsqueda de __abstractmethods__
que debe llegar al punto derecha)
Cuando esto ha funcionado para mí:
puedo crear MetaClass
. Luego puedo crear la subclase BaseClass
y MetaClass
para crear SubClass
, que necesita alguna funcionalidad adicional.Pero tengo una necesidad de convertir una instancia de BaseClass
en SubClass
cambiando el atributo __cls__
ya que no soy el propietario de BaseClass
, pero tengo instancias de ello que quiero eliminar.
Sin embargo, si inadecuadamente implemento SubClass
, todavía puedo derribar a menos que utilice la anterior __subclasshook__
y simplemente añadir un cheque subclase cuando lo haga el proceso de derribar (que debería hacer de todos modos ya que quiero sólo para tratar de fundido una clase para padres abajo). Si alguien lo solicita, puedo proporcionarle un MWE para esto.
ETA: Aquí hay un MWE. Creo que lo que estaba sugiriendo antes era incorrecto, por lo que lo siguiente parece hacer lo que pretendo.
El objetivo es poder convertir un objeto BaseClass
en SubClass
y volver. Desde SubClass
hasta BaseClass
es fácil. Pero desde el BaseClass
hasta el SubClass
no tanto. Lo estándar para hacer es actualizar el atributo __class__
pero deja una apertura cuando SubClass
no es realmente una subclase o deriva de una metaclase abstracta, pero no se implementa correctamente.
A continuación, la conversión se realiza en el método convert
que BaseMetaClass
implementa. Sin embargo, en esa lógica, verifico dos cosas. Uno, para convertir a la subclase, compruebo si se trata de una subclase. En segundo lugar, verifico el atributo __abstractmethods__
para ver si está vacío. Si es así, también es una metaclase implementada correctamente. El error conduce a un TypeError. De lo contrario, el objeto se convierte.
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, no puedo simplemente no utilizar interfaces en este proyecto. ¿Por qué? (No estoy siendo sarcástico, genuinamente curioso cuál podría ser el caso de uso) –