按照设计,属性 getter 应该在 python 中抛出异常吗?
By design should a property getter ever throw an exception in python?
对于问题的某些上下文 - 我正在使用延迟加载来推迟 class 中某些属性的完全初始化,直到需要它们(如果有的话),因为它们在计算上可能很昂贵计算。
我的问题是 - 在 python 中,如果在计算 属性 的值时发生错误,或者无法计算该值,引发异常是否可以接受或者是否客观坏主意?
我知道这个问题:Best practices: throwing exceptions from properties - 在复习了其中的要点后实际上改写了这个问题。
但是我真的在寻找关于 python 的明确答案。
例如,即使那个值是 None,getter 也应该总是 return 一个值吗?
在其他语言中,例如c#,对于如何设计属性有明确的建议。
AVOID throwing exceptions from property getters.
Property getters should be simple operations and should not have any
preconditions. If a getter can throw an exception, it should probably
be redesigned to be a method. Notice that this rule does not apply to
indexers, where we do expect exceptions as a result of validating the
arguments
http://msdn.microsoft.com/en-us/library/ms229006.aspx
在python中也是如此吗? 属性 真的应该是一种方法吗?
我可以看到在强类型语言(如 c#)中这可能是一个问题,但我不确定这里是否成立。在调试器中测试它按预期工作。
明确地说,我正在测试如下内容。
class A(object):
def __init__(self):
self.__x = None
@property
def x(self):
if not self.__x:
self.__x = calculate_x()
if not some_test(self.__x):
# Is this a bad idea?
raise ValueError('Get x error {}'.format(self.__x))
return self.__x
@x.setter
def x(self, value):
if not some_test(value):
raise ValueError('Set x error {}'.format(value))
self.__x = value
我一直在使用 RTFM 和很多关于属性的信息,但似乎看不到任何使用它或警告反对它的东西。这一切是完全可以接受的还是我从地狱创造了某种可怕的反模式?
我尝试这样做的原因是因为我想到了类似于 "lazy" 描述符的东西,它允许我快速标记属性。例如
from functools import wraps
class Descriptor(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
value = self.func(obj)
setattr(obj, self.func.__name__, value)
return value
def lazy(func):
return wraps(func)(Descriptor(func))
然后
class A(object):
def __init__(self):
self.__x = None
@lazy
def x(self):
# where calculate_x might raise an exception
return calculate_x()
我觉得这个问题更适合Software Engineering Stack。
但无论如何:我会尽量避免在 getter 中抛出异常,当一个字段突然吹到你的脸上时,这有点令人惊讶。
但是 C# 也有可以做完全相同的延迟字段 - 所以根据现实世界的经验我会说:尽量避免这个问题,除非有充分的理由进行延迟加载,在这种情况下它可能没问题。
备选方案提供了一个 Initialize 方法,该方法将尝试或(我最喜欢的)添加一个 returns 值的方法,但在第一次使用后在内部使用支持字段来缓存该值。
像这样:
class bla(object):
expensive = None
def get_expensive():
if not expensive:
expensive =compute_expensive()
return expensive
经过更多阅读并回到这里,我将回答我自己的问题并拒绝——根据 PEP 8 风格指南,不推荐这样做。
https://www.python.org/dev/peps/pep-0008/
Note 3: Avoid using properties for computationally expensive operations;
the attribute notation makes the caller believe that access is (relatively)
cheap.
我意识到这在某种程度上解释了 Christian 的回答 - 但我一直在寻找关于这种模式的某种官方文档或指南。
对于问题的某些上下文 - 我正在使用延迟加载来推迟 class 中某些属性的完全初始化,直到需要它们(如果有的话),因为它们在计算上可能很昂贵计算。
我的问题是 - 在 python 中,如果在计算 属性 的值时发生错误,或者无法计算该值,引发异常是否可以接受或者是否客观坏主意?
我知道这个问题:Best practices: throwing exceptions from properties - 在复习了其中的要点后实际上改写了这个问题。
但是我真的在寻找关于 python 的明确答案。 例如,即使那个值是 None,getter 也应该总是 return 一个值吗? 在其他语言中,例如c#,对于如何设计属性有明确的建议。
AVOID throwing exceptions from property getters.
Property getters should be simple operations and should not have any preconditions. If a getter can throw an exception, it should probably be redesigned to be a method. Notice that this rule does not apply to indexers, where we do expect exceptions as a result of validating the arguments
http://msdn.microsoft.com/en-us/library/ms229006.aspx
在python中也是如此吗? 属性 真的应该是一种方法吗? 我可以看到在强类型语言(如 c#)中这可能是一个问题,但我不确定这里是否成立。在调试器中测试它按预期工作。
明确地说,我正在测试如下内容。
class A(object):
def __init__(self):
self.__x = None
@property
def x(self):
if not self.__x:
self.__x = calculate_x()
if not some_test(self.__x):
# Is this a bad idea?
raise ValueError('Get x error {}'.format(self.__x))
return self.__x
@x.setter
def x(self, value):
if not some_test(value):
raise ValueError('Set x error {}'.format(value))
self.__x = value
我一直在使用 RTFM 和很多关于属性的信息,但似乎看不到任何使用它或警告反对它的东西。这一切是完全可以接受的还是我从地狱创造了某种可怕的反模式?
我尝试这样做的原因是因为我想到了类似于 "lazy" 描述符的东西,它允许我快速标记属性。例如
from functools import wraps
class Descriptor(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, type=None):
value = self.func(obj)
setattr(obj, self.func.__name__, value)
return value
def lazy(func):
return wraps(func)(Descriptor(func))
然后
class A(object):
def __init__(self):
self.__x = None
@lazy
def x(self):
# where calculate_x might raise an exception
return calculate_x()
我觉得这个问题更适合Software Engineering Stack。 但无论如何:我会尽量避免在 getter 中抛出异常,当一个字段突然吹到你的脸上时,这有点令人惊讶。 但是 C# 也有可以做完全相同的延迟字段 - 所以根据现实世界的经验我会说:尽量避免这个问题,除非有充分的理由进行延迟加载,在这种情况下它可能没问题。
备选方案提供了一个 Initialize 方法,该方法将尝试或(我最喜欢的)添加一个 returns 值的方法,但在第一次使用后在内部使用支持字段来缓存该值。
像这样:
class bla(object):
expensive = None
def get_expensive():
if not expensive:
expensive =compute_expensive()
return expensive
经过更多阅读并回到这里,我将回答我自己的问题并拒绝——根据 PEP 8 风格指南,不推荐这样做。
https://www.python.org/dev/peps/pep-0008/
Note 3: Avoid using properties for computationally expensive operations;
the attribute notation makes the caller believe that access is (relatively)
cheap.
我意识到这在某种程度上解释了 Christian 的回答 - 但我一直在寻找关于这种模式的某种官方文档或指南。