Pythonic-如何使用多个参数初始化构造函数并进行验证
我是一个python noob,我正试图以“python式”的方式解决我的问题。我有一个类,它的Pythonic-如何使用多个参数初始化构造函数并进行验证,python,design-patterns,Python,Design Patterns,我是一个python noob,我正试图以“python式”的方式解决我的问题。我有一个类,它的\uuuu init\uuu方法包含6个参数。我需要验证每个参数,如果任何参数未能验证,则抛出/引发异常 这条路对吗 class DefinitionRunner: def __init__(self, canvasSize, flightId, domain, definitionPath, harPath): self.canvasSize = canvasSize
\uuuu init\uuu
方法包含6个参数。我需要验证每个参数,如果任何参数未能验证,则抛出/引发异常
这条路对吗
class DefinitionRunner:
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
self.canvasSize = canvasSize
self.flightId = flightId
self.domain = domain
self.harPath = harPath
self.definitionPath = definitionPath
... bunch of validation checks...
... if fails, raise ValueError ...
从广义上讲,这看起来像是你做这件事的方式。虽然严格地说,您也可以在分配之前而不是之后进行验证,尤其是在分配可能会占用大量时间或资源的情况下。另外,样式约定要求不要像您这样对齐赋值块。我会像您那样做。除了验证性的东西。我将在setter方法中进行验证,并使用它来设置属性。如果希望变量可以独立于
\uuuu init\uuuu
进行设置,则可以使用在单独的方法中实现验证
但是,它们只适用于新样式的类,因此需要将类定义为class DefinitionRunner(object)
那么比如说,
@property
def canvasSize(self):
return self._canvasSize
@canvasSize.setter
def canvasSize(self, value):
# some validation here
self._canvasSize = value
你可以这样做。为每种类型的输入创建一个验证器。创建一个助手函数以运行验证:
def validate_and_assign(obj, items_d, validators):
#validate all entries
for key, validator in validators.items():
if not validator[key](items_d[key]):
raise ValueError("Validation for %s failed" % (key,))
#set all entries
for key, val in items_d.items():
setattr(obj, key, val)
您可以这样使用:
class DefinitionRunner:
validators = {
'canvasSize': canvasSize_validator,
'flightId': flightId_validator,
'domain': domain_validator,
'definitionPath': definitionPath_validator,
'harPath': harPath_validator,
}
def __init__(self, canvasSize, flightId, domain, definitionPath, harPath):
validate_and_assign(self, {
'canvasSize': canvasSize,
'flightId': flightId,
'domain': domain,
'definitionPath': definitionPath,
'harPath': harPath,
}, DefinitionRunner.validators)
当然,如果数据类型相同,验证程序可能是相同的函数。我不确定这是否完全是“Pythonic”,但我定义了一个名为require\u type的函数装饰程序。(老实说,我想我是在网上找到的。) 然后,要使用它:
class SomeObject(object):
@require_type("prop1", str)
@require_type("prop2", numpy.complex128)
def __init__(self, prop1, prop2):
pass
这个看起来不错。您认为这可能不是一个好方法,有什么特别的原因吗?您正在进行哪些类型的验证?很多时候,这并不是完全必要的…验证是非常基本的,只是确保设置了一些特定的值,并且所有变量都不是空的。。。值是必需的。@NPE-我不确定是否缺少处理此问题的python特定功能。通常在执行类似操作时,您会编写大量的锅炉板代码。然而,其优点是,在初始化类实例之后,您仍然可以安全地知道用户无法将属性重置为不正常的属性。您可以通过重写
\uuuuuuu setattr\uuuuuu
在很大程度上避免样板文件,但您要么最终将该方法膨胀,或是授权给其他方法。不过,你至少可以不用那样写一堆setter。您还可以围绕property
编写自己的decorator,它自动生成一个getter,只需要一个setter。谢谢。我现在没有选择这个,因为这不是我决定要做的,但这是一个很好的答案,我将进一步研究。这个逻辑只在对象周围有意义,所以直接将它放在类中,或在混合中。然后您可以做一些很好的事情,比如提供一个register
方法来向类添加新的验证器。或者,如果验证器很简单,只需完全放弃外部基础结构,直接在字典中以lambda的形式编写验证器,然后在\uuuuu init\uuuuu
中赋值时对其进行迭代。是的,mixin可能是最好的选择,使用类方法注册验证器库-这是一种有趣的方法。我会考虑这个,谢谢。你也可以使用断言语句。我一直在使用PyCharm IDE,如果您断言变量是某种类型,PyCharm可以为您提供代码完成。例如,我有一个名为Email
的类。如果我在函数中添加一行:assert-isinstance(email,email)
,PyCharm将知道email类的代码完成选项。我最终选择了这一行,因为这是目前工作量最小的应用程序。然而,我喜欢杰科泽拉的回答,并且很可能在将来实现这一点。
class SomeObject(object):
@require_type("prop1", str)
@require_type("prop2", numpy.complex128)
def __init__(self, prop1, prop2):
pass