Python Programming

Lecture 9 Advanced Features, File

9.1 Map, Filter, Lambda

map()


def f(x):
    return x * x

y = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])    
print(list(y))

[1, 4, 9, 16, 25, 36, 49, 64, 81]

print(list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])))


['1', '2', '3', '4', '5', '6', '7', '8', '9']

filter()


def k(x):
    return x%2 == 0

y = list(filter(k, [1, 2, 3, 4, 5, 6, 7, 8, 9]))   
print(y)

[2, 4, 6, 8]

Anonymous function: lambda


def add( x, y ):
    return x + y
 
lambda x, y: x + y
 
lambda x, y = 2: x + y
lambda *z: z
  • Sometimes the anonymous function is convenient.

  • It has only one expression. (You do not have to use return)


print(list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])))

print(list(filter(lambda x: x%2==0, [1, 2, 3, 4, 5, 6, 7, 8, 9])))

Comprehension Syntax

  • [ expression for value in iterable if condition ]


>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']

>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

9.2 Return a Function

Closure Function


def print_msg(msg):
    def printer():
        print(msg)
    return printer

another = print_msg("zen of python")
print(another())
  • We must have a nested function (function inside a function).

  • The nested function must refer to a value defined in the enclosing function.

  • The enclosing function must return the nested function.

When to use closures?

  • Closures can avoid the use of global values and provides some form of data hiding. It can also provide an object oriented solution to the problem.

Example


def lazy_sum(*args):
    def calc_sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return calc_sum

f = lazy_sum(1, 3, 5, 7, 9)
print(f()) 
print(type(f)) 

25
<class 'function'>

def make_multiplier_of(n):
    def multiplier(x):
        return x * n
    return multiplier

times3 = make_multiplier_of(3)
times5 = make_multiplier_of(5)

print(times3(9))
print(times5(3))
print(times5(times3(2)))

Decorator

  • Decorators are "wrappers", which means that they let you execute code before and after the function they decorate without modifying the function itself.


def new_decorator(a_function_to_decorate):
    def the_wrapper():
        print("Before the function runs") 
        a_function_to_decorate()
        print("After the function runs")
    return the_wrapper

def a_function():
    print("I am a stand alone function.")

a_function_decorated = new_decorator(a_function)
a_function_decorated()

Before the function runs
I am a stand alone function.
After the function runs

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

another_stand_alone_function()  

Before the function runs
Leave me alone
After the function runs

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()


--ham--

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

sandwich()


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

  • Passing arguments to the decorated function


def passing_arguments(function_to_decorate):
    def wrapper(arg1, arg2):
        print(f"I got args! Look: {arg1}, {arg2}")
        function_to_decorate(arg1, arg2)
    return wrapper

@passing_arguments
def print_name(first_name, last_name):
    print(f"My name is {first_name}, {last_name}")

print_name("Peter", "Venkman")

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 passing_arbitrary_arguments(function_to_decorate):
    def wrapper(*args, **kwargs):
        print("Do I have args?:")
        print(args)
        print(kwargs)
        function_to_decorate(*args, **kwargs)
    return wrapper

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

function_with_no_argument()

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

@passing_arbitrary_arguments
def function_with_arguments(a, b, c, d):
    print(a, b, c, d)

function_with_arguments(1,2,3,4)

Do I have args?:
(1, 2, 3, 4)
{}
1 2 3 4


function_with_arguments(1,2,3,d = "banana")

Do I have args?:
(1, 2, 3)
{'d': 'banana'}
1 2 3 banana

9.3 File

Reading from a File

  • pi_digits.txt


3.1415926535
8979323846
2643383279

with open('pi_digits.txt') as file_object:
    contents = file_object.read() # string
    print(contents.rstrip())

3.1415926535
8979323846
2643383279

File Path

  • relative path


with open('text_files/filename.txt') as file_object: # Linux or OSX
    pass
with open('text_files\filename.txt') as file_object: # Windows
    pass
  • absolute path


# Linux or OSX
file_path = '/home/ehmatthes/other_files/text_files/filename.txt'
with open(file_path) as file_object:
    pass

# Windows
file_path = r'C:\Users\ehmatthes\other_files\text_files\filename.txt'
with open(file_path) as file_object:
    pass
  • Please add "r" if you use Windows.

Reading Line by Line


filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line)

3.1415926535

8979323846

2643383279


filename = 'pi_digits.txt'
with open(filename) as file_object:
    for line in file_object:
        print(line.rstrip())

3.1415926535
8979323846
2643383279
  • Making a List of Lines from a File


filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readlines() #List
  • Working with a File's Contents


pi_string = ''
for line in lines:
    pi_string = pi_string + line.rstrip()
print(pi_string)
print(len(pi_string))

3.141592653589793238462643383279 # string
32

Writing to a File


filename = 'programming.txt'

with open(filename, 'w') as file_object:
    file_object.write("I love programming.")
  • The second argument, 'w', tells Python that we want to open the file in write mode. You can open a file 198 Chapter 10 in read mode ('r'), write mode ('w'), append mode ('a'), or a mode that allows you to read and write to the file ('r+'). If you omit the mode argument, Python opens the file in read-only mode by default.

  • Python can only write strings to a text file. If you want to store numerical data in a text file, you'll have to convert the data to string format first using the str() function.

  • Writing Multiple Lines


filename = 'programming.txt'
with open(filename, 'w') as file_object:
    file_object.write("I love programming.")
    file_object.write("I love creating new games.")

I love programming.I love creating new games.   

filename = 'programming.txt'
with open(filename, 'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")



I love programming.
I love creating new games.
  • Appending to a File


filename = 'programming.txt'
message.py
with open(filename, 'a') as file_object:
    file_object.write("I also love finding meaning in large datasets.\n")
    file_object.write("I love creating apps that can run in a browser.\n")

I love programming.
I love creating new games.
I also love finding meaning in large datasets.
I love creating apps that can run in a browser.
  • Handling the FileNotFoundError Exception


filename = 'alice.txt'
with open(filename) as f_obj:
    contents = f_obj.read() #Error

filename = 'alice.txt'
try:
    with open(filename) as f_obj:
        contents = f_obj.read()
except FileNotFoundError:
    msg = f"Sorry, the file {filename} does not exist."
    print(msg)

Sorry, the file alice.txt does not exist.
  • ZeroDivisionError

  • try-except-else

filename = 'alice.txt'
try:
    with open(filename) as f_obj:
        contents = f_obj.read()
except FileNotFoundError:
    msg = f"Sorry, the file {filename} does not exist."
    print(msg)
else:
# Count the approximate number of words in the file.
    words = contents.split()
    num_words = len(words)
    print(f"The file {filename} has about {num_words} words.")

JSON

  • JSON (JavaScript Object Notation, pronounced /ˈdʒeɪsən/; also /ˈdʒeɪˌsɒn/) is an open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays (or other serializable values). It is a common data format with diverse uses in electronic data interchange, including that of web applications with servers.
  • JSON is a language-independent data format. It was derived from JavaScript, but many modern programming languages include code to generate and parse JSON-format data. JSON filenames use the extension .json.
  • dump and load

import json

numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
    json.dump(numbers, f_obj)

import json

filename = 'numbers.json'
with open(filename) as f_obj:
    numbers = json.load(f_obj)
print(numbers)

[2, 3, 5, 7, 11, 13]
  • Saving and Reading User-Generated Data


import json

filename = 'username.json'

username = input("What is your name? ")
with open(filename, 'w') as f_obj:
    json.dump(username, f_obj)
    print(f"We'll remember you when you come back, {username}!")

import json
filename = 'username.json'

with open(filename) as f_obj:
    username = json.load(f_obj)
    print(f"Welcome back, {username}!")

import json

filename = 'username.json'
try:
    with open(filename) as f_obj:
        username = json.load(f_obj)
except FileNotFoundError:
    username = input("What is your name? ")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        print(f"We'll remember you when you come back, {username}!")
else:
    print(f"Welcome back, {username}!")

What is your name? Eric #First time
We'll remember you when you come back, Eric!

Welcome back, Eric!

Summary

  • File
    • Reading: Python Crash Course, Chapter 10