I'm new to python and I would like some help. I created some classes with properties in order to keep me from passing meaningless arguments.
So for example I have this class
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)
If I write
match1=match()
match1.teams=(2,4)
I get an exception as I should, but
match1.teams[0]=5
does not raise an exception and passes the number 5. Please keep in mind that this is not all of the class, I just wrote down only what is relative to my question, so assume that the code behaves as I describe.
I guess this is because everything is passed by reference in python but I have to be careful not to assign meaningless data to my objects which defeats the purpose of having properties in the first place.
So, is there a way to fix that apart from not using lists or do I have to learn to live with it?
This error isn't because you are failing some typecheck.
Unless you have misrepresented your code (it's obviously edited, as what you posted won't run correctly), this is happening because match1.teams[0]
calls your getTeams
function, not your setTeams
function. To see this for yourself, try this exercise:
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)
When I try this, I get the following:
>>> 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
Python and type checks don't go together. Learn to live with it. It's the job of whoever uses the code to pass the proper types. Document what your code expects, but don't check it explicitly.
There are other collections than lists and tuples. Why would you forbid, say, namedtuple? Python is a dynamic language, don't fight it by writing type checks.
Look up EAFP in the Python glossary. Don't try to anticipate errors; deal with them as they happen.
A reasonable thing you might do instead of type checking is converting to a list:
self.__teams = list(tms)
List-incompatible types will cause an exception to be raised on this line, and from now on you can be sure you're dealing with a list. (It won't prevent someone from assigning non-strings to the list, of course.)
Oh, and if you ever (with good reason!) need a type check, use the isinstance function instead of comparing the type()
. That will also catch subclasses of whatever your required type is. And more, try to use the most general base type you can. The proper way to test for a string (Unicode or otherwise) is:
if isinstance(my_object, basestring):
....
And the proper way to check for a list-like collection – not just a narrow-minded “list or tuple” – is:
import collections
if isinstance(my_object, collections.Sequence):
...
But that was just an aside, not the proper solution to your problem. Don't do type checking without good reason.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With