Python Programming

Lecture 8 Decorator, Modules

8.1 Functions (5)

Decorator

  • Decorator Basics


def shout(word="yes"):
    return word.title()+"!"

print(shout())
# outputs : 'Yes!'

scream = shout

print(scream())
# outputs : 'Yes!'

del shout
print(scream())
# outputs: 'Yes!'

def talk():
    def whisper(word="yes"):
        return word.lower()+"..."
    print(whisper())
 
talk()
# outputs: 
# "yes..."
# But "whisper" DOES NOT EXIST outside "talk":

def getTalk(kind="shout"):
    def shout(word="yes"):
        return word.title()+"!"
    def whisper(word="yes") :
        return word.lower()+"...";
    if kind == "shout":
        return shout  
    else:
        return whisper

talk = getTalk()      
# You can see that "talk" is here a function object:
print(type(talk))
#outputs : function

print(talk())
#outputs : Yes!

print(getTalk("whisper")())
#outputs : yes...
  • decorators are “wrappers”, which means that they let you execute code before and after the function they decorate without modifying the function itself.


# A decorator is a function that expects ANOTHER function as parameter
def my_shiny_new_decorator(a_function_to_decorate):
    def the_wrapper_around_the_original_function():
        print("Before the function runs")

        a_function_to_decorate()

        print("After the function runs")

    return the_wrapper_around_the_original_function

def a_stand_alone_function():
    print("I am a stand alone function, don't you dare modify me")

a_stand_alone_function() 
#outputs: 
I am a stand alone function, don't you dare modify me

a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#outputs:

Before the function runs
I am a stand alone function, don't you dare modify me
After the function runs

@my_shiny_new_decorator
def another_stand_alone_function():
    print("Leave me alone")

another_stand_alone_function()  
#outputs:  
Before the function runs
Leave me alone
After the function runs

# @decorator is just a shortcut

def bread(func):
    def wrapper():
        print("")
        func()
        print("<\______/>")
    return wrapper

def ingredients(func):
    def wrapper():
        print("#tomatoes#")
        func()
        print("~salad~")
    return wrapper

def sandwich(food="--ham--"):
    print(food)

sandwich()
#outputs: --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#outputs:

 #tomatoes#
 --ham--
 ~salad~
<\______/>

@bread
@ingredients # The order matters here.
def sandwich(food="--ham--"):
    print(food)

sandwich()
#outputs:

 #tomatoes#
 --ham--
 ~salad~
<\______/>
  • Taking decorators to the next level

  • Passing arguments to the decorated function


def a_decorator_passing_arguments(function_to_decorate):
    def a_wrapper_accepting_arguments(arg1, arg2):
        print("I got args! Look: %s, %s" % (arg1, arg2))
        function_to_decorate(arg1, arg2)
    return a_wrapper_accepting_arguments

@a_decorator_passing_arguments
def print_full_name(first_name, last_name):
    print("My name is %s, %s" % (first_name, last_name))

print_full_name("Peter", "Venkman")
# outputs:
I got args! Look: Peter Venkman
My name is Peter Venkman
  • If you're making general-purpose decorator--one you'll apply to any function or method, no matter its arguments--then just use *args, **kwargs:


def a_decorator_passing_arbitrary_arguments(function_to_decorate):
    # The wrapper accepts any arguments
    def a_wrapper_accepting_arbitrary_arguments(*args, **kwargs):
        print("Do I have args?:")
        print(args)
        print(kwargs)
        function_to_decorate(*args, **kwargs)
    return a_wrapper_accepting_arbitrary_arguments

@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
    print("Python is cool, no argument here.")

function_with_no_argument()
#outputs
Do I have args?:
()
{}
Python is cool, no argument here.

@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
    print(a, b, c)

function_with_arguments(1,2,3)
#outputs
Do I have args?:
(1, 2, 3)
{}
1 2 3 

@a_decorator_passing_arbitrary_arguments
def function_with_named_arguments(a, b, c, platypus="Why not ?"):
    print("Do {0}, {1} and {2} like platypus? {3}".format(a, b, c, platypus))

function_with_named_arguments("Bill", "Linus", "Steve", platypus="Indeed!")
#outputs
Do I have args ? :
('Bill', 'Linus', 'Steve')
{'platypus': 'Indeed!'}
Do Bill, Linus and Steve like platypus? Indeed! 

8.2 Modules

  • Module is a Python file, followed with .py

  • Storing Your Functions in Modules


def make_pizza(size, *toppings):
    print("\nMaking a " + str(size) +
        "-inch pizza with the following toppings:")
    for topping in toppings:
        print("- " + topping)
  • It is saved as "pizza.py" file.

  • We make a separate file called making_pizzas.py in the same directory as pizza.py.


import pizza

pizza.make_pizza(16, 'pepperoni')
pizza.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
  • Importing Specific Functions


from module_name import function_name

from module_name import function_0, function_1, function_2

from pizza import make_pizza
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')
  • Using as to Give a Function an Alias


from pizza import make_pizza as mp
mp(16, 'pepperoni')
mp(12, 'mushrooms', 'green peppers', 'extra cheese')

from module_name import function_name as fn
  • Using as to Give a Module an Alias


import pizza as p
p.make_pizza(16, 'pepperoni')
p.make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

import module_name as mn
  • Importing All Functions in a Module


from pizza import *
make_pizza(16, 'pepperoni')
make_pizza(12, 'mushrooms', 'green peppers', 'extra cheese')

from module_name import *
  • The asterisk in the import statement tells Python to copy every function from the module pizza into this program file. Because every function is imported, you can call each function by name without using the dot notation.

  • However, it's best not to use this approach when you're working with larger modules that you didn't write: if the module has a function name that matches an existing name in your project, you can get some unexpected results.

Search for Modules

  • When a module named is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named xxx.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:

  • The directory containing the input script (or the current directory when no file is specified).

  • PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).

  • The installation-dependent default.


import sys
print(sys.path)

Packages

  • Packages are namespaces which contain multiple packages and modules themselves. They are simply directories, but with a twist.

  • Each package in Python is a directory which MUST contain a special file called __init__.py. This file can be empty, and it indicates that the directory it contains is a Python package, so it can be imported the same way a module can be imported.


mycompany
├─ __init__.py
├─ abc.py
└─ xyz.py
  • The name of modules are mycompany.abc and mycompany.xyz

  • Be careful! The name of modules you created should not be in conflict with the name of any system module, or any build-in function.

  • Private functions in modules, _xxx, __xxx


def _private_1(name):
    return 'Hello, %s' % name

def _private_2(name):
    return 'Hi, %s' % name

def greeting(name):
    if len(name) > 3:
        return _private_1(name)
    else:
        return _private_2(name)
  • You can use those functions, but you would better not use.

Third party modules


import urllib
dir(urllib)
  • For Python, open the cmd.

  • For Anaconda, open the anaconda prompt.


pip install pillow
  • If you want to use both the Python and Anaconda, there might be some conflicts. Thus, please change file name in the Anaconda. D:\Anaconda\Scripts, pip.exe and pip-script.exe to condapip.exe and condapip-script.exe


pip install you-get #for python
condapip install itchat #for anaconda
conda list

Summary

  • Functions
    • Reading: Python for Everybody, Chapter 10.1-10.5, 10.7-10.8
    • Reading: Python Crash Course, Chapter 8
  • Problem Set 2