- Notifications
You must be signed in to change notification settings - Fork 2.8k
/
Copy pathtest_function_definition.py
123 lines (89 loc) · 5.33 KB
/
test_function_definition.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""Function Definition
@see: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
@see: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
The keyword def introduces a function definition. It must be followed by the function name and the
parenthesized list of formal parameters. The statements that form the body of the function start at
the next line, and must be indented.
"""
deffibonacci_function_example(number_limit):
"""Generate a Fibonacci series up to number_limit.
The first statement of the function body can optionally be a string literal; this string
literal is the function’s documentation string, or docstring. There are tools which use
docstrings to automatically produce online or printed documentation, or to let the user
interactively browse through code; it’s good practice to include docstrings in code that you
write, so make a habit of it.
"""
# The execution of a function introduces a new symbol table used for the local variables of the
# function. More precisely, all variable assignments in a function store the value in the local
# symbol table; whereas variable references first look in the local symbol table, then in the
# local symbol tables of enclosing functions, then in the global symbol table, and finally in
# the table of built-in names. Thus, global variables cannot be directly assigned a value
# within a function (unless named in a global statement), although they may be referenced.
fibonacci_list= []
previous_number, current_number=0, 1
whileprevious_number<number_limit:
# The statement result.append(a) calls a method of the list object result. A method is a
# function that ‘belongs’ to an object and is named obj.methodname, where obj is some
# object (this may be an expression), and methodname is the name of a method that is
# defined by the object’s type. Different types define different methods. Methods of
# different types may have the same name without causing ambiguity. (It is possible to
# define your own object types and methods, using classes, see Classes) The method
# append() shown in the example is defined for list objects; it adds a new element at
# the end of the list. In this example it is equivalent to result = result + [a], but
# more efficient.
fibonacci_list.append(previous_number)
# This is multiple assignment statement. We make current number to be previous one and the
# sum of previous and current to be a new current.
previous_number, current_number=current_number, previous_number+current_number
# The return statement returns with a value from a function. return without an expression
# argument returns None. Falling off the end of a function also returns None.
returnfibonacci_list
deftest_function_definition():
"""Function Definition"""
# Now call the function we just defined.
assertfibonacci_function_example(300) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
# A function definition introduces the function name in the current symbol table. The value of
# the function name has a type that is recognized by the interpreter as a user-defined function.
# This value can be assigned to another name which can then also be used as a function. This
# serves as a general renaming mechanism
fibonacci_function_clone=fibonacci_function_example
assertfibonacci_function_clone(300) == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
# In Python, functions are first class citizens, they are objects and that means we can do a
# lot of useful stuff with them.
# Assign functions to variables.
defgreet(name):
return'Hello, '+name
greet_someone=greet
assertgreet_someone('John') =='Hello, John'
# Define functions inside other functions.
defgreet_again(name):
defget_message():
return'Hello, '
result=get_message() +name
returnresult
assertgreet_again('John') =='Hello, John'
# Functions can be passed as parameters to other functions.
defgreet_one_more(name):
return'Hello, '+name
defcall_func(func):
other_name='John'
returnfunc(other_name)
assertcall_func(greet_one_more) =='Hello, John'
# Functions can return other functions. In other words, functions generating other functions.
defcompose_greet_func():
defget_message():
return'Hello there!'
returnget_message
greet_function=compose_greet_func()
assertgreet_function() =='Hello there!'
# Inner functions have access to the enclosing scope.
# More commonly known as a closure. A very powerful pattern that we will come across while
# building decorators. Another thing to note, Python only allows read access to the outer
# scope and not assignment. Notice how we modified the example above to read a "name" argument
# from the enclosing scope of the inner function and return the new function.
defcompose_greet_func_with_closure(name):
defget_message():
return'Hello there, '+name+'!'
returnget_message
greet_with_closure=compose_greet_func_with_closure('John')
assertgreet_with_closure() =='Hello there, John!'