osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Coding technique: distinguish using type or abc?


On 1/8/20 1:40 PM, DL Neil wrote:
> Do you prefer to use isinstance() with type() or to refer to collections.abc?
> 
> 
> This team producing bases statistical analyses for (lesser capable) user-coders 
> to utilise with their own experimental 'control code'; faces situations where a 
> list-parameter is often only one element long. As is so often the way, amongst 
> the 'clients' there are a couple of strong-minded (am not allowed to call them 
> "awkward", or otherwise!) user-coder-analysts, who demand that entry of a 
> single-element not require them to surround it with "unnecessary" 
> square-brackets. Despite complaining, we realise that this is actually quite a 
> good practice, and likely save us (as well as 'them') from interface mistakes.
> 
> Such single elements appear in both string and numeric formats, but for 
> simplicity (here) let's ignore numerics...
> 
> The problem rearing its ugly head, is when the string single-element becomes 
> input to a for-loop. If we loop around a list, then each element is handled 
> individually (as desired). Whereas if the element is a string, then each 
> character is treated as if it were a list-element (not)!
> 
> 
> In Code Review, I noticed that two 'solutions' have been coded.
> 
> 1 using type()s to distinguish:
> 
>  ????def format_as_list( parameter:Union[ str, list ] )->list:
>  ??????? if isinstance( parameter, str ):
>  ??????????? parameter_list = [ parameter ]
>  ??????? elif isinstance( parameter, list ):
>  ??????????? parameter_list = parameter
>  ??????? else:
>  ??????????? raise NotImplementedError
>  ??????? return parameter_list
> 
> 2 using abstract base classes from PSL.collections to distinguish:
> 
>  ????import collections.abc as abc
>  ????def is_list_not_string( parameter:Union[ str, list ] ) -> bool:
>  ??????? return isinstance( parameter, abc.MutableSequence )
> 
>  ????def format_as_list( parameter:str )->list:
>  ??????? if is_list_not_string( parameter ):
>  ??????????? return parameter
>  ??????? else:
>  ??????????? return [ parameter, ]
> 
> (ignoring implicit assumption/error!)
> NB I've simplified the code and attempted to harmonise the varNMs between snippets.
> 
> With our preference for EAFP, I went looking for a way to utilise an exception 
> by way of distinguishing between the input-types - but couldn't see how, without 
> major artifice (false/purposeless construct which would confuse the next reader 
> of the code). That said, I'm wondering if using (or appearing to use) tuples and 
> *args might solve the problem - but will have to dig back through the code-base...
> 
> 
> Meantime, faced with such a challenge, would you recommend utilising one of 
> these ideas over the other, or perhaps some other solution?
> 
> Are there perhaps circumstances where you would use one solution, and others the 
> other?
> 

I try to avoid making assumptions, so I wind up with a lot of

if isinstance(parameter, str):
   plist = [parameter]
else:
   try:
     plist = list(parameter)
   except TypeError:
     plist = [parameter]

Any iterable gets listified unless it's a string, which gets treated the same 
way a non-iterable does.  EAFP.