Python_Tips & Tricks

Embed Size (px)

Citation preview

  • 8/3/2019 Python_Tips & Tricks

    1/45

    Python: Tips & Tricks

    Prashant SinghNHST

  • 8/3/2019 Python_Tips & Tricks

    2/45

    Agenda

    The main purpose of this presentation is to make audience

    familiar with some python tips and tricks that includes

    some shorthand's for common tasks in programming &

    miscellaneous topic.

  • 8/3/2019 Python_Tips & Tricks

    3/45

    Quick Tricks

    Python provides various in-build data structures for easing up programming .

    Most common are:-

    1. List2. Set

    3. Dictionary

    4. Touple

  • 8/3/2019 Python_Tips & Tricks

    4/45

    Four Kinds ofQuotes

    Let's start with something quick that you probably know. If you'recoming from a different language, you're probably used to using singlequotes for one thing and double quotes for another. Python lets youuse both, although not interchangeably (if you start with one, you haveto end with the same one). Python also has a two more types of quotes.

    A triple

    quote,

    ''',is cr

    eat

    ed by typing thr

    eesingl

    equot

    es. A tripl

    e-double quote, """, is created by typing three double quotes. So, you canhave several layers of quoting before you need to worry about escapingyour quotes. For example, this is valid Python:

    print """I wish that I'd never heard him say, '''She said, "He said, 'Give me fivedollars'"'''"""

  • 8/3/2019 Python_Tips & Tricks

    5/45

    Truthfulness of VariousObjects

    Python types are false if empty, and true if not. That means you don'thave to check, for example, that the length of a string, tuple, list, or dictis 0 or is equal to an empty one. It is enough to just check the

    truthfulness of th

    eobj

    ect.

    As you would expect, the number zero is also false, while all othernumbers are true.

    For example, the following expressions areequivalent. Here,

    'my_object' is a string, but it could easily be another Python type (withappropriate modifications to theequality test)

  • 8/3/2019 Python_Tips & Tricks

    6/45

    In conclusion, there's really no need to check lengths or equality ifyou're only interested in if the object is empty or not.

    my_object = 'Test' # Trueexample

    # my_object = '' # Falseexample

    if len(my_object) > 0:print 'my_object is not empty

    if len(my_object): # 0 willevaluateto Falseprint 'my object is not empty

    if my_object != '':print 'my_object is not empty

    if my_object: # anemptystring willevaluateto Falseprint 'my_object is not empty'

  • 8/3/2019 Python_Tips & Tricks

    7/45

    Checking if a StringContainsa Substring

    Here's a quick hint that might be obvious, but it took me about a yearof Python programming to figure it out.You probably know that you can test if a list, tuple, or dict contains an

    item by testing theexpression 'item in list' or 'item not in list'. I neverrealized that this would work for strings as well. I was always writingcode like:

    string = 'Hi there' # Trueexample# string = 'Goodbye' # Falseexample

    if string.find('Hi') != -1:print 'Success!'

  • 8/3/2019 Python_Tips & Tricks

    8/45

    That's some ugly code. It is completely equivalent to do'if substring in string':

    Much cleaner and simpler.Might be obvious to 99% of thepopulation, but I wish I'd known about it sooner.

    string = 'Hi there' # Trueexample# string = 'Goodbye' # Falseexample

    if 'Hi' in string:

    print 'Success!'

  • 8/3/2019 Python_Tips & Tricks

    9/45

    Printing a List

    Lists don't print nicely. It's of course obvious what the list is, but anaverage user doesn't want to see brackets around everything. There's atrivial solution to this, using a string's 'join' method:

    Thejoin method turns the list into a string by casting each item into astring and connecting them with the string that join was called on. It'seven smart enough to not put one after the last element.

    As an added advantage, this is pretty fast, running in linear time.Don't evercreate a string by '+'ing list items together in a for loop: not

    only is it ugly, but it takes much longer.

    recent_presidents = ['George Bush', 'Bill Clinton', 'George W. Bush']

    print 'The three most recent presidents were: %s.' % ', '.join(recent_presidents)

    #prints 'Thethreemost recentpresidents were: George Bush, Bill Clinton, George W.Bush.

  • 8/3/2019 Python_Tips & Tricks

    10/45

    Integer vs. Float Division

    By default, if you divide one integer by another, the result will betruncated into an integer. For example,executing 5/2 returns 2.

    There are two was to fix this. The first and simplest way is to just turnone of the integers into a float. If the values are static, you can justappend a .0 to one to make it a float: 5.0/2 returns 2.5. Alternatively,you can just cast one of the values: float(5) / 2 returns 2.5.

  • 8/3/2019 Python_Tips & Tricks

    11/45

    The other way will result in cleaner code, but you must make surenone of your code is relying on this truncation. You can do a from__future__ import division to change Python to always return a float as

    the result of a division. After such an import, 5/2 will return 2.5. If youstill need to use the truncating integer division somewhere, you canthen use the // operator: 5//2 will always return 2.

    Note : - At some point float division will be the default. If you wantyour code to be future-proof, use the // operator if you want truncating

    division, no matter if you are doing a from __future__ importdivision or not.

    5/2 # Returns 25.0/2 # Returns 2.5float(5)/2 # Returns 2.55//2 # Returns 2

    from __future__import division5/2 # Returns 2.55.0/2 # Returns 2.5float(5)/2 # Returns 2.55//2 # Returns 2

  • 8/3/2019 Python_Tips & Tricks

    12/45

    Lambda Functions

    Sometimes you need to pass a function as an argument, or you wantto do a short but complex operation multiple times. You could defineyour function the normal way, or you could make a lambda function, amini-function that returns the result of a singleexpression. The twodefinitions are completely identical:

    The advantage of the lambda function is that it is in itself anexpression, and can be used inside another statement. Here's anexample using the map function, which calls a function on every

    element in a list, and returns a list of the results. (I make a good casebelow in List Comprehensions that map is pretty useless. It does,however, presents a good one lineexample.)

    def add(a,b): return a+b

    add2 = lambda a,b: a+b

    squares = map(lambda a: a*a, [1,2,3,4,5])# squares isnow [1,4,9,16,25]

  • 8/3/2019 Python_Tips & Tricks

    13/45

    Lists

    List Comprehensions

    If you've used Python for very long, you've at least heard of listcomprehensions. They're a way to fit a for loop, an if statement, and anassignment all in one line. In other words, you can map and filtera listin oneexpression.

  • 8/3/2019 Python_Tips & Tricks

    14/45

    Mapping the ListWe'll start with something really simple. Say you're trying to square

    every element in a list. A freshly-initiated Python programmer mightwrite code like this:

    You'veeffectively 'mapped' one list to another list. You could also use

    the

    map function,and do som

    ething lik

    ethis:

    numbers = [1,2,3,4,5]squares = []for number in numbers:

    squares.append(number*number)# Now, squaresshould have [1,4,9,16,25]

    numbers = [1,2,3,4,5]squares = map(lambda x: x*x, numbers)# Now, squaresshould have [1,4,9,16,25]

  • 8/3/2019 Python_Tips & Tricks

    15/45

    This code is definitely shorter (1 line instead of 3) but it's pretty ugly.It's hard to tell at a glance what the map function does (it accepts a

    function and a list, and applies the function to every element of thatlist). Plus, you have to give it a function of some sort which looks kindof messy. If only there were a cleaner way... perhaps a listcomprehension:

    This does theexact same thing as the previous two examples, but it's

    short (unlike the first example) and clean (unlike the second example).No one is going to have any problem determining what it does,even ifthey don't know Python.

    numbers = [1,2,3,4,5]squares = [number*number for number in numbers]# Now, squaresshould have [1,4,9,16,25]

  • 8/3/2019 Python_Tips & Tricks

    16/45

    Filtering the ListWhat if you're more interested in filtering the list? Say you want to

    removeevery element with a valueequal to or greater than 4? (Okay,so theexamples aren't very realistic. Whatever...) A Python neophytemight write:

    Pretty simple, right? But it took 4 lines, two degrees of nesting, and anappend to do something completely trivial. You could reduce the size ofthe code with the filter function:

    numbers = [1,2,3,4,5]numbers_under_4 = []for number in numbers:

    if number < 4:numbers_under_4.append(number)

    # Now, numbers_under_4 contains [1,4,3]

  • 8/3/2019 Python_Tips & Tricks

    17/45

    Similar to the map function we talked about above, this reduces codesize but is really ugly. What the hell is going on?Like map, filter accepts a function and a list. It evaluates for every list

    element and if the function evaluates to true, that list element isincluded in the final list. Of course, we can do this with a listcomprehension as well:

    Again, using a list comprehension gives us shorter, cleaner, and easierto understand code.

    numbers = [1,2,3,4,5]numbers_under_4 = filter(lambda x: x < 4, numbers)

    # Now, numbers_under_4 contains [1,2,3]

    numbers = [1,2,3,4,5]

    numbers_under_4 = [number fo

    r number in numbers if number < 4]# Now, numbers_under_4 contains [1,2,3]

  • 8/3/2019 Python_Tips & Tricks

    18/45

    Map and Filter at Once

    Now we get to the true power of list comprehensions. If I haven't yetconvinced you that map and filter are generally a waste of your time,hopefully this will.Say I want to map and filter a list at the same time. In other words, I'dlike to see the square of each element in the list where said element isunder 4. Once more, the Python neophyte way:

    The code is starting to expand in the horizontal direction now! Alas,what could we possibly do to simplify the code? We could tryusing map and filter, but I don't have a good feeling about this...

    numbers = [1,2,3,4,5]squares = []for number in numbers:

    if number < 4:squares.append(number*number)

    # squares isnow [1,4,3]

  • 8/3/2019 Python_Tips & Tricks

    19/45

  • 8/3/2019 Python_Tips & Tricks

    20/45

    Nested 'for' Statements

    List comprehensions and generator expressions can be used for morethan just mapping and filtering; you can create rather complex lists oflists with them . Not only can you map and filter, you can nest the forexpressions. A python neophyte might write something like:

    You can see that this code is pretty crazy. With a list comprehension,though, you can do this more quickly:

    for xin (0,1,2,3):for y in (0,1,2,3):

    if x < y:print (x, y,x*y),

    #prints (0, 1, 0) (0, 2, 0) (0, 3, 0) (1, 2, 2) (1, 3, 3) (2, 3, 6)

  • 8/3/2019 Python_Tips & Tricks

    21/45

    As you can see, this code iterates over four values of y, and for each ofthose values, iterates over four values of x and then filters and maps.Each list item then, is itself a list of x, y,x * y.

    print [(x, y,x * y)for xin (0,1,2,3)for y in (0,1,2,3)if x < y]

    #prints [(0, 1, 0), (0, 2, 0), (0, 3, 0), (1, 2, 2), (1, 3, 3), (2, 3, 6)]

  • 8/3/2019 Python_Tips & Tricks

    22/45

    Reducing a ListFor example, maybe you want find the product of all of the values in alist. You could make a for loop:

    Or you could use the built-in function reduce, which accepts afunction that takes two arguments, and a list:

    numbers = [1,2,3,4,5]result = 1for number in numbers:

    result *= number# result isnow 120

    numbers = [1,2,3,4,5]result = reduce(lambda a,b: a*b, numbers)# result isnow 120

  • 8/3/2019 Python_Tips & Tricks

    23/45

    Iterating over a List: range,xrange and enumerate

    Remember (or maybe not) when you programmed in C, and for loopscounted through index numbers instead of elements? You probablyalready know how to replicate this behavior in Python,using range or xrange.

    The problem here is that usually you end up needing the list elementsanyways. What's the use of just having the index values? Python has areally awesome built-in function called enumerate that will giveyou both.enumerate-ing a list will return an iteratorof index, value pairs:

    strings = ['a', 'b', 'c', 'd', 'e']for indexin xrange(len(strings)):

    print index,#prints '0 1 2 3 4'

  • 8/3/2019 Python_Tips & Tricks

    24/45

    As an added advantage, enumerate is quite a bit cleaner and morereadable than xrange(len()). Because of this, range and xrange are

    probably only useful if you need to create a list of values from scratchfor some reason, instead of from an existing list.

    strings = ['a', 'b', 'c', 'd', 'e']for index, string in enumerate(strings):

    print index, string,#prints '0 a 1 b 2 c 3 d 4 e'

  • 8/3/2019 Python_Tips & Tricks

    25/45

    Checking a Condition on Anyor Every List Element

    Say you want to check to see if any element in a list satisfies acondition (say, it's below 10). Before Python 2.5, you could dosomething like this:

    If none of theelements satisfy the condition, the list comprehensionwill create an empty list which evaluates as false. Otherwise, a non-empty list will be created, which evaluates as true. Strictly, you don'tneed to evaluateevery item in the list.

    numbers = [1,10,100,1000,10000]if [number for number in numbers if number < 10]:

    print 'At least oneelement is over 10# Output: 'Atleastoneelement isover 10'

  • 8/3/2019 Python_Tips & Tricks

    26/45

    The generator expression only computes these values as they areneeded, and any only requests the values it needs.

    Similarly, you can check if every element satisfies a condition. WithoutPython 2.5, you'll have to do something like this:

    With Python 2.5, there's of course an easier way. This method worksjust like the any method described above.

    numbers = [1,10,100,1000,10000]if any(number < 10 for number in numbers):print 'Success

    # Output: 'Success!'

    numbers = [1,2,3,4,5,6,7,8,9]if len(numbers) == len([number for number in numbers if number < 10]):

    print 'Success!# Output: 'Success!'

    numbers = [1,2,3,4,5,6,7,8,9]if all(number < 10 for number in numbers):

    print 'Success!

    # Output: 'Success!'

  • 8/3/2019 Python_Tips & Tricks

    27/45

    CombiningMultiple Lists,Item by Item

    The built-in zip function can be used, well, to zip lists together. Itreturns a list of tuples, where the nth tuple contains the nth item fromeach of the passed in lists. This might be a case where an example is thebest explanation:

    Often you'll use this sort of thing as the iterator a for loop, pulling outall three values at once ('for letter, number, squares in zipped_list').

    letters = ['a', 'b', 'c']numbers = [1, 2,3]squares = [1,4, 9]

    zipped_list = zip(letters, numbers, squares)

    # zipped_listcontains [('a', 1, 1), ('b', 2, 4), ('c', 3, 9)]

  • 8/3/2019 Python_Tips & Tricks

    28/45

    Advanced Logic With Sets

    The most common thing I want to do is to make sure my list isunique. This is easy; I just have to convert it to a set and check if thelength is the same:

    Of course, you can convert the set back into a list, but remember thatordering is not preserved.

    numbers = [1,2,3,3,4,1]

    set(numbers)# returnsset([1,2,3,4])

    if len(numbers) == len(set(numbers)):print 'List is unique!

    # Inthiscase, doesn'tprintanything

  • 8/3/2019 Python_Tips & Tricks

    29/45

    Dictionaries

    Constructing Dictionaries with KeywordArgumentsThis might be a bit cleaner than a 'regular' dictionary creationdepending on your code; there are less quotes floating around. I use itoften.

    dict(a=1, b=2, c=3)

    # returns {'a': 1, 'b': 2, 'c': 3}

  • 8/3/2019 Python_Tips & Tricks

    30/45

    Dicts to Lists

    To preserve both keys and values, you can turn a dict into a list oriterator of 2-item tuples by using .items() or .iteritems(). This issomething that you'll probably do a lot, and isn't very exciting:

    Lists to DictsYou can reverse the process, turning a list of 2-element lists or tuplesinto a dict:

    dictionary = {'a': 1, 'b': 2, 'c': 3}dict_as_list = dictionary.items()

    #dict_as_list now contains [('a', 1), ('b', 2), ('c', 3)]

    dict_as_list = [['a',1], ['b', 2], ['c',3]]dictionary = dict(dict_as_list, d=4,e=5)# dictionarynow contains {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

  • 8/3/2019 Python_Tips & Tricks

    31/45

    You can also combine this with the 'keyword arguments method of

    creating a dictionary discussed above:

    Being able to convert a dict to a list is kind of handy, I guess. But whatreally makes it awesome is the next trick.

    dict_as_list = [['a',1], ['b', 2], ['c',3]]dictionary = dict(dict_as_list, d=4,e=5)# dictionarynow contains {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

  • 8/3/2019 Python_Tips & Tricks

    32/45

    'Dictionary Comprehensions

    For example, say I have a dictionary of name:email pairs, and I want tocreate a dictionary of name:is_email_at_a_dot_com pairs:

    Damn straight. Of course, you don't have to start and end with a dict,you can throw some lists in there too.

    While this is a little less readable than a straight list comprehension,I'd argue it's still better than a massive for loop.

    emails = {'Dick': '[email protected]', 'Jane': '[email protected]', 'Stou':'[email protected]'}

    email_at_dotcom = dict( [name, '.com' in email] for name,email inemails.iteritems())

    # email_at_dotcomnow is {'Dick': True, 'Jane': True, 'Stou': False}

  • 8/3/2019 Python_Tips & Tricks

    33/45

    Functions

    Default Argument Values are Only Evaluated OnceLet's start this section with a warning. Here's a problem that hasconfused many new Python writers, including myself, repeatedly,evenafter I figured out the problem... It's easy to be stupid about this

    def function(item, stuff = []):stuff.append(item)print stuff

    function(1)#prints '[1]

    function(2)#prints '[1,2]' !!!

  • 8/3/2019 Python_Tips & Tricks

    34/45

    The default value for a function argument is only evaluated once,when the function is defined. Python simply assigns this value to thecorrect variable name when the function is called.The solution: don't use mutable objects as function defaults. Youmight be able to get away with it if you don't modify them, but it's stillnot a good idea.A better way to write the above code would be:

    def function(item, stuff = None):if stuff is None:

    stuff = []stuff.append(item)print stuff

    function(1)#prints '[1]

    function(2)#prints '[2]', asexpected

  • 8/3/2019 Python_Tips & Tricks

    35/45

    Passing keyword and non-keyword Argument

    Passing both arbitrary non-keyword arguments and named (non-arbitrary) keyword arguments in one function isseemingly impossible. This is because named keyword argumentsmust be defined before the '*' parameter in the function definition, and

    are filled before that parameter is filled. For example, imagine afunction:

    We now have a problem: there is no way to specify 'actually_print' as anamed keyword argument while simultaneously providing arbitrarynon-keyword arguments. Both of the following will error:

    def do_something(a, b, c, actually_print = True, *args):if actually_print:

    print a, b, c, args

  • 8/3/2019 Python_Tips & Tricks

    36/45

    The only way to pass 'actually_print' in this situation is to pass it as anon-keyword argument:

    do_something(1, 2,3,4, 5, actually_print = True)

    # actually_print is initiallysetto 4 (see why?) andthen re-set,# causinga TypeError ('gotmultiplevaluesforkeywordargument')

    do_something(1, 2,3, actually_print = True,4, 5,6)

    # This isnotallowedaskeywordargumentsmaynotprecedenon-keywordarguments. A SyntaxError is raised.

    do_something(1, 2,3, True,4, 5,6)

    # Result is '1, 2, 3, (4, 5, 6)'

  • 8/3/2019 Python_Tips & Tricks

    37/45

    Passing a List or Dictionaryas Arguments

    Since you can receive arguments as a list or dictionary, it's not terriblysurprising, I suppose, that you can send arguments to a function from alist or dictionary. The syntax is exactly the same as above.

    To send a list as non-keyword arguments, just pre pend it with a '*':

    And, of course, to send a dictionary as keyword arguments (this isprobably more common), prepend it with '**':

    args = [5,2]pow(*args)

    # returnspow(5,2), meaning 5^2 which is 25

  • 8/3/2019 Python_Tips & Tricks

    38/45

    def do_something(actually_do_something=True,

    print_a_bunch_of_numbers=False):if actually_do_something:print 'Something has been doneif print_a_bunch_of_numbers:

    print range(10)

    kwargs = {'actually_do_something': True, 'print_a_bunch_of_numbers': True}do_something(**kwargs)

    #prints 'Something hasbeendone', then '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'

  • 8/3/2019 Python_Tips & Tricks

    39/45

    DecoratorsA decorator is a function that wraps another function: the main

    function is called and its return value is passed to the decorator. Thedecorator then returns a function that replaces the wrapped function asfar as the rest of the program is concerned.

    def decorator1(func):return lambda: func() + 1

    def decorator2(func):def print_func():

    print func()return print_func

    @decorator2

    @decorator1def function():

    return 41

    function()#prints '42'

  • 8/3/2019 Python_Tips & Tricks

    40/45

    This example does theexact same thing, but more verbosely andwithout decorators:

    def decorator1(func):return lambda: func() + 1

    def decorator2(func):def print_func():

    print func()return print_func

    def function():return 41

    function = decorator2(decorator1(function))

    function()#prints '42'

  • 8/3/2019 Python_Tips & Tricks

    41/45

    'Switch Statements' using

    Dictionaries ofFunctionsFor example, say you're handling keystrokes and you need to call a

    different function for each keystroke. Also say you've already definedthese three functions:

    def key_1_pressed():

    print 'Key 1 Pressed

    def key_2_pressed():print 'Key 2 Pressed

    def key_3_pressed():

    print 'Key 3 Pressed

    def unknown_key_pressed():print 'Unknown Key

    Pressed'

    keycode = 2if keycode == 1:

    key_1_pressed()elif keycode == 2:

    key_2_pressed()elif number == 3:

    key_3_pressed()else:unknown_key_pressed()

    #prints 'Key 2 Pressed'

  • 8/3/2019 Python_Tips & Tricks

    42/45

    But you could also throw all the functions in a dictionary, and keythem to the value you're switching on. You could even check see if the

    key exists and run some code if it doesn't:

    You can see that this could be a lot cleaner than the elif example for

    large numbers of functions.

    keycode = 2

    functions = {1: key_1_pressed, 2: key_2_pressed,3: key_3_pressed}

    functions.get(keycode, unknown_key_pressed)()

  • 8/3/2019 Python_Tips & Tricks

    43/45

    ClassesPassing 'self'ManuallyMethods are just regular functions that when called from an instanceare passed that instance as the first argument (usually called 'self'). If forsome reason you're not calling the function from an instance, you canalways pass the instance manually as the first argument. For example:

    class Class:def a_method(self):

    print 'Hey a method'

    instance = Class()

    instance.a_method()#prints 'Heyamethod', somewhat unsuprisingly. You canalsodo:

    Class.a_method(instance)#prints 'Heyamethod'

  • 8/3/2019 Python_Tips & Tricks

    44/45

  • 8/3/2019 Python_Tips & Tricks

    45/45

    Thank You !