melobot.typ.cls 源代码
import inspect
from abc import ABCMeta
from typing_extensions import Any, Callable, cast
from .base import T
[文档]
class BetterABCMeta(ABCMeta):
"""更好的抽象元类,兼容 `ABCMeta` 的所有功能,但是额外支持 :func:`abstractattr`"""
class DummyAttribute: ...
def __call__(cls: type[T], *args: Any, **kwargs: Any) -> T:
instance = ABCMeta.__call__(cls, *args, **kwargs)
lack_attrs = set()
for name in dir(instance):
try:
attr = getattr(instance, name)
except Exception:
if not isinstance(getattr(instance.__class__, name), property):
raise
if getattr(attr, "__is_abstract_attribute__", False):
lack_attrs.add(name)
if inspect.iscoroutine(attr):
attr.close()
if lack_attrs:
raise NotImplementedError(
"Can't instantiate abstract class {} with"
" abstract attributes: {}".format(cls.__name__, ", ".join(lack_attrs))
)
return cast(T, instance)
[文档]
class BetterABC(metaclass=BetterABCMeta):
"""更好的抽象类,兼容 `ABC` 的所有功能,但是额外支持 :func:`abstractattr`"""
__slots__ = ()
[文档]
class SingletonMeta(type):
"""单例元类
相比单例装饰器,可以自动保证所有子类都为单例
"""
__instances__: dict[type, Any] = {}
def __call__(cls: type[T], *args: Any, **kwargs: Any) -> T:
if cls not in SingletonMeta.__instances__:
SingletonMeta.__instances__[cls] = cast(
T, super(SingletonMeta, cls).__call__(*args, **kwargs) # type: ignore[misc]
)
return cast(T, SingletonMeta.__instances__[cls])
[文档]
class SingletonBetterABCMeta(BetterABCMeta):
"""单例抽象元类
相比普通的抽象元类,还可以自动保证所有子类都为单例
"""
__instances__: dict[type, Any] = {}
def __call__(cls: type[T], *args: Any, **kwargs: Any) -> T:
mcls = SingletonBetterABCMeta
if cls not in mcls.__instances__:
mcls.__instances__[cls] = BetterABCMeta.__call__(cls, *args, **kwargs)
return cast(T, mcls.__instances__[cls])
[文档]
def abstractattr(obj: Callable[[Any], T] | None = None) -> T:
"""抽象属性
与 `abstractproperty` 相比更灵活,`abstractattr` 不关心你以何种形式定义属性。只要子类在实例化后,该属性存在,即认为合法。
但注意它必须与 :class:`BetterABC` 或 :class:`BetterABCMeta` 或 :class:`.SingletonBetterABCMeta` 配合使用
这意味着可以在类层级、实例层级定义属性,或使用 `property` 定义属性:
.. code:: python
class A(BetterABC):
foo: int = abstractattr() # 声明为抽象属性
# 或者使用装饰器的形式声明,这与上面是等价的
@abstractattr
def bar(self) -> int: ...
# 以下实现都是合法的:
class B(A):
foo = 2
bar = 4
class C(A):
foo = 3
def __init__(self) -> None:
self.bar = 5
class D(A):
def __init__(self) -> None:
self.foo = 8
@property
def bar(self) -> int:
return self.foo + 10
"""
_obj = cast(Any, obj)
if obj is None:
_obj = BetterABCMeta.DummyAttribute()
setattr(_obj, "__is_abstract_attribute__", True)
return cast(T, _obj)