Skip to content

Latest commit

 

History

History
187 lines (135 loc) · 9.65 KB

File metadata and controls

187 lines (135 loc) · 9.65 KB

Practical Function Examples

Example 1: Random Verification Code

Design a function to generate a random verification code. The verification code is made up of digits and uppercase and lowercase English letters, and the length can be set through a parameter.

import random
import string

ALL_CHARS = string.digits + string.ascii_letters


def generate_code(*, code_len=4):
    """
    Generate a verification code of the specified length.
    :param code_len: The length of the verification code (default is 4 characters)
    :return: A random verification code string made up of uppercase and lowercase English letters and digits
    """
    return ''.join(random.choices(ALL_CHARS, k=code_len))

Note 1: string.digits in the string module means the string '0123456789', and string.ascii_letters in the string module means the string 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.

Note 2: The sample and choices functions in the random module can both do random sampling. sample does sampling without replacement, which means the sampled elements are not repeated. choices does sampling with replacement, which means some elements may be chosen again. The first parameter of these two functions is the whole population to sample from, and the parameter k means the sample size. It should be noted that the parameter k of the choices function is a keyword-only parameter, so you must give the parameter name when passing it.

We can use the code below to generate 5 random verification codes to test the function above.

for _ in range(5):
    print(generate_code())

Or:

for _ in range(5):
    print(generate_code(code_len=6))

Note: The parameter of the generate_code function we designed is a keyword-only parameter. Because it has a default value, we can choose not to pass a value to it and use the default value 4. If we want to pass a value to the function, we must use the parameter name code_len.

Example 2: Check for Prime Numbers

Design a function that checks whether a given positive integer greater than 1 is a prime number. A prime number is a positive integer greater than 1 that can only be divided exactly by 1 and itself. If a positive integer $\small{N}$ greater than 1 is prime, that means there are no factors of it between 2 and $\small{N-1}$.

def is_prime(num: int) -> bool:
    """
    Determine whether a positive integer is prime.
    :param num: A positive integer greater than 1
    :return: True if num is prime, otherwise False
    """
    for i in range(2, int(num ** 0.5) + 1):
        if num % i == 0:
            return False
    return True

Note 1: The : int after the parameter num above is used to mark the parameter type. Although it does not affect the execution result of the code, it improves the readability of the code well. In the same way, -> bool after the parameter list is used to mark the return type of the function. It also does not affect the execution result of the code, but it clearly tells us that calling this function returns a Boolean value, either True or False.

Note 2: The loop above does not need to go from 2 all the way to $\small{N-1}$, because if by the time the loop reaches $\small{\sqrt{N}}$ we still have not found a factor of $\small{N}$, then no factor of $\small{N}$ will appear after $\small{\sqrt{N}}$. You can think for yourself about why that is.

Example 3: Greatest Common Divisor and Least Common Multiple

Design functions to calculate the greatest common divisor and the least common multiple of two positive integers. The greatest common divisor of $\small{x}$ and $\small{y}$ is the largest integer that can divide both $\small{x}$ and $\small{y}$ exactly. If $\small{x}$ and $\small{y}$ are coprime, then their greatest common divisor is 1. The least common multiple of $\small{x}$ and $\small{y}$ is the smallest positive integer that can be divided exactly by both $\small{x}$ and $\small{y}$. If $\small{x}$ and $\small{y}$ are coprime, then their least common multiple is $\small{x \times y}$. It should be noted that calculating the greatest common divisor and calculating the least common multiple are two different functions, so we should design them as two functions, instead of putting both functions into one function.

def lcm(x: int, y: int) -> int:
    """Compute the least common multiple."""
    return x * y // gcd(x, y)


def gcd(x: int, y: int) -> int:
    """Compute the greatest common divisor."""
    while y % x != 0:
        x, y = y % x, x
    return x

Note: Functions can call each other. The lcm function above calls the gcd function, and it uses $\frac{x \times y}{gcd(x, y)}$ to calculate the least common multiple.

Example 4: Data Statistics

Suppose sample data is saved in a list. Design functions to calculate the descriptive statistics of the sample data. Descriptive statistics usually include arithmetic mean, median, range, variance, standard deviation, coefficient of variation, and so on. The formulas are shown below.

def ptp(data):
    """Range."""
    return max(data) - min(data)


def mean(data):
    """Arithmetic mean."""
    return sum(data) / len(data)


def median(data):
    """Median."""
    temp, size = sorted(data), len(data)
    if size % 2 != 0:
        return temp[size // 2]
    else:
        return mean(temp[size // 2 - 1:size // 2 + 1])


def var(data, ddof=1):
    """Variance."""
    x_bar = mean(data)
    temp = [(num - x_bar) ** 2 for num in data]
    return sum(temp) / (len(temp) - ddof)


def std(data, ddof=1):
    """Standard deviation."""
    return var(data, ddof) ** 0.5


def cv(data, ddof=1):
    """Coefficient of variation."""
    return std(data, ddof) / mean(data)


def describe(data):
    """Print descriptive statistics."""
    print(f'均值: {mean(data)}')
    print(f'中位数: {median(data)}')
    print(f'极差: {ptp(data)}')
    print(f'方差: {var(data)}')
    print(f'标准差: {std(data)}')
    print(f'变异系数: {cv(data)}')

Note 1: The median is the number in the middle after sorting the data in ascending or descending order, and it describes the middle level of the data. There are two cases when calculating the median: when the amount of data $\small{n}$ is odd, the median is the element at position $\frac{n + 1}{2}$; when the amount of data $\small{n}$ is even, the median is the average of the elements at positions $\frac{n}{2}$ and $\frac{n}{2} + 1`.

Note 2: In the functions that calculate variance and standard deviation, there is a parameter named ddof. It means the adjustable degrees of freedom, and its default value is 1. When calculating sample variance and sample standard deviation, we need to do degree-of-freedom correction. If we want to calculate population variance and population standard deviation, we can set the ddof parameter to 0, which means no degree-of-freedom correction is needed.

Note 3: The describe function puts the statistics functions above together and is used to output the descriptive statistics of the data. In fact, Python's standard library has a module named statistics, and it has already packaged functions for getting descriptive statistics. Interested readers can learn about it by themselves.

Example 5: Double Color Ball Lottery Number Generator

Let us use functions to refactor the Double Color Ball example from an earlier lesson. We package the function that generates random numbers and the function that outputs one group of numbers into two functions, and then use function calls to generate N random tickets.

"""
Random number generator for Double Color Ball

Author: Luo Hao
Version: 1.3
"""
import random

RED_BALLS = [i for i in range(1, 34)]
BLUE_BALLS = [i for i in range(1, 17)]


def choose():
    """
    Generate one group of random numbers.
    :return: A list that saves the random numbers
    """
    selected_balls = random.sample(RED_BALLS, 6)
    selected_balls.sort()
    selected_balls.append(random.choice(BLUE_BALLS))
    return selected_balls


def display(balls):
    """
    Print one group of numbers in a formatted way.
    :param balls: A list that saves the random numbers
    """
    for ball in balls[:-1]:
        print(f'\033[031m{ball:0>2d}\033[0m', end=' ')
    print(f'\033[034m{balls[-1]:0>2d}\033[0m')


n = int(input('生成几注号码: '))
for _ in range(n):
    display(choose())

Note: Look at the line display(choose()). Here, we first use the choose function to get one group of random numbers, then use the return value of the choose function as the parameter of the display function, and use the display function to show the selected random numbers. After refactoring, the logic of the code becomes very clear, and the readability of the code becomes stronger. If someone already packaged these two functions for you, and you are only the caller of the functions, then you do not need to care about the internal implementation of the choose function and the display function at all. You only need to know that calling the choose function can generate one group of random numbers, and calling the display function with a list can output that group of numbers. In the future, when we use many third-party Python libraries, we also do not care about their bottom-layer implementation. What we need to know is only which function to call to solve the problem.

Summary

When writing code, especially when developing commercial projects, we should consciously package relatively independent functions that will be used repeatedly into functions. In this way, both you and other team members can use these functions by calling them, and this can reduce repeated and boring work in development.