KraftDiner wrote: > c = [a, b] > for c in [a,b]: > c.getName() > > but when does baseClass ever get used? > Why did i even have to define it? >
One reason for using base classes are for logical reasons. Oranges and Apples are different, but they are both fruits. Python has both unicode strings and 8-bit ASCII strings. Both are strings and share a common base class: the 'basestring' class. A second reason is for code sharing. Let's say Python's string class does everything you want already... except for one little thing. You want the split method to return a list with some extra information. Why re-invent the wheel trying to implement the other string methods when you can reuse everything that's already been done? >>> class MyString(str): ... def split(self): ... "Perform some extra work this version of split" ... wordList = str.split(self) # Call the original method ... return ['Extra'] + wordList + ['Information'] # Do additional work! ... >>> In Python, we often rely on duck typing. "If it looks like a duck, quacks like a duck, it's a duck." If we can treat it like a string, we can consider it a string. If we can't treat it like a string, Python will let us know by raising an exception. We can catch this exception and try something different, or let the exception stop the program and let the user know something went wrong. Duck typing allows us to re-use code very efficiently. I'll demonstrate it with a function and the class defined above. >>> def GetWords(stringValue): ... "Print the list of words in a string" ... print 'Words are: %s' % stringValue.split() ... >>> stringValue = str('Hello, world!') >>> unicodeValue = unicode('These are different strings') >>> myStringValue = MyString('good, hopefully useful') >>> >>> GetWords(stringValue) Words are: ['Hello,', 'world!'] >>> GetWords(unicodeValue) Words are: [u'These', u'are', u'different', u'strings'] >>> GetWords(myStringValue) Words are: ['Extra', 'good,', 'hopefully', 'useful', 'Information'] >>> As shown above, the GetWords() function works fine with my new string class. Any methods that I didn't redefine keep their old behavior. For example, I didn't define the upper() method in MyString, but I can still use it: >>> stringValue.upper() 'HELLO, WORLD!' >>> myStringValue.upper() 'GOOD, HOPEFULLY USEFUL' >>> While we rely on duck typing in Python, we occassionally want special behavior for certain types of data. Currently, you can pass anything into the GetWords() function that has a method named 'split'. It does not have to be a string: >>> class NotAString(object): ... def split(self): ... return 'I am not a string!' ... >>> otherDataValue = NotAString() >>> GetWords(otherDataValue) Words are: I am not a string! >>> Sometimes, we want some specialized behavior. Lists, tuples, and strings all act like sequences (meaning, you can get their length and use them in for-loops). Often, though, you'll want to treat strings differently. You can check the type directly, or you can check by using the isinstance() built-in function. isinstance() checks to see if a variable is an instance of a class or any of its subclasses. Remember the first reason given, of using a base class to logically organize other classes? This is it in practice. I'll demonstrate below: >>> def CheckOnlyBuiltinStrings(stringValue): ... "Tells us whether or not stringValue is a str or unicode string." ... if type(stringValue) is str or type(stringValue) is unicode: ... print 'A built-in string type: %s' % stringValue ... else: ... print 'Not a built-in string type: %s' % stringValue ... >>> def CheckAllStrings(stringValue): ... "Tells us whether or not stringValue is a string." ... # The basestring class is a superclass for all string classes. ... if isinstance(stringValue, basestring): ... print 'Is a string: %s' % stringValue ... else: ... print 'Not a string: %s' % stringValue ... >>> CheckOnlyBuiltinStrings(stringValue) A built-in string type: Hello, world! >>> CheckOnlyBuiltinStrings(unicodeValue) A built-in string type: These are different strings >>> CheckOnlyBuiltinStrings(myStringValue) Not a built-in string type: good, hopefully useful >>> >>> CheckAllStrings(stringValue) Is a string: Hello, world! >>> CheckAllStrings(unicodeValue) Is a string: These are different strings >>> CheckAllStrings(myStringValue) Is a string: good, hopefully useful >>> CheckAllStrings(42) Not a string: 42 >>> How do you know when you should use type() checks, when you should use isinstance(), and when you should just try to use the data? That depends, and there have been many lively debates on this subject in the newsgroup. I recommend that you should only use as much type checking as needed, and the less is better. A bit long, but I hope this helps you out. --Jason -- http://mail.python.org/mailman/listinfo/python-list