在@property的上下文中调用另一个方法中的方法

时间:2013-08-13 19:24:00

标签: python oop methods decorator

使用以下包含@property装饰器的示例代码:

class Grade_Calculator(object):
    def __init__(self,score):
        self.score = score

    @property
    def grade(self):
        if self.score in range(60,70):
            grade = 'D'
        elif self.score in range(70,80):
            grade = 'C'
        elif self.score in range(80,90):
            grade = 'B'
        elif self.score in range(90,101):
            grade = 'A'
        return grade

    @property
    def failure(self):
        if self.score < 60:
            print 'See me'
            grade = 'F'
            return grade

和一个实例:

g = Grade_Calculator(28)

g.grade会返回UnboundLocalError。我想在failure()内致电grade()以避免此错误。

使用实例:

g = Grade_Calculator(89)

g.failure()无声地失败。我想在grade()内致电failure(),以便在这种情况下充当自动防火墙。

我看过很多关于只做self.method()次调用的引用,但它们并不适合我,我认为装饰器的存在让我感到不知所措:

@property
def grade(self):
    if self.score < 60:
        self.failure()
    elif self.score in range(60,70):
        grade = 'D'
    elif self.score in range(70,80):
        grade = 'C'
    elif self.score in range(80,90):
        grade = 'B'
    elif self.score in range(90,101):
        grade = 'A'
    return grade

g = Grade_Calculator(28)
g.grade
See me
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-667-fb10e6cf27d4> in <module>()
----> 1 g.grade

./sample.py in grade(self)
      6     def grade(self):
      7         if self.score < 60:
----> 8             self.failure()
      9         elif self.score in range(60,70):
     10             grade = 'D'

TypeError: 'str' object is not callable

我不理解什么?

2 个答案:

答案 0 :(得分:2)

class Grade_Calculator(object):
    def __init__(self, score):
        self.score = score

    @property
    def grade(self):
        grade = self.failure
        if 60 <= self.score < 70:
            grade = 'D'
        elif 70 <= self.score < 80:
            grade = 'C'
        elif 80 <= self.score < 90:
            grade = 'B'
        elif 90 <= self.score < 100:
            grade = 'A'
        return grade

    @property
    def failure(self):
        if self.score < 60:
            print 'See me'
            grade = 'F'
            return grade

if __name__ == '__main__':
    a = Grade_Calculator(71)
    print a.grade

您基本上使用失败方法为对象创建了一个新属性。并且你永远不会试图获得它的价值,这就是为什么你永远不会看到'See me' 顺便说一下,你重写了最初为整数的等级值。您已将其转换为字符串('A''B''C',...) 我提供的代码有效,但我改变了一些东西。没有必要调用范围(这很昂贵)。您可以在Python中使用value < variable < other_value

答案 1 :(得分:2)

您已将failure定义为属性。因此,您无法使用()表示法来调用它;事实上,不这样做是有点使用财产的重点。 self.failure返回'F',然后您尝试调用它,这就是您收到无法调用字符串的错误的原因。这就好像你写了'F'()这是一个明显的错误。

此外,您丢弃了从failure获得的值,并且您只是在失败的情况下返回一个值(这意味着您将获得None)。当然,如果您的成绩不及格,那么您只能访问failure ...在这种情况下,您不需要在failure内查看该条件,现在对吗?

此外,在物业中打印东西是非常糟糕的风格。访问属性时,您不希望打印某些内容。关注点分离:类之外的东西可能应该是打印,或者你应该有一个单独的方法来调用打印grade返回的内容。

我会按如下方式重写你的课程:

class Grade_Calculator(object):
    def __init__(self, score):
        self.score = score

    @property
    def grade(self):
        if self.failure:
            return 'F'
        if 60 <= self.score < 70:
            return 'D'
        if 70 <= self.score < 80:
            return 'C'
        if 80 <= self.score < 90:
            return 'B'
        if 90 <= self.score < 100:
            return 'A'

    @property
    def failure(self):
        return self.score < 60   # returns True or False

    def print_grade(self):
        print self.grade, "- see me" * self.failure

if __name__ == '__main__':
    c = Grade_Calculator(71)
    c.print_grade()