使用 python class 作为工具包?
Use a python class as a toolkit?
我不确定这样做的正确方法是什么,但我有以下代码:
class ToolKit(object):
def printname(self):
print self.name
class Test(ToolKit):
def __init__(self):
self.name = "Test"
b = Test()
b.printname()
我的目标是拥有某种抽象基础 class,我可以将其用作其他 classes 的工具包。此工具包 class 不应实例化。它应该有抽象方法,但其他方法应该继承,不应该在 child classes 中实现,因为它们将在 children 之间共享。以下代码正在运行。但是,我正在使用 Pycharm 并且 "self.name" 导致此警告:
Unresolved attribute reference 'name' for class 'Toolkit'
我想知道这样做的正确方法是什么。我研究了 ABC metaclass,但由于两个原因未能使它按我的预期工作。首先,如果所有方法都不是抽象方法,则可以实例化一个抽象 class ;我只是想确保它根本无法实例化。其次,我想要一些将用作默认值的方法(不需要像 printname 那样被覆盖),但我似乎无法弄清楚如何实现它。
提前致谢!
编辑:
当我说它有效时,我的意思是它可以正确打印 "Test"。
如果你想阻止你的 'base' class 被实例化而其他 classes 可以实例化它 和 你不想使用 metaclasses,你可以简单地在实例创建级别阻止它,如:
class ToolKit(object):
def __new__(cls, *args, **kwargs):
assert cls is not ToolKit, "You cannot instantiate the base `ToolKit` class"
return super(ToolKit, cls).__new__(cls)
def printname(self):
print(self.name)
class Test(ToolKit):
def __init__(self):
self.name = "Test"
现在,如果您尝试像这样使用它:
b = Test()
b.printname()
一切都会很好,它会打印出来 Test
,但如果您尝试实例化 ToolKit class,您将得到一个不同的故事:
a = ToolKit()
# AssertionError: You cannot instantiate the base `ToolKit` class
你可以通过强制 method 为 implemented/overriden 来做类似的事情,但它很快就会变得难以处理,所以你最好从一开始就使用 abc.ABCMeta
。
P.S。无论如何,您可能想要重新考虑实施此类模式。与其竭力阻止用户以无法保证其 operation/correctness 的方式使用您的代码,不如将他们视为成年人,并在文档中清楚地写下您的意图。这样一来,如果他们决定以非预期的方式使用您的代码,那将是他们的错,您将在此过程中节省大量时间。
UPDATE - 如果你想强制执行属性的 subclass 定义,有一个专门用于此的特殊 @abc.abstractproperty
描述符 - 它并不理想它不是强制 subclasses 设置 属性 而是覆盖 属性 getter/setter,但是你不能在变量周围有描述符。
您至少可以强制执行 class 级变量(如在简单属性中,没有定义访问器),例如:
class ToolKit(object):
__REQUIRED = ["id", "name"]
def __new__(cls, *args, **kwargs):
assert cls is not ToolKit, "You cannot instantiate the base `ToolKit` class"
for req in ToolKit.__REQUIRED:
assert hasattr(cls, req), "Missing a required property: `{}`".format(req)
return super(ToolKit, cls).__new__(cls)
def printname(self):
print("{} is alive!".format(self.name))
class Test1(ToolKit):
id = 1
name = "Test1"
class Test2(ToolKit):
name = "Test2"
class Test3(ToolKit):
id = 3
现在,如果您测试它们每个的实例化:
for typ in [ToolKit, Test1, Test2, Test3]:
print("Attempting to instantiate `{}`...".format(typ.__name__))
try:
inst = typ()
inst.printname()
except AssertionError as e:
print("Instantiation failed: {}".format(e))
你会回来的:
Attempting to instantiate `ToolKit`...
Instantiation failed: You cannot instantiate the base `ToolKit` class
Attempting to instantiate `Test1`...
Test1 is alive!
Attempting to instantiate `Test2`...
Instantiation failed: Missing a required property: `id`
Attempting to instantiate `Test3`...
Instantiation failed: Missing a required property: `name`
然而,Python是一种动态语言,因此即使实例化级别检查通过,用户可以在之后删除属性,这将导致printname
引发错误由于缺少 属性。正如我所说,只需将代码的用户视为成年人,并要求他们做您希望他们做的事情,以使您的代码正常运行。它的麻烦要少得多,而且您可以节省大量时间来改进代码的实际有用部分,而不是发明方法来防止您的用户伤害自己。
我不确定这样做的正确方法是什么,但我有以下代码:
class ToolKit(object):
def printname(self):
print self.name
class Test(ToolKit):
def __init__(self):
self.name = "Test"
b = Test()
b.printname()
我的目标是拥有某种抽象基础 class,我可以将其用作其他 classes 的工具包。此工具包 class 不应实例化。它应该有抽象方法,但其他方法应该继承,不应该在 child classes 中实现,因为它们将在 children 之间共享。以下代码正在运行。但是,我正在使用 Pycharm 并且 "self.name" 导致此警告:
Unresolved attribute reference 'name' for class 'Toolkit'
我想知道这样做的正确方法是什么。我研究了 ABC metaclass,但由于两个原因未能使它按我的预期工作。首先,如果所有方法都不是抽象方法,则可以实例化一个抽象 class ;我只是想确保它根本无法实例化。其次,我想要一些将用作默认值的方法(不需要像 printname 那样被覆盖),但我似乎无法弄清楚如何实现它。
提前致谢!
编辑:
当我说它有效时,我的意思是它可以正确打印 "Test"。
如果你想阻止你的 'base' class 被实例化而其他 classes 可以实例化它 和 你不想使用 metaclasses,你可以简单地在实例创建级别阻止它,如:
class ToolKit(object):
def __new__(cls, *args, **kwargs):
assert cls is not ToolKit, "You cannot instantiate the base `ToolKit` class"
return super(ToolKit, cls).__new__(cls)
def printname(self):
print(self.name)
class Test(ToolKit):
def __init__(self):
self.name = "Test"
现在,如果您尝试像这样使用它:
b = Test()
b.printname()
一切都会很好,它会打印出来 Test
,但如果您尝试实例化 ToolKit class,您将得到一个不同的故事:
a = ToolKit()
# AssertionError: You cannot instantiate the base `ToolKit` class
你可以通过强制 method 为 implemented/overriden 来做类似的事情,但它很快就会变得难以处理,所以你最好从一开始就使用 abc.ABCMeta
。
P.S。无论如何,您可能想要重新考虑实施此类模式。与其竭力阻止用户以无法保证其 operation/correctness 的方式使用您的代码,不如将他们视为成年人,并在文档中清楚地写下您的意图。这样一来,如果他们决定以非预期的方式使用您的代码,那将是他们的错,您将在此过程中节省大量时间。
UPDATE - 如果你想强制执行属性的 subclass 定义,有一个专门用于此的特殊 @abc.abstractproperty
描述符 - 它并不理想它不是强制 subclasses 设置 属性 而是覆盖 属性 getter/setter,但是你不能在变量周围有描述符。
您至少可以强制执行 class 级变量(如在简单属性中,没有定义访问器),例如:
class ToolKit(object):
__REQUIRED = ["id", "name"]
def __new__(cls, *args, **kwargs):
assert cls is not ToolKit, "You cannot instantiate the base `ToolKit` class"
for req in ToolKit.__REQUIRED:
assert hasattr(cls, req), "Missing a required property: `{}`".format(req)
return super(ToolKit, cls).__new__(cls)
def printname(self):
print("{} is alive!".format(self.name))
class Test1(ToolKit):
id = 1
name = "Test1"
class Test2(ToolKit):
name = "Test2"
class Test3(ToolKit):
id = 3
现在,如果您测试它们每个的实例化:
for typ in [ToolKit, Test1, Test2, Test3]:
print("Attempting to instantiate `{}`...".format(typ.__name__))
try:
inst = typ()
inst.printname()
except AssertionError as e:
print("Instantiation failed: {}".format(e))
你会回来的:
Attempting to instantiate `ToolKit`... Instantiation failed: You cannot instantiate the base `ToolKit` class Attempting to instantiate `Test1`... Test1 is alive! Attempting to instantiate `Test2`... Instantiation failed: Missing a required property: `id` Attempting to instantiate `Test3`... Instantiation failed: Missing a required property: `name`
然而,Python是一种动态语言,因此即使实例化级别检查通过,用户可以在之后删除属性,这将导致printname
引发错误由于缺少 属性。正如我所说,只需将代码的用户视为成年人,并要求他们做您希望他们做的事情,以使您的代码正常运行。它的麻烦要少得多,而且您可以节省大量时间来改进代码的实际有用部分,而不是发明方法来防止您的用户伤害自己。