我是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)
如果我写
match1=match()
match1.teams=(2,4)
我得到了一个例外,但是
match1.teams[0]=5
不会引发异常并传递数字5.请记住,这不是全部类,我只记下了与我的问题相关的内容,所以假设代码的行为和我描述的一样。 / p>
我想这是因为所有内容都是通过python中的引用传递的,但是我必须注意不要将无意义的数据分配给我的对象,否则就会失去首先拥有属性的目的。
那么,有没有办法解决这个问题,除了不使用列表,还是我必须学会使用它?
答案 0 :(得分:5)
这个错误并不是因为你的某些类型检查失败了。
除非你歪曲了你的代码(显然已编辑,因为你发布的内容无法正常运行),这种情况正在发生,因为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)
当我尝试这个时,我得到以下内容:
>>> match1 = match()
>>> match1.teams[0]=5
in get
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> match1.teams = ["team1","team2"]
in set
>>> match1.teams[0]=5
in get
答案 1 :(得分:4)
Python和类型检查不会一起使用。学会与之共存。这是使用代码传递正确类型的人的工作。记录您的代码所期望的内容,但不要明确检查它。
除了列表和元组之外还有其他集合。你为什么要禁止,namedtuple? Python是一种动态语言,不要通过编写类型检查来对抗它。
在Python词汇表中查找EAFP。不要试图预测错误;当它们发生时处理它们。
你可以做的合理的事情而不是类型检查是转换为列表:
self.__teams = list(tms)
列表不兼容的类型将导致在此行引发异常,从现在开始,您可以确定您正在处理列表。 (当然,它不会阻止某人将非字符串分配给列表。)
哦,如果您(有充分理由!)需要进行类型检查,请使用isinstance函数,而不是比较type()
。这也将捕获您所需类型的子类。而且,尝试使用最常用的基本类型。测试字符串(Unicode或其他)的正确方法是:
if isinstance(my_object, basestring):
....
检查列表式集合的正确方法 - 不仅仅是一个狭隘的“列表或元组” - 是:
import collections
if isinstance(my_object, collections.Sequence):
...
但这只是一个旁边,而不是你问题的正确解决方案。没有充分理由不要进行类型检查。
答案 2 :(得分:2)
property
的一个优点是能够进行数据验证 - 有时确保获得非常具体的内容非常重要。
在您的情况下,您需要做以下两件事之一:
teams
数据存储在无法修改的结构中,例如tuple
或namedtuple
;然后,当检索数据时,无法更改或
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)
当你在获得值后尝试分配时,会发生这种情况:
Traceback (most recent call last):
File "test.py", line 22, in <module>
match1.teams[0]=5
TypeError: 'tuple' object does not support item assignment
第二个解决方案(返回副本而不是原始副本)如下所示:
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
对象中。