如何将实例属性标记为在基类中未实现? (与this问题不同,该问题讨论了将 class 属性标记为未实现,但也许我不能正确理解基类...)
例如我想要类似的东西
const presets =
[ { id: 0
, name: "videoFormats"
, content: ["(avi|mkv|mov|mp4|mpg|wmv)"]
, hidden: true
, include: ["imageFormats"]
}
, { id: 1
, name: "audioFormats"
, content: ["(ac3|flac|m4a|mp3|ogg|wav|wma)"]
, hidden: true
, include: ["imageFormats"]
}
, { id: 2
, name: "imageFormats"
, content: ["(bmp|gif|jpg|jpeg|png|psd|tif|tiff)"]
, hidden: true
}
, { id: 3
, name: "media"
, title: "Media"
, include: ["videoFormats", "audioFormats"]
, hidden: false
}
]
const fromArray = (a = []) =>
a.reduce((r,x) => r.set(x.name, x), new Map)
const traverse = function* (t = new Map, name = "") {
if (!t.has(name)) return
yield* traverse1(t, t.get(name))
}
const traverse1 = function* (t = new Map, preset = {}) {
yield preset
for (const i of preset.include || [])
yield* traverse(t, i)
}
const getIncludes = (t = new Map, name = "") =>
{ const r = new Set
for (const p of traverse(t, name))
if (r.has(p.name) || p.name === name)
continue
else
r.add(p.name)
return Array.from(r)
}
const tree =
fromArray(presets)
console.log(getIncludes(tree, "media"))
// [ "videoFormats", "imageFormats", "audioFormats" ]
console.log(getIncludes(tree, "audioFormats"))
// [ "imageFormats" ]
console.log(getIncludes(tree, "imageFormats"))
// []
或者,是否有更好的方法来强制class Base():
def __init__(self):
self.x = NotImplemented
class GoodSub(Base):
def __init__(self, x):
super().__init__()
self.x = x #good
class BadSub(Base):
def __init__(self):
super().__init__()
#forgot to set self.x
good = GoodSub(5)
bad = BadSub(-1)
good.x #returns 5
bad.x #throws error because x not implemented
的所有子类在初始化时设置Base
属性?
答案 0 :(得分:2)
我会考虑将x
设为财产。
class Base():
def __init__(self):
self.__x = None
self.__x_is_set = False
@property
def x(self):
if not self.__x_is_set:
raise NotImplementedError('Descendents from Base must set x')
else:
return self.__x
@x.setter
def x(self, value):
self.__x = value
self.__x_is_set = True
class GoodSub(Base):
def __init__(self):
super().__init__()
self.x = 5
class BadSub(Base):
def __init__(self):
super().__init__()
pass
class AlsoBad(Base):
def __init__(self):
super().__init__()
self.__x = 5 # sets the attribute, but not through the property
>>> g, a, b = GoodSub(), BadSub(), AlsoBad()
>>> g.x
5
>>> a.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in x
NotImplementedError: Descendents from Base must set x
>>> b.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in x
NotImplementedError: Descendents from Base must set x
答案 1 :(得分:2)
具有类装饰器和描述符(__get__
方法)的一种解决方案:
def abstract_variables(*args):
class av:
def __init__(self, error_message):
self.error_message = error_message
def __get__(self, *args, **kwargs):
raise NotImplementedError(self.error_message)
def f(klass):
for arg in args:
setattr(klass, arg, av('Descendants must set variable `{}`'.format(arg)))
return klass
return f
@abstract_variables('x', 'y')
class Base:
def __init__(self):
pass
class Derived(Base):
x = 10
b = Base()
d = Derived()
print(d.x) # prints 10
print(d.y) # raises NotImplementedError
打印:
10
Traceback (most recent call last):
File "main.py", line 28, in <module>
print(d.y)
File "main.py", line 7, in __get__
raise NotImplementedError(self.error_message)
NotImplementedError: Descendants must set variable `y`