miércoles, 23 de diciembre de 2015

Python Idiosyncrasies (I)

I want to post here some Python language characteristics i find different and interesting for anyone coming from more traditional ones such as C. So far i've used them every once and a while in the time i've been coding tools here in Madrid and i intend to do several related posts in the future as i learn new features.

I have to say that this only relates to Python 2.7 which is the version Mayapy 2015 comes with.

Composite conditions

Here we find the two key words: "any" and "all"

Both can receive as input a list of expressions that return a boolean and in turn the result is a boolean

"any" equivalent: "if sentence1 or sentence2 or sentence3.... or sentenceN"

"all" equivalent: "if sentence1 and sentence2 and sentence3... and sentenceN"

This way those complex expressions in the conditional can be reduced in combination with a list comprehension. For example this snippet of code shows how to check if some letters appear in a string:


1:  if any(letter in "somestring" for letter in ['a','b','c','s']):  


would return True whereas:


1:  if all(letter in "somestring" for letter in ['a','b','c','s'])  


would return False. 


Iterating multiple lists (I)

Use here the zip() command as stated here:


1:  for elementA, elementB in zip(listA,listB):  


It is worth noting that the zip command iterates until the last element of the shortest of the lists. Though many times both lists have same length, it might not always be the case. Furthermore, you might encounter the need to iterate until the longest list, returning a predefined value for empty element. There is another command for this from the itertools module:


1:  import itertools  
2:  list1 = ['a1','b1']  
3:  list2 = ['a2','b2','c2']  
4:  for element1, elemen2 in itertools.izip_longest(list1,list2)   


By default empty indices' value are set to 'None'.

What happpens if you want this behaviour but also be able to use the element's index?

There is the "enumerate" command that returns a list's current index and element.


1:  for index,element in enumerate(list1):  


And even more: we can combine iterating through multiple lists with the index of the element. In this case we will have one index and two variables holding each current element like so:


 for same_index, elementA, elementB in enumerate(zip(listA,listB)):  
 


 Iterating multiple lists (II)

What we have seen previously is okay, but there is a better way to do the same things in terms of execution time and memory consumption and it relies again on the itertools module.

Using a context manager i have measured the execution time of both functions hereby:


 def slow():  
          for i, (x,y) in enumerate(zip(range(10000000),range(10000000))):  
              pass  
 def quick():  
          for i, x,y in itertools.izip(itertools.count(), range(10000000),range(10000000)):  
              pass  
 measure(slow)  
 measure(quick)  


 Slow() function took 3.32 seconds whereas quick() took 1.30!! A good reason to take into account the itertools module.

Joining strings

Difference between os.path.join() and str.join() both are similar in behaviour.

os.path.join('path','to','directory')

takes a variable number of string arguments to assemble them all into a string with os.sep (operating system path separator). Note that it won't put an os.sep character at the beginning of the string neither at the end. But, if it's an absolute path you can always set as first argument the os.sep character.

if you have the arguments in a list instead of comma separated you can expand the list into it using the * operator thus this would also work:

os.path.join(*['path','to','directory'] 


 Now the str.join method does take a tuple or list as argument and the 'str' string or character will be the separator thus this:

'-'.join(['a','b','c'])

yields the following string : 'a-b-c'. Note again that there is no '-' at the beginining nor at the end.   

No hay comentarios:

Publicar un comentario