đây là một vài năm cuối nhưng đây là cách tôi đã làm nó:
import abc
class MetaClass(object):
__metaclass__ = abc.ABCMeta
[...]
@classmethod
def __subclasshook__(cls, C):
if C.__abstractmethods__:
print C.__abstractmethods__
return False
else:
return True
Nếu C
là một lớp cố gắng của MetaClass
, sau đó C.__abstractmethods__
sẽ trống chỉ nếu C
thực hiện tất cả các phương pháp trừu tượng.
Xem ở đây để biết chi tiết: https://www.python.org/dev/peps/pep-3119/#the-abc-module-an-abc-support-framework (đó là dưới "Thực hiện" nhưng một tìm kiếm cho __abstractmethods__
nên giúp bạn có được những đoạn phải)
đâu này đã làm việc cho tôi:
tôi có thể tạo MetaClass
. Sau đó tôi có thể phân loại BaseClass
và MetaClass
để tạo SubClass
cần một số chức năng bổ sung.Nhưng tôi có một nhu cầu để đúc một thể hiện của BaseClass
xuống đến SubClass
bằng cách thay đổi các thuộc tính __cls__
vì tôi không sở hữu BaseClass
nhưng tôi nhận được trường hợp của nó mà tôi muốn bỏ xuống.
Tuy nhiên, nếu tôi triển khai không đúng SubClass
, tôi vẫn có thể bỏ qua trừ khi tôi sử dụng ở trên __subclasshook__
và chỉ thêm một kiểm tra lớp con khi tôi thực hiện quy trình truyền xuống (tôi nên làm như vậy vì tôi chỉ muốn thử truyền một lớp cha xuống). Nếu ai đó yêu cầu, tôi có thể cung cấp một MWE cho việc này.
ETA: Đây là MWE. Tôi nghĩ rằng những gì tôi đã đề xuất trước đây là không chính xác vì vậy sau đây xuất hiện để làm những gì tôi dự định.
Mục đích là để có thể chuyển đổi đối tượng BaseClass
thành SubClass
và ngược lại. Từ SubClass
đến BaseClass
thật dễ dàng. Nhưng từ BaseClass
đến SubClass
không quá nhiều. Điều tiêu chuẩn cần làm là cập nhật thuộc tính __class__
nhưng để lại mở khi SubClass
không thực sự là phân lớp hoặc xuất phát từ lớp meta trừu tượng nhưng không được triển khai đúng cách.
Dưới đây, việc chuyển đổi được thực hiện theo phương pháp convert
mà thực hiện BaseMetaClass
. Tuy nhiên, trong logic đó, tôi kiểm tra hai thứ. Một, để chuyển đổi sang lớp con, tôi kiểm tra xem nó có thực sự là một phân lớp hay không. Thứ hai, tôi kiểm tra thuộc tính __abstractmethods__
để xem thuộc tính có trống không. Nếu có, thì nó cũng là một metaclass được thực hiện đúng cách. Thất bại dẫn đến một TypeError. Nếu không thì đối tượng được chuyển đổi.
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
'Không, tôi không thể đơn giản không sử dụng giao diện trong dự án này.' Tại sao? (Tôi không phải là châm biếm, thực sự tò mò về trường hợp sử dụng có thể là gì) –