CS150 - Fall 2013 - Class 16

  • quiz!

  • modifying things during iteration
       - what happens if we had done:

          def filter_dict(my_dict, number):
             for key in my_dict:
                if my_dict[key] <= number:
                   del my_dict[key]

          - if we do find an entry to delete, we will get an exception:
             Traceback (most recent call last):
              File "/Applications/WingIDE.app/Contents/MacOS/src/debug/tserver/_sandbox.py", line 1, in <module>
              # Used internally for debug sandbox under external interpreter
              File "/Applications/WingIDE.app/Contents/MacOS/src/debug/tserver/_sandbox.py", line 2, in filter_dict
              if __name__ == '__main__':
             RuntimeError: dictionary changed size during iteration
       - what happens if we type the following:
          >>> x = [4, 3, 2, 1]
          >>> for val in x:
          >>> ...   x.sort()
          >>> ... print val
          >>> ...
          4
          2
          3
          4

       - bottom line: generally not a good idea to do certain types of modifications to an object when you're iterating over it

  • admin
       - midterm
          - average and median: ~48 (average ~88% and median ~89%)

  • course feedback
       - Thanks!
       - If you every have feedback, etc., feel free to let me know
       - Summary stats
       - A few comments:
          - pair programming
          - more challenges/additional problems
          - more pop quizzes?

  • modules
       - what is a module?
          - a collection of related functions and variables
       - why do we have modules?
          - to avoid collisions with names
          - for efficiency, since sometimes we won't need some functionalities

  • writing your own modules
       - any guesses as to how we write our own module?
          - just put some functions, etc. in a .py file
          - everything we've written so far has technically been a module!
       - every time you write code in a .py file you're creating a new module

  • look at my_module.py in Modules code
       - I have written a variable and three functions in a file called my_module.py
       - This defines a new module:
       
          >>> import my_module
          >>> my_module.a()
          10
          >>> my_module.b(10, 15)
          25
          >>> my_module.c("this is a test")
          'tt'
          >>> my_module.SOME_CONSTANT
          10
       - look at my_module_user.py in modules code
          - we can then use this module just like any other module
          - here we:
             - import my_module
             - call the functions in my_module

  • documentation for a module
       - what do you think that string at the top of the module is?
          - docstring for the module!
       
          >>> import my_module
          >>> help(my_module)
          Help on module my_module:

          NAME
           my_module

          FILE
           /Users/dkauchak/classes/cs150/examples/modules/my_module.py

          DESCRIPTION
           Some basic functions to illustrate
           how modules work

          FUNCTIONS
           a()
           Prints out the number 10

           b(x, y)
           Returns x plus y

           c(some_string)
           Returns the first and last character of the string

          DATA
           SOME_CONSTANT = 10

       - notice that Python extracts all the information that you've provided
          - the DESCRIPTION comes from your module docstring
          - the functions in the file are enumerated
          - the docstrings from the functions are used as descriptions for the functions
          - the DATA comes from the variables/constants that you define

  • importing
       - when I type "import" what does Python do?
          - executes the code in that module/file
       - for example, if I add:
          print "Loaded my_module"

          to the end of my_module.py
       - when I import my_module
          >>> import my_module
          Loaded my_module
       - what happens if I import the module again?
          >>> import my_module
          >>>
       
          - since it's already been imported, Python does NOT import it again
          - why do you think Python does this?
             - efficiency!
                - what if many other modules import the same thing?
                - what if two modules import eachother?
       - what happens if I change my_module.py and the import again?
          >>> import my_module
          >>>
          
          - be careful!
          - Python only keeps track of whether or not a module has been loaded or not
          - if you change the module, you either need to rerun your program (with the green arrow) OR restart the shell
             - to restart the shell, go under "Options" in the upper right corner and select restart shell

  • running vs. importing
       - we've been creating modules all along and then just running them
       - we could have also been importing them
       - Are there situations where we might want to differentiate whether the module is being run or imported?
          - could run some of the functions and print out information if the module is run, but not imported
          - could print out some help information if the module is run
       - For every module, Python creates a special variable called __name__
          - if you run the module.py file __name__ gets set to "__main__"
          - if you import the module __name__ gets set to the name of the file
          - for example, we can put:

             print __name__

             at the end of our module
          - if we run it:
             __main__
          - if we import it:
             >>> import my_module
             my_module
       - could we use this to help differentiate the module's behavior if it is run vs. imported?
          - check the value of __name__, for example:

             if __name__ == "__main__":
              # it's being run
              print "Running the module"
             else:
              # it's being imported
              print "Imported the module"
       - most often, we just include the if part of this if statement to see if we're being run, and if the module is, then it provides some functionality (i.e. runs the game, etc.)
          - for example, for our current assignment, we would put the code that prompts the user for the file and then runs the function inside this if statement
       - starting from the next assignment, if you have code that runs in your program/module (i.e. not function definitions) you should put it inside a check to see if the program is being run:
          if __name__ == "__main__":
             # run my program

  • .pyc file
       - when you import a module, if you look in the directory where the module resides, you'll also notice a file with the modules name with the ending ".pyc"
       - the .pyc file is a "compiled" version of your module/program
       - what does "compiled" mean?
          - when we compile a program, we convert the code/statements into something that's easier for the computer to understand
       - why do you think Python does this?
          - it's more efficient
       - for now, don't worry too much about it, but I wanted to let you know that you will see it

  • optional parameters
       - let's pretend Python doesn't include the range function and we decide we'd like to implement the same behavior
       - range provides many different functionalities for us:
          >>> range(10)
          [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
          >>> range(4, 10)
          [4, 5, 6, 7, 8, 9]
          >>> range(4, 10, 2)
          [4, 6, 8]

       - try and write the following functions (without using range!):
          - my_range_basic, which takes two parameters, start and stop, and returns a list from start up to end, including start, but not end
          - my_range write that takes a third argument the step size
          - as you're writing these, try and avoid duplicate code
       - look at optional_parameters_wrong.py code
          - use a while loop to generate the data
          - notice the code reuse: my_range_basic is just a call to my_range
       - could we do any better?
          - ideally just one function (like range does)
          - Python won't let us define two functions with the same name, even if they have different numbers of parameters
       - Python has optional parameter
          - an optional parameter is included in the list of parameters, however, we give it a default value using '='
          - the function can be called with OR without that parameter
             - if it's called without it, the parameter gets the default value specified by '='
             - it it's called with it, the parameter gets whatever the user passes in
       - look at optional_parameters.py code
          - we've just written one version called my_range that has step as optional
             - if step isn't specified, it gets a value of 1
             - if it is, then we use the value specified

             >>> my_range(0, 10)
             [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
             >>> my_range(0, 10, 2)
             [0, 2, 4, 6, 8]

          - optional parameters must come AFTER all non-optional parameters. why?
             - say we defined a function as follows:

                def simple(a = 1, b = 2, c):
                   ...

                what happens if I call it with 2 parameter?

                >>> simple(10, 15)

                - we don't know whether a or b should get 10

  • parameters by value
       - look at the optional function in optional_parameters.py code
          - what does this function do?
          - how can we call it?
             >>> optional(10)
             10
             >>> optional(10, 11)
             21
             >>> optional(10, 11, 2)
             31
          - what if we wanted to specify multiplier, but not adder?
             >>> optional(10, multiplier=10)
             100
          - Python allows you to specify ANY parameter by name
             - if you have optional parameters, you can specify them by name
             - you can also specify required parameters by name
                >>> optional(multiplier=2, val = 10)
                20