Optional args have little to do with polymorphism (and don't even need you to have classes around!-) -- it's just (main use!) that often you have "rarely needed" arguments for choices that are generally made in a certain way, but it might be useful for the caller to set differently.
For example, consider built-in open
. Most often, you open text files rather than binary opens, you open them for reading rather than for writing, and you're happy with the default buffering -- so, you just open('thefile.txt')
and live happily ever after. Being able to specify the way in which you want to open (binary, for overwrite, for append, ...) as the second (optional) argument, instead of its default 'r'
value, is of course often useful. Once in a blue moon you want a file object with peculiar buffering options, and then having the buffering as the third (optional) argument (with a default value of course) pays big dividends... without it being in your way for the vast majority of the files you open!
Inheritance and polymorphism would not really help one bit in getting the convenience of with open('blah.txt') as f:
so concisely, while still allowing the same built-in function to serve many more use cases (e.g., when you need to open a file for binary append without any buffering... maybe once a year if you code a lot;-). And of course the convenience principles that apply to such built-in functions apply to the functions you write just as well!-)