On 10/31/07, Kent Johnson <[EMAIL PROTECTED]> wrote: > > Aditya Lal wrote: > > On 10/29/07, *Kent Johnson* <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>> > wrote: > > > - Common Python practice is to prefer the least restrictive type > check > > possible. > > > I completely agree that the check " type(n) == int " is very intuitive > > and simple. Its just that there are many more types that the basic ones > > and 'types' module provide a "consistent" way for checking for types. > > Yes, for some types it is easiest to import types and use its > definitions. Whether to use types.IntegerType or int is a matter of > preference, I suppose. > > As > > an example - consider a function : > > > > def execMyFun( f ) : > > if type(f) == types.GeneratorType : > > return f.next() > > elif type(f) == types.FunctionType : > > return f() > > else : > > raise Exception("Invalid type for f : " + type(f) ) > > > > Here types module came to the rescue which otherwise I would have > > written using exception handling. /Well ! if you have a cleaner solution > > do let me know./ > > You probably should write this using exception handling. The least > restrictive type check is to check for the specific operations you need, > rather that checking for a type that supports the operation. This can be > done with preflight checks - known as Look Before You Leap - or by > trying an operation and catching exceptions in case of failure, known as > Easier to Ask Forgiveness than Permission. > > In this case, it seems that if f implements the iterator protocol then > you want the next item and if f is callable then you want to just call > it. In both cases checking for specific operations or trying the > operation and catching any exception will allow a wider range of > parameters. For example, next() is meaningful for generators, iterators > on built-in types, user-defined iterators (defined with classes). > In [129]: import types > In [130]: i=iter([1]) > In [131]: type(i) > Out[131]: <type 'listiterator'> > In [132]: type(i)==types.GeneratorType > Out[132]: False > In [133]: isinstance(i, types.GeneratorType) > Out[133]: False > In [134]: i.next > Out[134]: <method-wrapper 'next' of listiterator object at 0x20d0050> > > Function call is valid for functions, bound methods, and instances of > any class that defines a __call__() method. > > Here is a less restrictive LBYL implementation of your function: > def execMyFun( f ) : > if hasattr(f, 'next') and callable(f.next): > return f.next() > elif callable(f): > return f() > else : > raise Exception("Invalid type for f : " + type(f) ) > > Here in an EAFP implementation: > def execMyFun( f ) : > try: > return f.next() > except AttributeError: > pass > > try: > return f() > except TypeError: > pass > raise Exception("Invalid type for f : " + type(f) ) > > I think I prefer the LBYL version here, it allows the same values for f > and it won't hide AttributeErrors and TypeErrors raised by calling > f.next() or f(). > > Finally you should probably raise TypeError which is "raised when an > operation or function is applied to an object of inappropriate type." > > Kent > > Hey! I really liked LBYL version ... it matches exactly what I intended. And yeah! I should raise TypeError instead of Exception. Thanx :)
-- Aditya
_______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor