Python十个经典例子(排序、递归、设计模式、装饰器等)

一、实现查找功能的模块

"""
实现查找功能的模块
"""


def seq_search(items, elem):
    """顺序查找"""
    for index, item in enumerate(items):
        if item == elem:
            return index
    return -1

def bin_search(items, elem):
    """折半查找(二分查找)"""
    start, end = 0, len(items) - 1
    while start <= end:
        mid = (start + end) // 2
        if elem < items[mid]:
            end = mid - 1
        elif elem > items[mid]:
            start = mid + 1
        else:
            return mid
    return -1

二、排序

"""
排序 - 冒泡排序(简单O(N**2)) / 归并排序(高级O(N*log2N))
冒泡排序
34, 99, 52, 11, 47, 68, 50, 84
34, 52, 11, 47, 68, 50, 84, 99
34, 11, 47, 52, 50, 68, 84
11, 34, 47, 50, 52, 68

快速排序
34, 99, 52, 11, 47, 68, 50, 84
{34, 11, 47}, {50}, {99, 52, 68, 84}
{11}, {34}, {47}, {50}, {52, 68, 84}, {99}
{11}, {34}, {47}, {50}, {52}, {68, 84}, {99}
{11}, {34}, {47}, {50}, {52}, {68}, {84}, {99}

归并排序 - 分治法(divide-and-conquer)
34, 99, 52, 11, 47, 68, 50, 84
{34, 99, 52, 11}, {47, 68, 50, 84}
{34, 99}, {52, 11}, {47, 68}, {50, 84}
{34}, {99}, {52}, {11}, {47}, {68}, {50}, {84}
{34, 99}, {11, 52}, {47, 68}, {50, 84}
{11, 34, 52, 99}, {47, 50, 68, 84}
{11, 34, 47, 50, 52, 68, 84, 99}

在使用分治法的时候通常都会使用到递归调用这种编程手段
一个函数直接或间接的调用了自身就称之为递归调用
"""


# 9 1 2 3 4 5 6 7 8
# 2 3 4 5 6 7 8 9 1
# *前面的参数称为位置参数, *后面的参数称为命名关键字参数
# 所谓命名关键字参数就是调用函数时必须以"参数名=参数值"的形式传入参数
def bubble_sort(origin_items, *, comp=lambda x, y: x > y):
    """冒泡排序"""
    items = origin_items[:]
    length = len(items)
    for i in range(1, length):
        swapped = False
        for j in range(0, length - i):
            if comp(items[j], items[j + 1]):
                items[j], items[j + 1] = items[j + 1], items[j]
                swapped = True
        if swapped:
            swapped = False
            for j in range(length - i - 1, i - 1, -1):
                if comp(items[j - 1], items[j]):
                    items[j - 1], items[j] = items[j], items[j - 1]
                    swapped = True
        if not swapped:
            break
    return items


def merge(list1, list2, comp=lambda x, y: x <= y):
    """"有序合并(将两个有序的列表合并成一个新的有序的列表)"""
    list3 = []
    index1, index2 = 0, 0
    while index1 < len(list1) and index2 < len(list2):
        if comp(list1[index1], list2[index2]):
            list3.append(list1[index1])
            index1 += 1
        else:
            list3.append(list2[index2])
            index2 += 1
    list3 += list1[index1:]
    list3 += list2[index2:]
    return list3


def merge_sort(origin_items, comp=lambda x, y: x <= y):
    """归并排序"""
    if len(origin_items) <= 1:
        return origin_items[:]
    mid = len(origin_items) // 2
    left = merge_sort(origin_items[:mid], comp)
    right = merge_sort(origin_items[mid:], comp)
    return merge(left, right, comp)


class Person:
    """人"""

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return f'{self.name}: {self.age}'


def main():
    # list1 = [12, 35, 48, 87, 92]
    # list2 = [39, 44, 50, 60, 77, 88]
    # list3 = merge(list1, list2)
    # print(list3)
    items = [34, 99, 52, 11, 47, 50, 84]
    print(items)
    print(merge_sort(items))
    # items = ['hi', 'hello', 'orange', 'watermelon', 'zoo', 'pitaya']
    # items = [
    #     Person("LuoHao", 38), Person("Baiyuanfang", 25),
    #     Person("Zhangsanfeng", 120), Person("Lee", 18)
    # ]
    # new_items = bubble_sort(items, comp=lambda x, y: len(x) > len(y))
    # new_items = bubble_sort(items, comp=lambda x, y: x.age > y.age)
    # print(items)
    # print(new_items)


if __name__ == '__main__':
    main()


三、递归(recursion)

"""
递归(recursion)
"""


def fac(num):
    """求阶乘"""
    if num in (0, 1):
        return 1
    return num * fac(num - 1)


# 动态规划 - 把求解问题的中间结果保存起来
# 这种算法适合求解有最优子结构的问题或子问题会重复求解的问题
def fib(num, temp={}):
    """计算斐波拉切数"""
    # 递归的两个要素
    # 收敛条件 - 什么时候结束递归
    if num in (1, 2):
        return 1
    # 递归公式 - 降低问题的求解难度
    try:
        return temp[num]
    except KeyError:
        temp[num] = fib(num - 1) + fib(num - 2)
        return temp[num]


def fib2(total):
    """斐波拉切数列生成器"""
    num1, num2 = 0, 1
    for _ in range(total):
        num1, num2 = num2, num1 + num2
        yield num1


def main():
    """主函数"""
    for num in fib2(120):
        print(num)


if __name__ == '__main__':
    main()

四、设计范式:扑克牌的例子

"""
程序设计的范式(理念):
1. 指令式程序设计 - 汇编语言
2. 面向过程程序设计 - 把一组指令封装成一个过程,需要执行这组指令时调用这个过程即可 - C
3. 面向对象程序设计 - 将数据和操作数据的函数从逻辑上组织成了对象 - C++ / Java
4. 函数式程序设计 - 函数是一等对象(一等公民) - Haskell

面向对象程序设计步骤:
1. 定义类 - 抽象过程 - 数据抽象(静态特征-属性)/行为抽象(动态特征-方法)
2. 创建对象 - 构造器 - 初始化(__init__)
3. 给对象发消息 - 对象引用.对象方法(参数)

面向对象的三大支柱 - 封装 / 继承 / 多态

类与类(对象与对象)之间的关系:
1. is-a: 继承
2. has-a: 关联 / 聚合 / 合成
3. use-a: 依赖

面向对象的设计原则/SOLID原则:
1. 单一职责原则 - 类的设计要高内聚
2. 开闭原则 - 接受扩展不接受修改 - 抽象是关键/用继承封装可变性
3. 依赖倒转原则 - 面向抽象编程
4. 里氏替换原则 - 任何时候都可以使用子类型对象替换父类型对象
5. 接口隔离原则
6. 合成聚合复用原则 - 优先考虑用强关联而不是继承去复用代码
7. 最少知识原则(迪米特法则) - 不要跟陌生人讲话

GoF设计模式 - 23种场景(Python中有16中已经被弱化)
- 单例、工厂、原型、适配器、观察者、策略
"""
from enum import Enum
from enum import unique

import random

# 经验: 符号常量优于字面常量
# 枚举类型是定义符号常量的最佳选择
# 如果一个变量的值只有有限多个选项那么最好使用枚举
@unique
class Suite(Enum):
    """花色"""

    SPADE = 0
    HEART = 1
    CLUB = 2
    DIAMOND = 3


class Card():
    """牌"""

    def __init__(self, suite, face):
        self.suite = suite
        self.face = face

    def show(self):
        """显示牌的花色和点数"""
        suites = ['♠️', '♥️', '♣️', '♦️']
        faces = [
            '', 'A', '2', '3', '4', '5', '6',
            '7', '8', '9', '10', 'J', 'Q', 'K'
        ]
        return f'{suites[self.suite.value]} {faces[self.face]}'

    def __str__(self):
        return self.show()

    def __repr__(self):
        return self.show()


class Poker():
    """扑克"""

    def __init__(self):
        self.index = 0
        self.cards = [Card(suite, face)
                      for suite in Suite
                      for face in range(1, 14)]

    def shuffle(self):
        """洗牌"""
        random.shuffle(self.cards)

    def deal(self):
        """发牌"""
        temp = self.cards[self.index]
        self.index += 1
        return temp

    @property
    def has_more(self):
        """是否有牌可以发"""
        return self.index < len(self.cards)


class Player():
    """玩家"""

    def __init__(self, name):
        self.name = name
        self.cards = []

    def get_one(self, card):
        """摸一张牌"""
        self.cards.append(card)

    def drop_one(self, index):
        """打出一张牌"""
        return self.cards.remove(index)

    def get_many(self, more_cards):
        """摸多张牌"""
        self.cards += more_cards

    def drop_cards(self):
        """扔掉所有牌"""
        self.cards.clear()

    def arrange(self):
        """整理手上的牌"""
        self.cards.sort(key=lambda x: (x.suite.value, x.face))


def main():
    """主函数"""
    poker = Poker()
    poker.shuffle()
    players = [
        Player("刘备"), Player("关羽"),
        Player("张飞"), Player("曹操")
    ]
    for _ in range(3):
        for player in players:
            if poker.has_more:
                player.get_one(poker.deal())
    for player in players:
        player.arrange()
        print(player.name)
        print(player.cards)


if __name__ == '__main__':
    main()

五、设计模式-策略模式

"""
设计模式 - 策略模式(指定的策略不同执行的算法不同)
"""
from hashlib import md5
from hashlib import sha1
from hashlib import sha256
from hashlib import sha512


class StreamHasher():
    """哈希摘要生成器"""

    def __init__(self, algorithm='md5', size=1024):
        self.size = size
        alg = algorithm.lower()
        if alg == 'md5':
            self.hasher = md5()
        elif alg == 'sha1':
            self.hasher = sha1()
        elif alg == 'sha256':
            self.hasher = sha256()
        elif alg == 'sha512':
            self.hasher = sha512()
        else:
            raise ValueError('不支持指定的摘要算法')

    # 魔法方法: 让对象可以像函数一样被调用
    def __call__(self, stream):
        return self.to_digest(stream)

    def to_digest(self, stream):
        """生成十六进制形式的哈希摘要字符串"""
        for data in iter(lambda: stream.read(self.size), b''):
            self.hasher.update(data)
        return self.hasher.hexdigest()


def main():
    """主函数"""
    hasher = StreamHasher('sha1', 4096)
    with open('Python魔法方法指南.pdf', 'rb') as stream:
        # print(hasher.to_digest(stream))
        print(hasher(stream))


if __name__ == '__main__':
    main()

六、抽象类/继承/多态

"""
抽象类 / 继承 / 多态
"""
from abc import ABCMeta, abstractmethod


class Employee(metaclass=ABCMeta):
    """员工"""

    def __init__(self, name):
        self.name = name

    @abstractmethod
    def get_salary(self):
        """结算月薪"""
        pass


class Manager(Employee):
    """部门经理"""

    def get_salary(self):
        return 15000


class Programmer(Employee):
    """程序员"""

    def __init__(self, name):
        super().__init__(name)
        self._working_hour = 0

    @property
    def working_hour(self):
        return self._working_hour

    @working_hour.setter
    def working_hour(self, _working_hour):
        self._working_hour = 0 if _working_hour < 0 \
            else _working_hour

    def get_salary(self):
        return 200 * self.working_hour


class Salesman(Employee):
    """销售员"""

    def __init__(self, name):
        super().__init__(name)
        self._sales = 0

    @property
    def sales(self):
        return self._sales
    
    @sales.setter
    def sales(self, _sales):
        self._sales = 0 if _sales < 0 else _sales

    def get_salary(self):
        return 1800 + 0.05 * self.sales


def main():
    """主函数"""
    emps = [
        Programmer("王大锤"), Manager("武则天"),
        Programmer("狄仁杰"), Salesman("白洁"),
        Programmer("白元芳"), Salesman("冷面")
    ]
    for emp in emps:
        if isinstance(emp, Programmer):
            emp.working_hour = int(input(f'{emp.name}本月工作时间: '))
        elif isinstance(emp, Salesman):
            emp.sales = float(input(f'{emp.name}本月销售额: '))
        print("%s本月工资为: ¥%.2f元" % (emp.name, emp.get_salary()))


if __name__ == '__main__':
    main()

七、单例模式

"""
设计模式 - 单例模式(让一个类只能创建唯一的实例)
"""


class SingletonMeta(type):
    """单例类的元类(描述其他类的类)"""

    def __init__(cls, *args, **kwargs):
        cls.__instance = None

    def __call__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__call__(*args, **kwargs)
        return cls.__instance


class President(metaclass=SingletonMeta):
    """总统(单例类)"""

    def __init__(self, name):
        self.name = name


def main():
    p1 = President("王大锤")
    p2 = President("奥巴马")
    print(p1.name)
    print(p2.name)
    print(p1 == p2)
    print(p1 is p2)


if __name__ == '__main__':
    main()

八、单例模式2

"""
设计模式 - 单例模式(让一个类只能创建唯一的实例)
"""
from functools import wraps


def singleton(cls):
    instances = {}

    @wraps(cls)
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper


@singleton
class President():
    """总统(单例类)"""

    def __init__(self, name):
        self.name = name


def main():
    p1 = President("王大锤")
    p2 = President("奥巴马")
    print(p1.name)
    print(p2.name)
    print(p1 == p2)
    print(p1 is p2)
    print('-' * 30)
    President2 = President.__wrapped__
    p2 = President2("奥巴马")
    print(p1.name)
    print(p2.name)
    print(p1 == p2)
    print(p1 is p2)



if __name__ == '__main__':
    main()

九、装饰器

"""
装饰器 - 背后的设计模式是代理模式(注意不是装饰器模式)
代理模式通常是让代理对象去执行被代理对象的行为并在这个过程中增加额外的操作
这种设计模式最适合处理代码中的横切关注功能(与正常业务没有必然联系但是又需要执行的功能)
"""
from functools import wraps
from time import time


def record(*, output=print):
    
    def decorate(func):
        
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time()
            result = func(*args, **kwargs)
            output(func.__name__, time() - start)
            return result
            
        return wrapper
    
    return decorate


@record()
def some_task():
    print(123 ** 100000)


if __name__ == '__main__':
    some_task()
    print(some_task.__name__)
    # 取消装饰器
    some_task = some_task.__wrapped__
    some_task()

十、作用域

"""
作用域 - Local -> Embedded -> Global -> Built-in
"""
def foo():
    x = 300

    def bar():
        nonlocal x
        x = 200
        print(x)

    bar()
    print(x)


if __name__ == '__main__':
    foo()

你可能感兴趣的:(Python)