【发布时间】:2019-11-01 15:45:10
【问题描述】:
我知道这可能是一个糟糕的设计,但我遇到了这样一种情况,我需要即时创建类 Base 的子类 Derived,并使 Derived 的实例失败issubclass(Derived, Base) 或 isinstance(derived_obj, Base) 检查(即返回 False)。
我尝试了很多方法,但都没有成功:
- 在
Derived(https://stackoverflow.com/a/42958013/4909228) 中创建一个名为__class__的属性。这只能用于使检查返回True。 - 覆盖
Base的__instancecheck__和__subclasscheck__方法。这不起作用,因为 CPython 仅在常规检查返回False时调用这些方法。 - 在
__init__期间分配__class__属性。这在 Python 3.6+ 中不再允许。 - 创建
Derived子类object并将其所有属性和方法(包括特殊方法)分配给Base。这不起作用,因为某些方法(例如__init__)不能在不是Base子类的实例上调用。
这可能在 Python 中完成吗?该方法可能是特定于解释器的(代码仅在 CPython 中运行),并且只需要针对 Python 3.6+ 版本。
为了说明此要求的潜在用途,请考虑以下函数:
def map_structure(fn, obj):
if isinstance(obj, list):
return [map_structure(fn, x) for x in obj]
if isinstance(obj, dict):
return {k: map_structure(fn, v) for k, v in obj.items()}
# check whether `obj` is some other collection type
...
# `obj` must be a singleton object, apply `fn` on it
return fn(obj)
此方法泛化map 以处理任意嵌套的结构。但是,在某些情况下我们不想遍历某个嵌套结构,例如:
# `struct` is user-provided structure, we create a list for each element
struct_list = map_structure(lambda x: [x], struct)
# somehow add stuff into the lists
...
# now we want to know how many elements are in each list, so we want to
# prevent `map_structure` from traversing the inner-most lists
struct_len = map_structure(len, struct_list)
如果上述功能可以实现,那么上面可以改成:
pseudo_list = create_fake_subclass(list)
struct_list = map_structure(lambda x: pseudo_list([x]), struct)
# ... and the rest of code should work
【问题讨论】:
-
是的,那是糟糕的设计。您可能应该以某种方式使用组合。
-
您要求的是没有接口继承的实现继承(或者至少,Python 必须最接近接口继承)。这是组合的完美用例。如果您的对象不应该像
list那样迭代,那么它就不是list。干净利落。使它成为一个列表违反了鸭子类型、Liskov 替换和其他可能的原则。 -
您是否尝试过向实现
__instancecheck__的基类添加元类?
标签: python