【问题标题】:Python OO: how to stop procedure flow in an entire class with `return` statement?Python OO:如何使用“return”语句停止整个类中的过程流?
【发布时间】:2012-07-16 00:45:41
【问题描述】:

这是一个初学者 OO Python 问题。我希望有一个适合初学者的stackoverflow,如果我可以问这个而不会得到反对票。所以,我们开始吧。

当我运行这段代码时:

from nltk import NaiveBayesClassifier,classify
import USSSALoader
import random

class genderPredictor():

    def getFeatures(self):
        if self._loadNames() != None:
            maleNames,femaleNames=self._loadNames()
        else:
            print "There is no training file."
            return

        featureset = list()
        for nameTuple in maleNames:
            features = self._nameFeatures(nameTuple[0])
            featureset.append((features,'M'))

        for nameTuple in femaleNames:
            features = self._nameFeatures(nameTuple[0])
            featureset.append((features,'F'))

        return featureset

    def trainAndTest(self,trainingPercent=0.80):
        featureset = self.getFeatures()
        random.shuffle(featureset)

        name_count = len(featureset)

        cut_point=int(name_count*trainingPercent)

        train_set = featureset[:cut_point]
        test_set  = featureset[cut_point:]

        self.train(train_set)

        return self.test(test_set)

    def classify(self,name):
        feats=self._nameFeatures(name)
        return self.classifier.classify(feats)

    def train(self,train_set):
        self.classifier = NaiveBayesClassifier.train(train_set)
        return self.classifier

    def test(self,test_set):
       return classify.accuracy(self.classifier,test_set)

    def getMostInformativeFeatures(self,n=5):
        return self.classifier.most_informative_features(n)

    def _loadNames(self):
        return USSSALoader.getNameList()

    def _nameFeatures(self,name):
        name=name.upper()
        return {
            'last_letter': name[-1],
            'last_two' : name[-2:],
            'last_is_vowel' : (name[-1] in 'AEIOUY')
        }

if __name__ == "__main__":
    gp = genderPredictor()
    accuracy=gp.trainAndTest()

self._loadNames() 返回None,我得到了这个错误(来自随机导入的模块):

shuffle C:\Python27\lib\random.py   285     
TypeError: object of type 'NoneType' has no len()

发生这种情况是因为尽管我在 getFeatures(self) 中添加了 return 语句,但流程会跳转到调用随机模块 (random.shuffle(featureset)) 的下一个类方法(即 trainAndTest(self,trainingPercent=0.80))。

所以,我想知道:如何不仅在getFeatures(self) 方法中,而且在包含它的整个类中停止过程流?

顺便说一句,感谢Stephen Holiday 分享代码。

【问题讨论】:

  • +1。这是一个很好的问题的例子。你解释了问题并包含了相关的回溯。
  • 没错。好问题。有一个简单的问题,有一个相对简洁的代码示例。您也包含了回溯的一部分!我不知道您为什么会期望对此投反对票。

标签: python oop class flow


【解决方案1】:

发生这种情况是因为尽管我在其中添加了退货声明 getFeatures(self),流程跳转到下一个类方法(也就是 trainAndTest(self,trainingPercent=0.80)) 调用随机模块 (random.shuffle(featureset))。

要记住的重要一点是None 是一个完全有效的值。 getFeatures() 中的 return 语句完全按照它的指示执行并返回有效值。只有在特殊情况下,或者您明确表示,才会停止这种流动。

与其询问如何“从类中返回”,您可能想要研究的是检查您调用的函数的返回值,并在继续之前确保它符合您的期望。有两个地方可以这样做:

def trainAndTest(self,trainingPercent=0.80):
    featureset = self.getFeatures()

...

def _loadNames(self):
    return USSSALoader.getNameList()

在第一个地方,你可以检查if featureset is None,如果它是无则做出反应。
在第二个地方,你可以先检查并在那里做出反应,而不是盲目返回。

其次。您可以选择引发异常。异常是代码遇到错误并且无法继续的情况。然后,调用函数负责处理它或让它顺着链向上。如果没有处理异常,您的应用程序将崩溃。如您所见,您从 random 类中引发了一个异常,因为您允许 None 进入 shuffle 调用。

names = USSSALoader.getNameList()
if names is None:
    # raise an exception?
    # do something else?
    # ask the user to do something?

此时的问题是,当你的程序碰巧得到一个 None 而不是一个有效的列表时,你希望你的程序做什么?您是否想要一个类似于随机引发的异常,但对您的应用程序更有帮助且更具体?或者,也许您只是想调用其他一些获取默认列表的方法。即使您的应用程序执行除退出之外的任何操作,是否也没有名称列表?那将是一个不可挽回的局面。

names = USSSALoader.getNameList()
if names is None:
    raise ValueError("USSSALoader didn't return any "
                     "valid names! Can't continue!")

更新

根据您的评论,我想添加您想要的特定处理。 Python 有几个built in exception types 来代表各种情况。您最可能想要引发的是一个 IOError,表示找不到该文件。我假设“文件”是指 USSSALoader.getNameList() 需要使用但找不到的任何文件。

names = USSSALoader.getNameList()
if names is None:
    raise IOError("No USSSALoader file found")

此时,除非调用链更高的某个函数处理它,否则您的程序将终止并出现回溯错误。

【讨论】:

  • 感谢您的周到回复。我的目标是,如果程序找不到文件,它会显示一条消息(“无文件”)并终止。
  • @Pythonista'sApprentice:不客气。我刚刚用那个具体的例子为你更新了答案的结尾。
【解决方案2】:

没有什么能比得上“全班归来”。您需要组织代码,以便返回值在获取它们的函数中有效。这些函数可以测试该值以确定下一步该做什么。类边界对程序流程没有影响,只是方法的命名空间。

【讨论】:

    【解决方案3】:

    通常你会在这里做的是在你调用函数后检查有效性,例如:

    featureset = self.getFeatures()
    if not featureset:
        # You could log an error message if you expected to get something, etc.
        return
    

    【讨论】:

      猜你喜欢
      • 2012-04-18
      • 2018-02-07
      • 1970-01-01
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 2017-08-29
      • 2014-02-02
      • 1970-01-01
      相关资源
      最近更新 更多