[Tutor] question re type()

Aditya Lal aditya.n.lal at gmail.com
Thu Nov 1 07:23:42 CET 2007


On 10/31/07, Kent Johnson <kent37 at tds.net> wrote:
>
> Aditya Lal wrote:
> > On 10/29/07, *Kent Johnson* <kent37 at tds.net <mailto:kent37 at tds.net>>
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20071101/fca76332/attachment-0001.htm 


More information about the Tutor mailing list