0% found this document useful (0 votes)
7 views

5. More on functions

The document discusses the concept of functions in Python, focusing on scopes (LEGB), function parameters, and handling arbitrary numbers of arguments. It explains how names are managed through namespaces, the use of global variables, and the differences between positional, keyword, and default arguments. Additionally, it covers the use of dictionaries with Pickle for data storage and the try-except mechanism for error handling.

Uploaded by

gamer.guy123679
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views

5. More on functions

The document discusses the concept of functions in Python, focusing on scopes (LEGB), function parameters, and handling arbitrary numbers of arguments. It explains how names are managed through namespaces, the use of global variables, and the differences between positional, keyword, and default arguments. Additionally, it covers the use of dictionaries with Pickle for data storage and the try-except mechanism for error handling.

Uploaded by

gamer.guy123679
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

More on Functions

Computer Science & Engineering Department


The Chinese University of Hong Kong
Content

• LEGB & Scope

• Revisit function parameters

• Arbitrary number of parameters

2
Identifiers in Program
• Names of variables, functions, modules can collide with others – same
name used unintentionally (Python allows this)
• Managed using name spaces
• Encapsulation of names through levels of abstraction
• Three levels of encapsulation
• LEGB rule for simple variables
• Qualified names
• modules

3
LEGB
• L: local
• E: Enclosing function definitions
• G: Global
• B: built-in functions
• When Python is looking for meaning attached to a name, it
search the scope in the order: Local, Enclosing, Global, Built-in
>>> x = 42
>>> def afun():
... x = 12 Only creating local var
... print (x)
>>> afun()
12
>>> print (x)
42 4
Enclosing
• Occurs when one function is defined inside another
• Each function definition creates a new scope for variables at that level

>>> def a(x):


... def b(y):
... print (x + y)
... y = 11
... b(3)
... print (y)
...
>>> a(4)
7
11
5
Revision

Name Scope
• Names defined outside functions have global scope
• Any local names will shadow the global (same name)
• All values & names destroyed after return

>>> x=4 x=4


>>> def scopetest(a): >>> def scopeTest(a):
... return x + a ... x=7
... ... return x + a
>>> print (scopetest(3)) ...
7 >>> print (scopeTest(3))
>>> 10

6
Scopes
• Described as a series of nested boxes
• To find a match for a given variable, the boxes are examined from
inside out until the name is found
• Lambda create their own local scope
• Thus distinct from surrounding function scope

>>> def a(x):


... f = lambda x: x + 3
... print (f(3))
... print (x)
...
>>> a(4)
6
4
7
Using globals
• To have assignment access on global variables, use global statement
>>> b = 2
>>> def scopeTest (a):
... global b
... b = 4
... print ('inside func, b is ', b)
...
>>> a = 1
>>> scopeTest(a)
inside func, b is 4
>>> print ('after func, b is ', b)
after func, b is 4
8
Block Scope
• Python has no block scope like C or Java in loop

>>> for i in range(5):


... print (i) if i%2 == 0 else print (-i)
... print (i) This is not an error
0
-1
2
-3
4
4

9
Built-in functions
• Functions that are initially part of any Python program e.g. open, zip,
etc
• Can be overridden in a different scope
• For example, a programmer can define his/her own open.
• However it will prevent access to the standard function i.e. file open

10
dir function
• dir can be used to access a list of names in current scope
• Get global scope in topmost level

>>> z = 12
>>> def dirTest():
... x = 34
... print (dir())
>>> print (dir())
['__builtins__', '__doc__', '__name__', '__package__',
'dirTest', 'pywin', 'z']
>>> dirTest()
['x']

11
dir function
• Can accept an argument
• Return scope of the object

>>> dir (dirTest)


['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals',
'func_name']
>>> import math
>>> dir(math)
['__doc__', '__name__', '__package__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2',
'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'factorial', 'floor',
'fmod', 'frexp', 'fsum', 'hypot', 'isinf', 'isnan', 'ldexp', 'log', 'log10', 'log1p', 'modf', 'pi',
'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc']
12
1 def foo(x, y): Revision
2 print("{} {}" .format(x, y))
3
4 x = 3
5 y = 2
6
7 foo(x, y)
8
9 foo(y, x)
10

Positional Arguments

• Arguments and parameters are matched by positions


(not by names).

13
1 def foo(x, y): Revision
2 print("{} {}" .format(x, y))
3
4 foo(x=3, y=2)
5
6 foo(y=2, x=3)
7
8 foo(3, y=2) 3 2
9 3 2
10 3 2

Keyword arguments

• Arguments in function call can also be in the form of


keyword (match by names)
• Must use keyword argument for all others once used for
the first of them
14
1 def foo(x, y=2): Revision
2 print("{} {}" .format(x, y))
3
4 foo(x=3)
5
6 foo(3)
7
3 2
8 foo(x=2, y=3)
3 2
9 2 3
10 foo(2, 3) 2 3

Default arguments

• an argument that assumes a default value if a value is not


provided in the function call for that argument
• Default argument must appear later than those without
default value i.e. (x=3, y) is not allowed
15
Function Parameters Revisited
1 def describe_person(first_name, last_name, age=None, favorite_language=None,
2 died=None):
3 print("First name: {:s}".format( first_name.title()))
4 print("Last name: {:s}".format( last_name.title()))
5 if age:
6 print("Age: {:d}".format(age))
7 if favorite_language:
8 print("Favorite language: {:s}".format( favorite_language))
9 if died:
10 print("Died at: {:d}".format( died))
11 print("\n")
12
describe_person('ken', 'thompson', age=70)
describe_person('adele', 'goldberg', age=68, favorite_language='Smalltalk')
describe_person('dennis', 'ritchie', favorite_language='C', died=2011)

16
Function Parameters Revisited
1 First name: Ken
2 Last name: Thompson
3 Age: 70
4
5
First name: Adele
6
Last name: Goldberg
7 Age: 68
8 Favorite language: Smalltalk
9
10
11 First name: Dennis
12 Last name: Ritchie
Favorite language: C
Died at: 2011

17
Arbitrary Number of Arguments
• Python functions can be flexible to handle different situation by
combination of keyword arguments and default value
• But we can do even better
• Consider a function to add up two numbers
1 # This function adds two numbers together, and prints the sum
2 def adder(num_1, num_2):
3 sum = num_1 + num_2
4 print("The sum of your numbers is {:d}.".format(sum))
5 The sum of your numbers is 3.
6 # Let's add some numbers. The sum of your numbers is 1.
adder(1, 2) The sum of your numbers is -1.
adder(-1, 2)
adder(1, -2)
18
Arbitrary Number of Arguments
• If we pass three arguments to it, the function will has problem
1 def adder(num_1, num_2):
2 sum = num_1 + num_2
3 print("The sum of your numbers is {:d}.".format(sum))
4
5 # Let's add some numbers.
6 adder(1, 2, 3)

TypeError Traceback (most recent call last)


<ipython-input-1-ef5adcfdedef> in <module>
----> 7 adder(1, 2, 3)

TypeError: adder() takes 2 positional arguments but 3 were given


19
Arbitrary Number of Arguments
• For end of the list of arguments with an asterisk in front of it, that
argument will collect any remaining values from the calling
statement into a tuple
•1 def example_function(arg_1, arg_2, *arg_3): arg_1: 1
2 print('\narg_1:', arg_1) arg_2: 2
3 print('arg_2:', arg_2) arg_3: ()
4 print('arg_3:', arg_3)
arg_1: 1
5
arg_2: 2
6 example_function(1, 2)
arg_3: (3,)
7 example_function(1, 2, 3)
8 example_function(1, 2, 3, 4) arg_1: 1
arg_2: 2
arg_3: (3, 4)
20
Arbitrary Number of Arguments
• We can use a loop to process these other arguments

1 def example_function(arg_1, arg_2, *arg_3): arg_1: 1


2 print('arg_1:', arg_1) arg_2: 2
3 print('arg_2:', arg_2) arg_3 value: 3
4 for value in arg_3: arg_3 value: 4
5 print('arg_3 value:', value)
arg_1: 1
6
arg_2: 2
7 arg_3 value: 3
8 example_function(1, 2, 3, 4) arg_3 value: 4
example_function(1, 2, 3, 4, 5) arg_3 value: 5

21
Arbitrary Number of Arguments
• Let's rewrite our adder() function
1 def adder(num_1, num_2, *nums):
2 sum = num_1 + num_2
3 for num in nums:
4 sum = sum + num
5
6 print("The sum of your numbers is %d." % sum)
7
8 # Let's add some numbers.
9 adder(3,4) The sum of your numbers is 7.
10 adder(1, 2, 3) The sum of your numbers is 6.
11 adder(1,2,3,4,5) The sum of your numbers is 15.

22
Arbitrary Number of Arguments
• Accept i ng an arbi t rary number of keyword argument s i s
al so possi bl e
1 def example_function(arg_1, arg_2, **kwargs): arg_1: a
2 print('\narg_1:', arg_1) arg_2: b
3 print('arg_2:', arg_2) arg_3: {}
4 print('arg_3:', kwargs)
5 arg_1: a
arg_2: b
6 example_function('a', 'b')
arg_3: {'value_3': 'c'}
7 example_function('a', 'b', value_3='c')
8 example_function('a', 'b', value_3='c', value_4='d') arg_1: a
arg_2: b
arg_3: {'value_3': 'c',
'value_4': 'd'}
23
Arbitrary Number of Arguments
• Keyword argument s are st ored as a di ct i onary

1 def example_function(arg_1, arg_2, **kwargs): arg_1: a


2 print('\narg_1:', arg_1) arg_2: b
3 print('arg_2:', arg_2)
4 for key, value in kwargs.items(): arg_1: a
5 print('arg_3 value:', value) arg_2: b
arg_3 value: c
6
7 example_function('a', 'b') arg_1: a
8 example_function('a', 'b', value_3='c') arg_2: b
example_function('a', 'b', value_3='c', value_4='d') arg_3 value: c
arg_3 value: d

24
Exercise
• Can you rewrite the adder() with the following function signature?

def adder(num_1, num_2, **nums):


# your implementation goes here

25
First Example Rewritten
1 def describe_person(first_name, last_name, **kwargs):
2 print("First name: %s" % first_name.title())
3 print("Last name: %s" % last_name.title())
4 # Optional information:
5 for key in kwargs:
6 print("%s: %s" % (key.title(), kwargs[key]))
7 print("\n")
8
9 describe_person('brian', 'kernighan', favorite_language='C', famous_book='The
10 C Programming Language')
11 describe_person('dennis', 'ritchie', favorite_language='C', died=2011,
12 famous_book='The C Programming Language')
13 describe_person('guido', 'van rossum', favorite_language='Python',
14 company='Dropbox')
15
16
26
Function Parameters
1 First name: Brian
2 Last name: Kernighan
3 Favorite_Language: C
4 Famous_Book: The C Programming Language
5
First name: Dennis
6
Last name: Ritchie
7 Favorite_Language: C
8 Died: 2011
9 Famous_Book: The C Programming Language
10
11 First name: Guido
12 Last name: Van Rossum
Favorite_Language: Python
Company: Dropbox

27
Pickle & Dictionary
• Dictionary is best to pair with Pickle

import pickle # import to use


info = {'name':'Batman', 'age':82, 'weight':180}
f = open('pickle1.pyp','wb')
pickle.dump(info, f) # store the dictionary in a file

• Later on, in another program


>>> import pickle
>>> f = open('pickle1.pyp', "rb")
>>> d = pickle.load(f)
>>> for i in d.keys():
>>> print (f"{i}:{d[i]}",end=',')
name:Batman,age:82,weight:180

28
Appendix
Try except
• Similar to the try-catch mechanism in other programming language, python use try-
except-else-finally block to handle exception
def divide(x, y):
try:
result = x // y # Floor Division : Gives only Fractional
except ZeroDivisionError:
print ("Sorry ! You are dividing by zero ")
else:
print ("Yeah ! Your answer is :", result)
divide(3, 2)
divide(3, 0)
divide(3,'1')
>>> Yeah ! Your answer is : 1
>>> Sorry ! You are dividing by zero
> Traceback (most recent call last):
File "COURSE/python/divide.py", line 10, in <module>
divide(3,'1')
File "COURSE/python/divide.py", line 3, in divide
result = x //y
TypeError: unsupported operand type(s) for //: 'int' and 'str'
30
Raise exception
• When the program is running at a point that the current function cannot solve
the problem, we can raise an exception for caller to handle
def divide(x, y):
try:
result = x // y # Floor Division : Gives only Fractional
except ZeroDivisionError:
print ("Sorry ! You are dividing by zero ")
except Exception as e:
raise
else:
print ("Yeah ! Your answer is :", result)

try:
divide(1, 's')
except Exception as e:
print (e)

>> unsupported operand type(s) for //: 'int' and 'str' 31


Restoring redirected Standard I/O
• After redirecting the stdout, how to restore it?
import sys
In output.txt
fout = sys.stdout = open('output.txt', 'w') see where this goes
with open('error.txt', 'w') as ferr: 1.25
try:
print("see where this goes")
In error.txt
print(5 / 4) ZeroDivisionError: float
print(7.0 / 0) division by zero
except Exception as e:
print(type(e).__name__, e, sep=": ", file=ferr)
sys.stdout = sys.__stdout__ # reset stdout to normal
fout.close()

32

You might also like