python属性中的健全性检查部分起作用

2024-10-03 06:19:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我是python新手,我需要一些帮助。为了避免传递无意义的参数,我创建了一些带有属性的类。在

举个例子,我有一节课

class match(object):
     __teams=(None,None)

     def setTeams(self,tms):
          if type(tms) != type(list()) and type(tms) != type(tuple()):
               raise Exception("Teams must be a list of length 2")
          if len(tms) != 2:
               raise Exception("Teams must be a list of length 2")
          if (type(tms[0])==type(str()) or (type(tms[0])==type(unicode()))) \
          and (type(tms[1])==type(str()) or type(tms[1])==type(unicode())):
               self.__teams=tms
          else:
               raise Exception("Both teams must be strings")
          return

      teams=property(getTeams,setTeams)

如果我写信

^{pr2}$

我应该有个例外,但是

match1.teams[0]=5

不引发异常并传递数字5。请记住,这不是类的全部,我只写下了与我的问题相关的内容,所以假设代码的行为与我描述的一样。在

我想这是因为在python中,所有的东西都是通过引用传递的,但是我必须小心,不要给我的对象分配无意义的数据,这首先会破坏拥有属性的目的。在

那么,除了不使用列表之外,有没有一种方法可以解决这个问题呢?还是我必须学会接受它?在


Tags: andselfnoneif属性typeexceptionbe
3条回答

Python和类型检查不在一起。学会接受它。使用代码传递正确类型的人的工作。记录代码的期望值,但不要显式检查。在

除了列表和元组,还有其他集合。你为什么要禁止,比如说,namedtuple?Python是一种动态语言,不要通过编写类型检查来对抗它。在

在Python词汇表中查找EAFP。不要试图预测错误,要及时处理。在


一个合理的替代类型检查的方法是转换成一个列表:

self.__teams = list(tms)

列出不兼容的类型将导致在此行引发一个异常,从现在起,您可以确定您正在处理的是一个列表。 (当然,这不会阻止某人为列表分配非字符串。)


哦,如果你有过的话(有充分的理由!)需要类型检查,请使用isinstance函数,而不是比较type()。它还将捕捉所需类型的子类。此外,尽量使用最通用的基类型。测试字符串(Unicode或其他)的正确方法是:

^{pr2}$

检查列表式集合的正确方法是:

import collections
if isinstance(my_object, collections.Sequence):
    ...

但那只是一个旁白,不是你问题的适当解决办法。没有正当理由不要做类型检查。在

这个错误不是因为某些类型检查失败。在

除非您错误地陈述了代码(它显然是经过编辑的,因为您发布的代码不会正确运行),否则发生这种情况的原因是match1.teams[0]调用了您的getTeams函数,而不是您的setTeams函数。要亲自查看,请尝试以下练习:

class match(object):
    __teams=(None,None)
    def setTeams(self,tms):
        print "in set"
        self.__teams = tms
    def getTeams(self):
        print "in get"
        return self.__teams
    teams=property(getTeams,setTeams)

当我尝试这个时,我得到了以下结果:

^{pr2}$

propertys的一个优点是能够进行数据验证有时确保获得非常具体的内容非常重要。在

在您的情况下,您需要做两件事之一:

  • 将您的teams数据存储在一个不能修改的结构中,例如tuple或{};然后当数据被检索时,它就不能被更改

或者

  • 让您的get方法返回一个数据的副本,这样任何修改都不会弄乱原始的数据

第一个解决方案(不可变类型)如下所示:

class match(object):
    __teams=(None,None)

    def setTeams(self,tms):
        "any sequence type will do, as long as length is two"
        if len(tms) != 2:
            raise TypeError(
                "Teams must be a sequence of length 2"
                )
        if not isinstance(tms[0], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        if not isinstance(tms[1], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        self.__teams = tuple(tms)

    def getTeams(self):
        return self.__teams

    teams=property(getTeams,setTeams)

当您在获得值后尝试赋值时,会发生以下情况:

^{pr2}$

第二个解决方案(返回一个副本而不是原来的)如下所示:

class match(object):
    __teams=(None,None)

    def setTeams(self,tms):
        "any sequence type will do, as long as length is two"
        if len(tms) != 2:
            raise TypeError(
                "Teams must be a sequence of length 2"
                )
        if not isinstance(tms[0], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                 )
        if not isinstance(tms[1], (str, unicode)):
            raise TypeError(
                "Team names must be str or unicode, not %r" % type(tms[0])
                )
        self.__teams = list(tms)

    def getTeams(self):
        return list(self.__teams)

    teams=property(getTeams,setTeams)

# and the code in action...
match1=match()
match1.teams=('us',u'them')

match1.teams[0]=5
print match1.teams

其结果如下:

['us', u'them']

如您所见,更改并没有使其返回到match对象中。在

相关问题 更多 >