Python属性的多类型验证



如果未提供UUID,则默认生成UUID,如果提供str,则验证/创建UUID对象的类。

import attr
from attrs import validators
from uuid import UUID, uuid1
def _validate(instance, attribute, value) -> None:
try:
if isinstance(value, str):
instance.uuid = UUID(value)
return
except Exception as e:
raise BadUUID() from e

@attr.s(slots=True)
class Private:
uuid = attr.ib(type=[str, UUID], validator=[validators.optional([validators.instance_of(UUID), validators.instance_of(str)]), _validate], default=uuid1())

它应该提供和不提供价值:

print(Private())
print(Private('d283a713-9f4b-1c15-ab8d-8d95d7ce8999'))

在没有提供的情况下,它应该使用默认设置生成一个新的UUID。

如果提供了值,则应验证该值并创建UUID对象。


我得到一个错误,因为它只会验证一个实例类型,strUUID

如果我设置instance_of(UUID),它只会在没有提供值的情况下工作。

如果我将其设置为instance_of(str),它将仅在提供str的情况下工作。


我做错了什么吗?有更好的方法来完成我想要的吗?

这似乎就是你想要的:

import attr
from uuid import UUID, uuid1

def _convert(value) -> UUID:
return value if isinstance(value, UUID) else UUID(value)

@attr.s(slots=True)
class Private:
uuid = attr.ib(default=uuid1(), converter=_convert)

p1 = Private()
print(p1.uuid)
p2 = Private('c53358b3-798e-11ec-a49b-cf6d4243e811')
print(p2.uuid)

示例结果:

d5e2d087-798e-11ec-9d59-cf6d4243e811
c53358b3-798e-11ec-a49b-cf6d4243e811

如果您更喜欢仅转换字符串,并且如果传递了任何其他内容,则会引发您自己的异常(尽管我可能会将其留给UUID()本身(,这是可行的:

import attr
from uuid import UUID, uuid1

class BadUUID(Exception):
...

def _convert(value) -> UUID:
if isinstance(value, str):
return UUID(value)
elif isinstance(value, UUID):
return value
else:
raise BadUUID(f'{value} is neither a string nor a UUID')

@attr.s(slots=True)
class Private:
uuid = attr.ib(default=uuid1(), converter=_convert)

p = Private(42)

或者,如果您的意图是从UUID中捕获异常并添加一些内容:

import attr
from uuid import UUID, uuid1

class BadUUID(Exception):
...

def _convert(value) -> UUID:
try:
return value if isinstance(value, UUID) else UUID(value)
except Exception as e:
raise BadUUID (f'{value} is not a good UUID') from e

@attr.s(slots=True)
class Private:
uuid = attr.ib(default=uuid1(), converter=_convert)

p = Private(42)

最新更新