-- Why use functions? Reduce code duplication Splitting a complex task data.science.example.py def do_report(data_source): # fetch and prepare data data = fetch_data(data_source) parsed_data = parse_data(data) filtered_data = filter_data(parsed_data) polished_data = polish_data(filtered_data) # run algorithms on data final_data = analyse(polished_data) # create and return report report = Report(final_data) return report Hide implementation details Improve readability matrix.multiplication.nofunc.py a = [[1, 2], [3, 4]] b = [[5, 1], [2, 1]] c = [[sum(i * j for i, j in zip(r, c)) for c in zip(*b)] for r in a] matrix.multiplication.func.py # this function could also be defined in another module def matrix_mul(a, b): return [[sum(i * j for i, j in zip(r, c)) for c in zip(*b)] for r in a] a = [[1, 2], [3, 4]] b = [[5, 1], [2, 1]] c = matrix_mul(a, b) Improve traceability vat.py price = 100 # GBP, no VAT final_price1 = price * 1.2 final_price2 = price + price / 5.0 final_price3 = price * (100 + 20) / 100.0 final_price4 = price + price * 0.2 vat.function.py def calculate_price_with_vat(price, vat): return price * (100 + vat) / 100 -- Scopes and name resolution scoping.level.1.py def my_function(): test = 1 # this is defined in the local scope of the function print('my_function:', test) test = 0 # this is defined in the global scope my_function() print('global:', test) $ python scoping.level.1.py scoping.level.2.py def outer(): test = 1 # outer scope def inner(): test = 2 # inner scope print('inner:', test) inner() print('outer:', test) test = 0 # global scope outer() print('global:', test) $ python scoping.level.2.py The global and nonlocal statements scoping.level.2.nonlocal.py def outer(): test = 1 # outer scope def inner(): nonlocal test test = 2 # nearest enclosing scope print('inner:', test) inner() print('outer:', test) test = 0 # global scope outer() print('global:', test) $ python scoping.level.2.nonlocal.py scoping.level.2.global.py def outer(): test = 1 # outer scope def inner(): global test test = 2 # global scope print('inner:', test) inner() print('outer:', test) test = 0 # global scope outer() print('global:', test) $ python scoping.level.2.global.py -- Input parameters Argument passing key.points.argument.passing.py x = 3 def func(y): print(y) func(x) # prints: 3 Assignment to argument names don't affect the caller key.points.assignment.py x = 3 def func(x): x = 7 # defining a local x, not changing the global one func(x) print(x) # prints: 3 Changing a mutable affects the caller key.points.mutable.py x = [1, 2, 3] def func(x): x[1] = 42 # this affects the caller! func(x) print(x) # prints: [1, 42, 3] x = [1, 2, 3] def func(x): x[1] = 42 # this changes the caller! x = 'something else' # this points x to a new string object func(x) print(x) # still prints: [1, 42, 3] How to specify input parameters Positional arguments arguments.positional.py def func(a, b, c): print(a, b, c) func(1, 2, 3) # prints: 1 2 3 Keyword arguments and default values arguments.keyword.py def func(a, b, c): print(a, b, c) func(a=1, c=2, b=3) # prints: 1 3 2 arguments.default.py def func(a, b=4, c=88): print(a, b, c) func(1) # prints: 1 4 88 func(b=5, a=7, c=9) # prints: 7 5 9 func(42, c=9) # prints: 42 4 9 func(b=1, c=2, 42) # positional argument after keyword one Variable positional arguments arguments.variable.positional.py def minimum(*n): # print(n) # n is a tuple if n: # explained after the code mn = n[0] for value in n[1:]: if value < mn: mn = value print(mn) minimum(1, 3, -7, 9) # n = (1, 3, -7, 9) - prints: -7 minimum() # n = () - prints: nothing arguments.variable.positional.unpacking.py def func(*args): print(args) values = (1, 3, -7, 9) func(values) # equivalent to: func((1, 3, -7, 9)) func(*values) # equivalent to: func(1, 3, -7, 9) Variable keyword arguments arguments.variable.keyword.py def func(**kwargs): print(kwargs) # All calls equivalent. They print: {'a': 1, 'b': 42} func(a=1, b=42) func(**{'a': 1, 'b': 42}) func(**dict(a=1, b=42)) arguments.variable.db.py def connect(**options): conn_params = { 'host': options.get('host', '127.0.0.1'), 'port': options.get('port', 5432), 'user': options.get('user', ''), 'pwd': options.get('pwd', ''), } print(conn_params) # we then connect to the db (commented out) # db.connect(**conn_params) connect() connect(host='127.0.0.42', port=5433) connect(port=5431, user='fab', pwd='gandalf') $ python arguments.variable.db.py Keyword-only arguments arguments.keyword.only.py def func(a, b, c=7, *args, **kwargs): print('a, b, c:', a, b, c) print('args:', args) print('kwargs:', kwargs) func(1, 2, 3, *(5, 7, 9), **{'A': 'a', 'B': 'b'}) func(1, 2, 3, 5, 7, 9, A='a', B='b') # same as previous one $ python arguments.all.py arguments.all.kwonly.py def func_with_kwonly(a, b=42, *args, c, d=256, **kwargs): print('a, b:', a, b) print('c, d:', c, d) print('args:', args) print('kwargs:', kwargs) # both calls equivalent func_with_kwonly(3, 42, c=0, d=1, *(7, 9, 11), e='E', f='F') func_with_kwonly(3, 42, *(7, 9, 11), c=0, d=1, e='E', f='F') $ python arguments.all.kwonly.py Avoid the trap! Mutable defaults arguments.defaults.mutable.py def func(a=[], b={}): print(a) print(b) print('#' * 12) a.append(len(a)) # this will affect a's default value b[len(a)] = len(a) # and this will affect b's one func() func() func() $ python arguments.defaults.mutable.py arguments.defaults.mutable.intermediate.call.py func() func(a=[1, 2, 3], b={'B': 1}) func() $ python arguments.defaults.mutable.intermediate.call.py arguments.defaults.mutable.no.trap.py def func(a=None): if a is None: a = [] # do whatever you want with `a` ... -- Return values return.none.py def func(): pass func() # the return of this call won't be collected. It's lost. a = func() # the return of this one instead is collected into `a` print(a) # prints: None return.single.value.py def factorial(n): if n in (0, 1): return 1 result = n for k in range(2, n): result *= k return result f5 = factorial(5) # f5 = 120 return.single.value.2.py from functools import reduce from operator import mul def factorial(n): return reduce(mul, range(1, n + 1), 1) f5 = factorial(5) # f5 = 120 Returning multiple values return.multiple.py def moddiv(a, b): return a // b, a % b print(moddiv(20, 7)) # prints (2, 6) -- A few useful tips numbers = [4, 1, 7, 5] sorted(numbers) # won't sort the original `numbers` list numbers # let's verify #[4, 1, 7, 5] # good, untouched numbers.sort() # this will act on the list numbers #[1, 4, 5, 7] -- Recursive functions recursive.factorial.py def factorial(n): if n in (0, 1): # base case return 1 return factorial(n - 1) * n # recursive case -- Anonymous functions The logic is exactly the same but the filtering function is now a lambda. Defining a lambda is very easy and follows this form: func_name = lambda [parameter_list]: expression. A function object is returned, which is equivalent to this: def func_name([parameter_list]): return expression. filter.regular.py def is_multiple_of_five(n): return not n % 5 def get_multiples_of_five(n): return list(filter(is_multiple_of_five, range(n))) print(get_multiples_of_five(50)) filter.lambda.py def get_multiples_of_five(n): return list(filter(lambda k: not k % 5, range(n))) print(get_multiples_of_five(50)) -- Function attributes func.attributes.py def multiplication(a, b=1): """Return a multiplied by b. """ return a * b special_attributes = [ "__doc__", "__name__", "__qualname__", "__module__", "__defaults__", "__code__", "__globals__", "__dict__", "__closure__", "__annotations__", "__kwdefaults__", ] for attribute in special_attributes: print(attribute, '->', getattr(multiplication, attribute)) $ python func.attributes.py -- Build-in functions inspecting the builtin module with dir(__builtin__) One final example primes.py from math import sqrt, ceil def get_primes(n): """Calculate a list of primes up to n (included). """ primelist = [] for candidate in range(2, n + 1): is_prime = True root = int(ceil(sqrt(candidate))) # division limit for prime in primelist: # we try only the primes if prime > root: # no need to check any further break if candidate % prime == 0: is_prime = False break if is_prime: primelist.append(candidate) return primelist -- Documenting your code from math import sqrt, ceil docstrings.py def square(n): """Return the square of a number n. """ return n ** 2 def get_username(userid): """Return the username of a user given their id. """ return db.get(user_id=userid).username docstrings.py def connect(host, port, user, password): """Connect to a database. Connect to a PostgreSQL database directly, using the given parameters. :param host: The host IP. :param port: The desired port. :param user: The connection username. :param password: The connection password. :return: The connection object. """ # body of the function here... return connection -- Importing objects from mymodule import myfunc as better_named_func karma/test_nt.py import unittest # imports the unittest module from math import sqrt # imports one function from math from random import randint, sample # two imports at once from mock import patch from nose.tools import ( # multiline import assert_equal, assert_list_equal, assert_not_in, ) from karma import nt, utils funcdef.py def square(n): return n ** 2 def cube(n): return n ** 3 func_import.py import lib.funcdef print(lib.funcdef.square(10)) print(lib.funcdef.cube(10)) func_from.py from lib.funcdef import square, cube print(square(10)) print(cube(10)) Relative imports Relative imports from .mymodule import myfunc Summary
Monday, March 21, 2016
Learning Python 4 - Functions
Labels:
Python
Subscribe to:
Post Comments (Atom)
Blog Archive
-
▼
2016
(87)
-
▼
March
(25)
- Learning Python 12 - Summing Up
- Learning Python 11 - Debugging and Troubleshooting
- Learning Python 10 - Web Development Done Right
- Learning Python 9 - Data Science
- Learning Python 8 - The GUIs and Scripts
- Learning Python 7 - Tesing, Profiling, and Dealing...
- Learning Python 6 - OOP, Decorators, and Iterators
- Learning Python 5 - Saving Time and Memory
- Learning Python 4 - Functions
- Learning Python 3 - Interating and Making Decisions
- Learning Python 2 - Build-in Data Types
- Learning Python 1 - Introduction
- Bandit algorithms 7 - Bandits in the Real World: C...
- Bandit algorithms 6 - UCB - The Upper Confidence B...
- Bandit algorithms 5 - The Softmax Algorithm
- Bandit algorithms 4 - Debugging Bandit Algorithms
- Bandit algorithms 3 - The Epsilon-Greedy Algorithm
- Bandit algorithms 2 - Multiarmed Bandit Algorithms
- Bandit algorithms 1 - Exploration and Exploitation
- Python Data Analysis 11 - Recognizing Handwritten ...
- Python Data Analysis 10 - Embedding the JavaScript...
- Python Data Analysis 9 - An Example - Meteorologic...
- Python Data Analysis 8 - Machine Learning with sci...
- Python Data Analysis 7 - Data Visualization with m...
- Python Data Analysis 6 - pandas in Depth: Data Man...
-
▼
March
(25)
No comments:
Post a Comment