简体   繁体   English

我应该在哪里检查状态/抛出异常?

[英]Where should I check state / throw exception?

My situation is something like this: 我的情况是这样的:

class AbstractClass:
    def __init__(self, property_a):
        self.property_a = property_a

    @property
    def some_value(self):
        """Code here uses property_a but not property_b to determine some_value"""

    @property
    def property_a(self):
        return self.property_a

    @property
    def property_b(self):
        """Has to be implemented in subclass."""
        raise NotImplementedError


class Concrete1(AbstractClass):
    """Code here including an implementation of property_b"""


class Concrete2(AbstractClass):
    """Code here including an implementation of property_b"""

There is also a condition that if property_b is less than property_a , then property_a is invalid and thus the result of some_value is also invalid. 还有一个条件是如果property_b小于property_a ,则property_a无效,因此some_value的结果也无效。

What I mean is this... if at any time during the object's lifetime, calling property_b would yield a number lower than calling property_a , there's a problem. 我的意思是这个......如果在对象的生命周期中的任何时候,调用property_b会产生比调用property_a更低的数字,那就有问题了。 However, property_b is not a field . 但是,property_b 不是字段 It is determined dynamically based on n fields, where n >= 1. It is impossible to check this condition while setting property_b because property_b itself is never set. 它是基于n个字段动态确定的,其中n > = 1.在设置property_b无法检查此条件,因为property_b本身从未设置。 Really, setters are not anticipated to be used anywhere here. 实际上,预计不会这里任何地方使用制定者。 All fields are likely to be set in the constructors and then left alone. 所有字段都可能在构造函数中设置,然后单独保留。 This means that property_a will be known in the constructor for AbstractClass and property_b only after evaluating the constructor for the concrete classes. 这意味着, property_a将在构造函数中被称为AbstractClassproperty_b仅评估构造函数的具体类之后

<update> <更新>
The fundamental problem is this: I need to check property_a for validity, but when property_a is set (the most intuitive place to check it), property_b is undefined. 基本问题是:我需要检查property_a的有效性,但是当设置property_a时(最直观的检查位置), property_b是未定义的。
</update> </更新>

I want to ensure that property_b is never less than property_a . 我想确保property_b永远不会低于property_a How should I handle it? 我应该怎么处理?

Check property_a against property_b in... 在...中检查property_a property_b

  1. AbstractClass.__init__ . AbstractClass.__init__ This is actually impossible because property_b hasn't been defined yet. 这实际上是不可能的,因为还没有定义property_b
  2. AbstractClass.property_a . AbstractClass.property_a This seems problematic because I would be throwing an exception in a getter. 这似乎有问题,因为我会在getter中抛出一个异常。
  3. Each concrete implementation of property_b . property_b每个具体实现。 Not only would I be throwing an exception in a getter, I would be duplicating code. 我不仅会在getter中抛出异常,我还会复制代码。 Also property_b does not logically depend on property_a . property_b在逻辑上也不依赖于property_a
  4. AbstractClass.some_value . AbstractClass.some_value This is still throwing an exception in a getter. 这仍然在getter中引发异常。 Also, it is logically impossible for property_b to be less than property_a all the time , not just when trying to determine some_value . 此外,它在逻辑上是不可能的property_b比少property_a 所有的时间 ,试图确定不只是当some_value Further, if subclasses decide to add other properties that depend on property_a , they may forget to check it against property_b . 此外,如果子类决定添加依赖于property_a其他属性,他们可能会忘记对property_b进行检查。
  5. Concrete setters for property_b . property_b具体setter。 These don't exist. 这些不存在。 property_b is sometimes determined from a value set in the constructor, sometimes calculated from multiple values. property_b有时是根据构造函数中设置的值确定的,有时是根据多个值计算的。 Also, code duplication. 另外,代码重复。
  6. Concrete class __init__ methods. 具体类__init__方法。 Code duplication. 代码重复。 Someone may forget. 有人可能会忘记。
  7. ??? ???

UPDATE UPDATE

I think what is causing confusion is that property_b is not simply a field. 我认为导致混淆的是property_b不仅仅是一个领域。 property_b relies on calculations. property_b依赖于计算。 It is really more a function than a property, if it helps to think about it that way. 它实际上是一个功能而不是一个属性,如果它有助于以这种方式思考它。

Add a method _validate_b(self, b) (single leading underscore to indicate "protected", ie, callable from derived classes but not by general client code) that validates the value of b (which only subclasses know) vs the value of a (which the abstract superclass does know). 添加方法_validate_b(self, b) (单个前导下划线表示“受保护”,即可从派生类调用,但不能通过一般客户端代码调用),验证b的值(只有子类知道)与a的值(抽象超类确实知道的)。

Make subclasses responsible for calling the validation method whenever they're doing something that could change their internal value for b. 让子类负责在他们做某些可能改变b的内部值的事情时调用验证方法。 In your very general case, the superclass cannot identify when b's value changes; 在一般情况下,超类无法识别b的值何时发生变化; since the responsibility of that change lies entirely with the subclasses, then the responsibility for triggering validation must also be with them (the superclass can perform validation, given the proposed new value of b, but it cannot know when validity must be checked). 由于该变更的责任完全在于子类,因此触发验证的责任也必须与它们一起(超类可以执行验证,给定b的新值,但它不知道何时必须检查有效性)。 So, document that clearly. 所以,清楚地记录下来。

If most subclasses fall into broad categories in terms of the strategies they use to affect their b's values, you can factor that out into either intermediate abstract classes (inheriting from the general one and specializing the general approach to "determining b", including the validation call), or (better, if feasible) some form of Strategy design pattern (typically implemented via either composition, or mix-in inheritance). 如果大多数子类在用于影响其b值的策略方面属于广泛的类别,则可以将其分解为中间抽象类(从一般类继承并专门化“确定b”的一般方法,包括验证调用),或(更好,如果可行的话)某种形式的策略设计模式(通常通过组合或混合继承实现)。 But this has more to do with convenience (for concrete-subclass authors) than with "guaranteeing correctness", since a given concrete subclass might bypass such mechanisms. 但这与方便性(对于具体子类作者)有关,而与“保证正确性”有关,因为给定的具体子类可能会绕过这些机制。

If you need to, you can offer a "debug/test mode" where properties are validated redundantly on access (probably not advisable in production use, but for debugging and testing it would help catch errant subclasses that are not properly calling validation methods). 如果需要,您可以提供“调试/测试模式”,其中属性在访问时被冗余验证(在生产使用中可能不可取,但是对于调试和测试,它将有助于捕获未正确调用验证方法的错误子类)。

The golden rule is to "encapsulate" property_b so that the subclass provides part of the implementation, but not all of it. 黄金法则是“封装” property_b以便子类提供部分实现,但不是全部。

class AbstractClass:
    def __init__(self, property_a):
        self._value_of_a = property_a

    @property
    def get_b( self ):
       self.validate_a()
       self._value_of_b = self.compute_b()
       self.validate_other_things()
       return self._value_of_b

   def compute_b( self ):
       raise NotImplementedError

It's hard to say precisely what's supposed to happen when you have two classes and you're asking about allocation of responsibility. 当你有两个课程并且你在询问责任分配时,很难准确地说出应该发生什么。

It appears that you want the superclass to be responsible for some aspect of the relationship between a and b 看来您希望超类负责a和b之间关系的某些方面

It appears that you want the the subclass to be responsible for some other aspect of computing b, and not responsible for the relationship. 看来您希望子类负责计算b的某些其他方面,而不负责该关系。

If this is what you want, then your design must assign responsibility by decomposing things into the part the superclass is responsible for and the part the subclass is responsible for. 如果这是您想要的,那么您的设计必须通过将事物分解为超类负责的部分以及子类负责的部分来分配责任。

I suggest that you don't raise raise NotImplementedError but call a method instead which raises this error. 我建议您不要引发raise NotImplementedError但是调用一个方法而不是引发此错误。 Subclasses then have to override that method (instead of property_b ). 然后子类必须覆盖该方法(而不是property_b )。 In property_b , you call the method and then verify the result. property_b ,您调用该方法,然后验证结果。

Rationale: You should check the value as soon as possible (which is when someone changes it). 理由:您应该尽快检查该值(即有人更改时)。 Otherwise, an illegal value could be set and cause a problem much later in the code when no one can say how it got there. 否则,可能会设置非法值,并且在没有人能够说明它是如何到达时会在代码中导致问题。

Alternatively, you could store the value and a stack trace. 或者,您可以存储值和堆栈跟踪。 When the value is used, you can then check the value and print the original stack trace as "value was changed here". 使用该值时,您可以检查该值并将原始堆栈跟踪打印为“此处更改了值”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM