Python 多重继承依赖项-基需要AbstractBaseClass
问题的要点是:如果继承多个类,我如何保证如果继承了一个类,子对象也会使用互补抽象基类(abc) 我一直在玩弄pythons继承,试图看看我能做什么样的酷东西,我想出了这个模式,这很有趣 我一直在尝试使用它,使实现和测试与缓存接口的对象变得更容易。我有三个模块:Python 多重继承依赖项-基需要AbstractBaseClass,python,multiple-inheritance,abstract-base-class,Python,Multiple Inheritance,Abstract Base Class,问题的要点是:如果继承多个类,我如何保证如果继承了一个类,子对象也会使用互补抽象基类(abc) 我一直在玩弄pythons继承,试图看看我能做什么样的酷东西,我想出了这个模式,这很有趣 我一直在尝试使用它,使实现和测试与缓存接口的对象变得更容易。我有三个模块: ICachable.py 可缓存的.py 某个班级 ICacheable.py import abc class ICacheable(abc.ABC): @property @abc.abstractmethod
- ICachable.py
- 可缓存的.py
- 某个班级
import abc
class ICacheable(abc.ABC):
@property
@abc.abstractmethod
def CacheItemIns(self):
return self.__CacheItemIns
@CacheItemIns.setter
@abc.abstractmethod
def CacheItemIns(self, value):
self.__CacheItemIns = value
return
@abc.abstractmethod
def Load(self):
"""docstring"""
return
@abc.abstractmethod
def _deserializeCacheItem(self):
"""docstring"""
return
@abc.abstractmethod
def _deserializeNonCacheItem(self):
"""docstring"""
return
class Cacheable:
def _getFromCache(self, itemName, cacheType,
cachePath=None):
"""docstring"""
kwargs = {"itemName" : itemName,
"cacheType" : cacheType,
"cachePath" : cachePath}
lstSearchResult = CacheManager.SearchCache(**kwargs)
if lstSearchResult[0]:
self.CacheItemIns = lstSearchResult[1]
self._deserializeCacheItem()
else:
cacheItem = CacheManager.NewItem(**kwargs)
self.CacheItemIns = cacheItem
self._deserializeNonCacheItem()
return
可缓存的.py
import abc
class ICacheable(abc.ABC):
@property
@abc.abstractmethod
def CacheItemIns(self):
return self.__CacheItemIns
@CacheItemIns.setter
@abc.abstractmethod
def CacheItemIns(self, value):
self.__CacheItemIns = value
return
@abc.abstractmethod
def Load(self):
"""docstring"""
return
@abc.abstractmethod
def _deserializeCacheItem(self):
"""docstring"""
return
@abc.abstractmethod
def _deserializeNonCacheItem(self):
"""docstring"""
return
class Cacheable:
def _getFromCache(self, itemName, cacheType,
cachePath=None):
"""docstring"""
kwargs = {"itemName" : itemName,
"cacheType" : cacheType,
"cachePath" : cachePath}
lstSearchResult = CacheManager.SearchCache(**kwargs)
if lstSearchResult[0]:
self.CacheItemIns = lstSearchResult[1]
self._deserializeCacheItem()
else:
cacheItem = CacheManager.NewItem(**kwargs)
self.CacheItemIns = cacheItem
self._deserializeNonCacheItem()
return
某个班级
import ICacheable
import Cacheable
class SomeClass(Cacheable, ICacheable):
__valueFromCache1:str = ""
__valueFromCache2:str = ""
__CacheItemIns:dict = {}
@property
def CacheItemIns(self):
return self.__CacheItemIns
@CacheItemIns.setter
def CacheItemIns(self, value):
self.__CacheItemIns = value
return
def __init__(self, itemName, cacheType):
#Call Method from Cacheable
self.__valueFromCache1
self.__valueFromCache2
self.__getItemFromCache(itemName, cacheType)
return
def _deserializeCacheItem(self):
"""docstring"""
self.__valueFromCache1 = self.CacheItemIns["val1"]
self.__valueFromCache2 = self.CacheItemIns["val2"]
return
def _deserializeNonCacheItem(self):
"""docstring"""
self.__valueFromCache1 = #some external function
self.__valueFromCache2 = #some external function
return
因此,这个例子是可行的,但可怕的是,无法保证继承
Cacheable
的类也继承ICacheable
。这似乎是一个设计缺陷,因为可缓存
本身是无用的。然而,用它从我的子类/子类中抽象事物的能力是强大的。有没有办法保证Cacheable对ICacheable的依赖性?如果您明确不希望继承,可以将类注册为ABC的虚拟子类
@ICacheable.register
class Cacheable:
...
这意味着Cacheable
的每个子类也会自动视为ICacheable
的子类。如果您有一个高效的实现,而该实现会因为要遍历非功能性抽象基类(例如,对于super
调用)而减慢速度,那么这将非常有用
然而,ABC不仅仅是接口,从它们继承也不错。事实上,ABC的部分好处在于它强制子类来实现所有抽象方法。中间帮助器类(如Cacheable
)在从未实例化时不实现所有方法是可以的。但是,实例化的任何非虚拟子类都必须是具体的
>>> class FailClass(Cacheable, ICacheable):
... ...
...
>>> FailClass()
TypeError: Can't instantiate abstract class FailClass with abstract methods CacheItemIns, Load, _deserializeCacheItem, _deserializeNonCacheItem
请注意,如果
- 始终将子类设置为
class AnyClass(可缓存、可缓存):
- 从不实例化可缓存的
ICacheable
继承的Cacheable
。方法分辨率顺序(即继承菱形)相同
>>> AnyClass.__mro__
(__main__. AnyClass, __main__.Cacheable, __main__.ICacheable, abc.ABC, object)
使
Cacheable
成为ICacheable
@mypetlion的一个子类,让我们进入“如何知道哪些方法需要在Cacheable中重写”的时代。它现在实际上是在实现iCachable,而不是提供帮助实现的Cachable。突然之间,我们又回到了与C#和Java相同的问题上,但是没有一半的继承工具(比如声明类作用域的能力)。至少我是这么想的。为什么要指定私有方法,例如\u反序列化onCacheItem
,作为接口的一部分?这些内容不应该是可见的,因此您实际上是在实施一个实现细节。还要注意的是,\uuu CacheItemIns
是一个类私有成员,其名称会被破坏-ICacheable
不能使用它,除非它声明它。看,对于虚拟子类,这是否意味着Cacheable必须实现ICacheable?这里的部分想法是Cacheable不实现ICacheable。Cacheable
只需要完全实现ICacheable
,如果Cacheable
是一个具体的子类并被实例化。虚拟子类不继承任何内容,包括ABC一致性检查。一个具体但不完整的子类只是一个更专业但仍然是抽象的基类。Cacheable不总是作为构造函数链的一部分被实例化吗?Python中的类型不是这样工作的。如果实例化SomeClass
,则会实例化并初始化类型为SomeClass
的对象-其MRO仅包含可缓存的
。现在,这个实例可以选择像可缓存的实例一样初始化自己(通过Cacheable.\uuuuu init\uuuu
或super()。\uuuuu init\uuuuu
),但在这期间它仍然是SomeClass
类型。这意味着它具有满足ICacheable
所需的所有具体方法。有趣的是,我今天将讨论这个问题。如果我能把这篇文章做好,我会回来给它做正确的标记。谢谢