在方法开始时合并检查

时间:2019-10-10 18:32:03

标签: python python-3.x

我有几种类似于以下的方法:

@property
def tpr_num_days(self):
    """
    The duration, in days, of the TPR interval.
    """
    if not self.prices:
        raise RuntimeError("Must initialize self.prices first.")

    # do something

@property
def revenue_during_tpr_is_greatest(self):
    """
    Tells us if the Revenue that was generated during the TPR was both greater
    than the revenue that was generated in the same-duration interval before the TPR and after the TPR.
    """
    if not self.prices:
        raise RuntimeError("Must initialize self.prices first.")

    # do something

def build_pricing_data(self):
    """
    This will build a list of pricing objects.

    Note that we are currently excluding "returns" because the price of the returned
    item may be different than the current price of the product, which could open up
    a can of worms trying to track down when that item was purchased.
    """
    cursor.execute('''SELECT
                            date,
                            max(if(offer_code='sdbuy', price, null)) sd_buy_price,
                            max(if(offer_code='hdbuy', price, null)) hd_buy_price,
                            max(if(offer_code='sdrent', price, null)) sd_rent_price,
                            max(if(offer_code='hdrent', price, null)) hd_rent_price,
                            sum(revenue) revenue
                      FROM price_date WHERE apple_id=%s and territory=%s and revenue > 0
                      GROUP BY date
                      ORDER BY date
                      ''', (self.apple_id, self.territory))

    # let's make sure it's re-initialized in case it's called multiple times.
    self.prices = []     
    for row in cursor:
        pricing_obj = {"date": item[0], "SDBUY": item[1], "HDBUY": item[2], "SDRENT": item[3], "HDRENT": item[4], "REVENUE": item[5]}
        self.prices.append(pricing_obj)

与其在多种方法开始时使用此if语句,不如将其封装为更好的方法是什么?

2 个答案:

答案 0 :(得分:2)

您可以添加一种方法进行检查。

def validate_prices(self):
    if not self.prices:
        raise RuntimeError("Must initialize self.prices first.")

,然后将self.validate_prices()放在每个函数的开头。

它只保存一行,但您不必每次都重复相同的错误消息。

如果您想要更自动的功能,则可能必须定义一个元类,以将此代码添加到每个属性方法中。

答案 1 :(得分:2)

您可以使用函数装饰器:

import functools

def requires_price(func):
    @functools.wraps(func)
    def wrapper(obj, *args, **kwargs):
        if not obj.prices:
            raise RuntimeError("Must initialize self.prices first.")

        return func(obj, *args, **kwargs)

    return wrapper

将这样使用:

@property
@requires_price
def tpr_num_days(self):
    ... # do something

或者您可以更进一步,将装饰器实现为descriptor,这样就可以省略@property

class price_property:
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self

        if not instance.prices:
            raise RuntimeError("Must initialize self.prices first.")

        return self.func(instance)

这样使用:

@price_property
def tpr_num_days(self):
    ... # do something