Python基础入门教程:Day16-20/Python语言进阶

Python基础入门教程:Python语言进阶


数据结构和算法
  • 算法:解决问题的方法和步骤

  • 评价算法的好坏:渐近时间复杂度和渐近空间复杂度。

  • 渐近时间复杂度的大O标记:

    • - 常量时间复杂度 - 布隆过滤器 / 哈希存储
    • - 对数时间复杂度 - 折半查找(二分查找)
    • - 线性时间复杂度 - 顺序查找 / 桶排序
    • - 对数线性时间复杂度 - 高级排序算法(归并排序、快速排序)
    • - 平方时间复杂度 - 简单排序算法(选择排序、插入排序、冒泡排序)
    • - 立方时间复杂度 - Floyd算法 / 矩阵乘法运算
    • - 几何级数时间复杂度 - 汉诺塔
    • - 阶乘时间复杂度 - 旅行经销商问题 - NP

  • 排序算法(选择、冒泡和归并)和查找算法(顺序和折半)

    def select_sort(origin_items, comp=lambda x, y: x < y):
        """简单选择排序"""
        items = origin_items[:]
        for i in range(len(items) - 1):
            min_index = i
            for j in range(i + 1, len(items)):
                if comp(items[j], items[min_index]):
                    min_index = j
            items[i], items[min_index] = items[min_index], items[i]
        return items复制代码
    def bubble_sort(origin_items, comp=lambda x, y: x > y):
        """高质量冒泡排序(搅拌排序)"""
        items = origin_items[:]
        for i in range(len(items) - 1):
            swapped = False
            for j in range(i, len(items) - 1 - 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(len(items) - 2 - i, i, -1):
                    if comp(items[j - 1], items[j]):
                        items[j], items[j - 1] = items[j - 1], items[j]
                        swapped = True
            if not swapped:
                break
        return items复制代码
    def merge_sort(items, comp=lambda x, y: x <= y):
        """归并排序(分治法)"""
        if len(items) < 2:
            return items[:]
        mid = len(items) // 2
        left = merge_sort(items[:mid], comp)
        right = merge_sort(items[mid:], comp)
        return merge(left, right, comp)
    
    
    def merge(items1, items2, comp):
        """合并(将两个有序的列表合并成一个有序的列表)"""
        items = []
        index, index2 = 0, 0
        while index1 < len(items1) and index2 < len(items2):
            if comp(items1[index1], items2[index2]):
                items.append(items1[index1])
                index1 += 1
            else:
                items.append(items2[index2])
                index2 += 1
        items += items1[index1:]
        items += items2[index2:]
        return items复制代码
    def seq_search(items, key):
        """顺序查找"""
        for index, item in enumerate(items):
            if item == key:
                return index
        return -1复制代码
    def bin_search(items, key):
        """折半查找"""
        start, end = 0, len(items) - 1
        while start <= end:
            mid = (start + end) // 2
            if key > items[mid]:
                start = mid + 1
            elif key < items[mid]:
                end = mid - 1
            else:
                return mid
        return -1复制代码
  • 使用生成式(推导式)语法

    prices = {
        'AAPL': 191.88,
        'GOOG': 1186.96,
        'IBM': 149.24,
        'ORCL': 48.44,
        'ACN': 166.89,
        'FB': 208.09,
        'SYMC': 21.29
    }
    # 用股票价格大于100元的股票构造一个新的字典
    prices2 = {key: value for key, value in prices.items() if value > 100}
    print(prices2)复制代码

    说明:生成式(推导式)可以用来生成列表、集合和字典。

  • 嵌套的列表

    names = ['关羽', '张飞', '赵云', '马超', '黄忠']
    courses = ['语文', '数学', '英语']
    # 录入五个学生三门课程的成绩
    # 错误 - 参考http://pythontutor.com/visualize.html#mode=edit
    # scores = [[None] * len(courses)] * len(names)
    scores = [[None] * len(courses) for _ in range(len(names))]
    for row, name in enumerate(names):
        for col, course in enumerate(courses):
            scores[row][col] = float(input(f'请输入{name}的{course}成绩: '))
            print(scores)复制代码

    Python Tutor - VISUALIZE CODE AND GET LIVE HELP

  • heapq、itertools等的用法

    """
    从列表中找出最大的或最小的N个元素
    堆结构(大根堆/小根堆)
    """
    import heapq
    
    list1 = [34, 25, 12, 99, 87, 63, 58, 78, 88, 92]
    list2 = [
        {'name': 'IBM', 'shares': 100, 'price': 91.1},
        {'name': 'AAPL', 'shares': 50, 'price': 543.22},
        {'name': 'FB', 'shares': 200, 'price': 21.09},
        {'name': 'HPQ', 'shares': 35, 'price': 31.75},
        {'name': 'YHOO', 'shares': 45, 'price': 16.35},
        {'name': 'ACME', 'shares': 75, 'price': 115.65}
    ]
    print(heapq.nlargest(3, list1))
    print(heapq.nsmallest(3, list1))
    print(heapq.nlargest(2, list2, key=lambda x: x['price']))
    print(heapq.nlargest(2, list2, key=lambda x: x['shares']))复制代码
    """
    迭代工具 - 排列 / 组合 / 笛卡尔积
    """
    import itertools
    
    itertools.permutations('ABCD')
    itertools.combinations('ABCDE', 3)
    itertools.product('ABCD', '123')复制代码
  • collections模块下的工具类

    """
    找出序列中出现次数最多的元素
    """
    from collections import Counter
    
    words = [
        'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
        'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around',
        'the', 'eyes', "don't", 'look', 'around', 'the', 'eyes',
        'look', 'into', 'my', 'eyes', "you're", 'under'
    ]
    counter = Counter(words)
    print(counter.most_common(3))复制代码











  • 常用算法:

    • 穷举法 - 又称为暴力破解法,对所有的可能性进行验证,直到找到正确答案。
    • 贪婪法 - 在对问题求解时,总是做出在当前看来是最好的选择,不追求最优解,快速找到满意解。
    • 分治法 - 把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题,直到可以直接求解的程度,最后将子问题的解进行合并得到原问题的解。
    • 回溯法 - 回溯法又称为试探法,按选优条件向前搜索,当搜索到某一步发现原先选择并不优或达不到目标时,就退回一步重新选择。
    • 动态规划 - 基本思想也是将待求解问题分解成若干个子问题,先求解并保存这些子问题的解,避免产生大量的重复运算。


    穷举法例子:百钱百鸡和五人分鱼。

    # 公鸡5元一只 母鸡3元一只 小鸡1元三只
    # 用100元买100只鸡 问公鸡/母鸡/小鸡各多少只
    for x in range(20):
        for y in range(33):
            z = 100 - x - y
            if 5 * x + 3 * y + z // 3 == 100 and z % 3 == 0:
                print(x, y, z)
    
    # A、B、C、D、E五人在某天夜里合伙捕鱼 最后疲惫不堪各自睡觉
    # 第二天A第一个醒来 他将鱼分为5份 扔掉多余的1条 拿走自己的一份
    # B第二个醒来 也将鱼分为5份 扔掉多余的1条 拿走自己的一份
    # 然后C、D、E依次醒来也按同样的方式分鱼 问他们至少捕了多少条鱼
    fish = 1
    while True:
        total = fish
        enough = True
        for _ in range(5):
            if (total - 1) % 5 == 0:
                total = (total - 1) // 5 * 4
            else:
                enough = False
                break
        if enough:
            print(fish)
            break
        fish += 1复制代码

    贪婪法例子:假设小偷有一个背包,最多能装20公斤赃物,他闯入一户人家,发现如下表所示的物品。很显然,他不能把所有物品都装进背包,所以必须确定拿走哪些物品,留下哪些物品。

    名称 价格(美元) 重量(kg)
    电脑 200 20
    收音机 20 4
    175 10
    花瓶 50 2
    10 1
    油画 90 9
    """
    贪婪法:在对问题求解时,总是做出在当前看来是最好的选择,不追求最优解,快速找到满意解。
    输入:
    20 6
    电脑 200 20
    收音机 20 4
    钟 175 10
    花瓶 50 2
    书 10 1
    油画 90 9
    """
    class Thing(object):
        """物品"""
    
        def __init__(self, name, price, weight):
            self.name = name
            self.price = price
            self.weight = weight
    
        @property
        def value(self):
            """价格重量比"""
            return self.price / self.weight
    
    
    def input_thing():
        """输入物品信息"""
        name_str, price_str, weight_str = input().split()
        return name_str, int(price_str), int(weight_str)
    
    
    def main():
        """主函数"""
        max_weight, num_of_things = map(int, input().split())
        all_things = []
        for _ in range(num_of_things):
            all_things.append(Thing(*input_thing()))
        all_things.sort(key=lambda x: x.value, reverse=True)
        total_weight = 0
        total_price = 0
        for thing in all_things:
            if total_weight + thing.weight <= max_weight:
                print(f'小偷拿走了{thing.name}')
                total_weight += thing.weight
                total_price += thing.price
        print(f'总价值: {total_price}美元')
    
    
    if __name__ == '__main__':
        main()复制代码

    分治法例子:快速排序。

    """
    快速排序 - 选择枢轴对元素进行划分,左边都比枢轴小右边都比枢轴大
    """
    def quick_sort(origin_items, comp=lambda x, y: x <= y):
        items = origin_items[:]
        _quick_sort(items, 0, len(items) - 1, comp)
        return items
    
    
    def _quick_sort(items, start, end, comp):
        if start < end:
            pos = _partition(items, start, end, comp)
            _quick_sort(items, start, pos - 1, comp)
            _quick_sort(items, pos + 1, end, comp)
    
    
    def _partition(items, start, end, comp):
        pivot = items[end]
        i = start - 1
        for j in range(start, end):
            if comp(items[j], pivot):
                i += 1
                items[i], items[j] = items[j], items[i]
        items[i + 1], items[end] = items[end], items[i + 1]
        return i + 1复制代码

    回溯法例子:骑士巡逻。

    """
    递归回溯法:叫称为试探法,按选优条件向前搜索,当搜索到某一步,发现原先选择并不优或达不到目标时,就退回一步重新选择,比较经典的问题包括骑士巡逻、八皇后和迷宫寻路等。
    """
    import sys
    import time
    
    SIZE = 5
    total = 0
    
    
    def print_board(board):
        for row in board:
            for col in row:
                print(str(col).center(4), end='')
            print()
    
    
    def patrol(board, row, col, step=1):
        if row >= 0 and row < SIZE and \
            col >= 0 and col < SIZE and \
            board[row][col] == 0:
            board[row][col] = step
            if step == SIZE * SIZE:
                global total
                total += 1
                print(f'第{total}种走法: ')
                print_board(board)
            patrol(board, row - 2, col - 1, step + 1)
            patrol(board, row - 1, col - 2, step + 1)
            patrol(board, row + 1, col - 2, step + 1)
            patrol(board, row + 2, col - 1, step + 1)
            patrol(board, row + 2, col + 1, step + 1)
            patrol(board, row + 1, col + 2, step + 1)
            patrol(board, row - 1, col + 2, step + 1)
            patrol(board, row - 2, col + 1, step + 1)
            board[row][col] = 0
    
    
    def main():
        board = [[0] * SIZE for _ in range(SIZE)]
        patrol(board, SIZE - 1, SIZE - 1)
    
    
    if __name__ == '__main__':
        main()复制代码

    动态规划例子1:斐波拉切数列。(不使用动态规划将会是几何级数复杂度)

    """
    动态规划 - 适用于有重叠子问题和最优子结构性质的问题
    使用动态规划方法所耗时间往往远少于朴素解法(用空间换取时间)
    """
    def fib(num, temp={}):
        """用递归计算Fibonacci数"""
        if num in (1, 2):
            return 1
        try:
            return temp[num]
        except KeyError:
            temp[num] = fib(num - 1) + fib(num - 2)
            return temp[num]复制代码

    动态规划例子2:子列表元素之和的最大值。(使用动态规划可以避免二重循环)

    说明:子列表指的是列表中索引(下标)连续的元素构成的列表;列表中的元素是int类型,可能包含正整数、0、负整数;程序输入列表中的元素,输出子列表元素求和的最大值,例如:

    输入:1 -2 3 5 -3 2

    输出:8

    输入:0 -2 3 5 -1 2

    输出:9

    输入:-9 -2 -3 -5 -3

    输出:-2

    def main():
        items = list(map(int, input().split()))
        size = len(items)
        overall, partial = {}, {}
        overall[size - 1] = partial[size - 1] = items[size - 1]
        for i in range(size - 2, -1, -1):
            partial[i] = max(items[i], partial[i + 1] + items[i])
            overall[i] = max(partial[i], overall[i + 1])
        print(overall[0])
    
    
    if __name__ == '__main__':
        main()复制代码

函数的使用方式

  • 将函数视为“一等公民”

    • 函数可以赋值给变量
    • 函数可以作为函数的参数
    • 函数可以作为函数的返回值
  • 高阶函数的用法(filtermap以及它们的替代品)

    items1 = list(map(lambda x: x ** 2, filter(lambda x: x % 2, range(1, 10))))
    items2 = [x ** 2 for x in range(1, 10) if x % 2]复制代码
  • 位置参数、可变参数、关键字参数、命名关键字参数

  • 参数的元信息(代码可读性问题)

  • 匿名函数和内联函数的用法(lambda函数)

  • 闭包和作用域问题

    • Python搜索变量的LEGB顺序(Local --> Embedded --> Global --> Built-in)

    • globalnonlocal关键字的作用

      global:声明或定义全局变量(要么直接使用现有的全局作用域的变量,要么定义一个变量放到全局作用域)。

      nonlocal:声明使用嵌套作用域的变量(嵌套作用域必须存在该变量,否则报错)。

  • 装饰器函数(使用装饰器和取消装饰器)

    例子:输出函数执行时间的装饰器。

    def record_time(func):
        """自定义装饰函数的装饰器"""
        
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time()
            result = func(*args, **kwargs)
            print(f'{func.__name__}: {time() - start}秒')
            return result
            
        return wrapper复制代码

    如果装饰器不希望跟print函数耦合,可以编写带参数的装饰器。

    from functools import wraps
    from time import time
    
    
    def record(output):
        """自定义带参数的装饰器"""
    	
    	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复制代码
    from functools import wraps
    from time import time
    
    
    class Record():
        """自定义装饰器类(通过__call__魔术方法使得对象可以当成函数调用)"""
    
        def __init__(self, output):
            self.output = output
    
        def __call__(self, func):
    
            @wraps(func)
            def wrapper(*args, **kwargs):
                start = time()
                result = func(*args, **kwargs)
                self.output(func.__name__, time() - start)
                return result
    
            return wrapper复制代码

    说明:由于对带装饰功能的函数添加了@wraps装饰器,可以通过func.__wrapped__方式获得被装饰之前的函数或类来取消装饰器的作用。

    例子:用装饰器来实现单例模式。

    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():
        """总统(单例类)"""
        pass复制代码

    说明:上面的代码中用到了闭包(closure),不知道你是否已经意识到了。还没有一个小问题就是,上面的代码并没有实现线程安全的单例,如果要实现线程安全的单例应该怎么做呢?

    from functools import wraps
    
    
    def singleton(cls):
        """线程安全的单例装饰器"""
        instances = {}
        locker = Lock()
    
        @wraps(cls)
        def wrapper(*args, **kwargs):
            if cls not in instances:
                with locker:
                    if cls not in instances:
                        instances[cls] = cls(*args, **kwargs)
            return instances[cls]
    
        return wrapper复制代码


面向对象相关知识

  • 三大支柱:封装、继承、多态

    例子:工资结算系统。

    """
    月薪结算系统 - 部门经理每月15000 程序员每小时200 销售员1800底薪加销售额5%提成
    """
    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.0
    
    
    class Programmer(Employee):
        """程序员"""
    
        def __init__(self, name, working_hour=0):
            self.working_hour = working_hour
            super().__init__(name)
    
        def get_salary(self):
            return 200.0 * self.working_hour
    
    
    class Salesman(Employee):
        """销售员"""
    
        def __init__(self, name, sales=0.0):
            self.sales = sales
            super().__init__(name)
    
        def get_salary(self):
            return 1800.0 + self.sales * 0.05
    
    
    class EmployeeFactory():
        """创建员工的工厂(工厂模式 - 通过工厂实现对象使用者和对象之间的解耦合)"""
    
        @staticmethod
        def create(emp_type, *args, **kwargs):
            """创建员工"""
            emp_type = emp_type.upper()
            emp = None
            if emp_type == 'M':
                emp = Manager(*args, **kwargs)
            elif emp_type == 'P':
                emp = Programmer(*args, **kwargs)
            elif emp_type == 'S':
                emp = Salesman(*args, **kwargs)
            return emp
    
    
    def main():
        """主函数"""
        emps = [
            EmployeeFactory.create('M', '曹操'), 
            EmployeeFactory.create('P', '荀彧', 120),
            EmployeeFactory.create('P', '郭嘉', 85), 
            EmployeeFactory.create('S', '典韦', 123000),
        ]
        for emp in emps:
            print('%s: %.2f元' % (emp.name, emp.get_salary()))
    
    
    if __name__ == '__main__':
        main()复制代码
  • 类与类之间的关系

    • is-a关系:继承
    • has-a关系:关联 / 聚合 / 合成
    • use-a关系:依赖

    例子:扑克游戏。

    """
    经验:符号常量总是优于字面常量,枚举类型是定义符号常量的最佳选择
    """
    from enum import Enum, unique
    
    import random
    
    
    @unique
    class Suite(Enum):
        """花色"""
    
        SPADE, HEART, CLUB, DIAMOND = range(4)
    
        def __lt__(self, other):
            return self.value < other.value
    
    
    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)
            self.index = 0
    
        def deal(self):
            """发牌"""
            card = self.cards[self.index]
            self.index += 1
            return card
    
        @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 sort(self, comp=lambda card: (card.suite, card.face)):
            """整理手上的牌"""
            self.cards.sort(key=comp)
    
    
    def main():
        """主函数"""
        poker = Poker()
        poker.shuffle()
        players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
        while poker.has_more:
            for player in players:
                    player.get_one(poker.deal())
        for player in players:
            player.sort()
            print(player.name, end=': ')
            print(player.cards)
    
    
    if __name__ == '__main__':
        main()复制代码
  • 对象的复制(深复制/深拷贝/深度克隆和浅复制/浅拷贝/影子克隆)

  • 垃圾回收、循环引用和弱引用

    Python使用了自动化内存管理,这种管理机制以引用计数为基础,同时也引入了标记-清除分代收集两种机制为辅的策略。

    typedef struct_object {
        /* 引用计数 */
        int ob_refcnt;
        /* 对象指针 */
        struct_typeobject *ob_type;
    } PyObject;复制代码
    /* 增加引用计数的宏定义 */
    #define Py_INCREF(op)   ((op)->ob_refcnt++)
    /* 减少引用计数的宏定义 */
    #define Py_DECREF(op) \ //减少计数
        if (--(op)->ob_refcnt != 0) \
            ; \
        else \
            __Py_Dealloc((PyObject *)(op))复制代码

    导致引用计数+1的情况:

    • 对象被创建,例如a = 23
    • 对象被引用,例如b = a
    • 对象被作为参数,传入到一个函数中,例如f(a)
    • 对象作为一个元素,存储在容器中,例如list1 = [a, a]

    导致引用计数-1的情况:

    • 对象的别名被显式销毁,例如del a
    • 对象的别名被赋予新的对象,例如a = 24
    • 一个对象离开它的作用域,例如f函数执行完毕时,f函数中的局部变量(全局变量不会)
    • 对象所在的容器被销毁,或从容器中删除对象

    引用计数可能会导致循环引用问题,而循环引用会导致内存泄露,如下面的代码所示。为了解决这个问题,Python中引入了“标记-清除”和“分代收集”。在创建一个对象的时候,对象被放在第一代中,如果在第一代的垃圾检查中对象存活了下来,该对象就会被放到第二代中,同理在第二代的垃圾检查中对象存活下来,该对象就会被放到第三代中。

    # 循环引用会导致内存泄露 - Python除了引用技术还引入了标记清理和分代回收
    # 在Python 3.6以前如果重写__del__魔术方法会导致循环引用处理失效
    # 如果不想造成循环引用可以使用弱引用
    list1 = []
    list2 = [] 
    list1.append(list2)
    list2.append(list1)复制代码

    以下情况会导致垃圾回收:

    • 调用gc.collect()
    • gc模块的计数器达到阀值
    • 程序退出

    如果循环引用中两个对象都定义了__del__方法,gc模块不会销毁这些不可达对象,因为gc模块不知道应该先调用哪个对象的__del__方法,这个问题在Python 3.6中得到了解决。

    也可以通过weakref模块构造弱引用的方式来解决循环引用的问题。

  • 魔法属性和方法(请参考《Python魔法方法指南》)

    有几个小问题请大家思考:

    • 自定义的对象能不能使用运算符做运算?
    • 自定义的对象能不能放到set中?能去重吗?
    • 自定义的对象能不能作为dict的键?
    • 自定义的对象能不能使用上下文语法?
  • 混入(Mixin)

    例子:自定义字典限制只有在指定的key不存在时才能在字典中设置键值对。

    class SetOnceMappingMixin():
        """自定义混入类"""
        __slots__ = ()
    
        def __setitem__(self, key, value):
            if key in self:
                raise KeyError(str(key) + ' already set')
            return super().__setitem__(key, value)
    
    
    class SetOnceDict(SetOnceMappingMixin, dict):
        """自定义字典"""
        pass
    
    
    my_dict= SetOnceDict()
    try:
        my_dict['username'] = 'jackfrued'
        my_dict['username'] = 'hellokitty'
    except KeyError:
        pass
    print(my_dict)复制代码
  • 元编程和元类

    例子:用元类实现单例模式。

    import threading
    
    
    class SingletonMeta(type):
        """自定义元类"""
    
        def __init__(cls, *args, **kwargs):
            cls.__instance = None
            cls.__lock = threading.Lock()
            super().__init__(*args, **kwargs)
    
        def __call__(cls, *args, **kwargs):
            if cls.__instance is None:
                with cls.__lock:
                    if cls.__instance is None:
                        cls.__instance = super().__call__(*args, **kwargs)
            return cls.__instance
    
    
    class President(metaclass=SingletonMeta):
        """总统(单例类)"""
        pass复制代码
  • 面向对象设计原则

    • 单一职责原则 (SRP)- 一个类只做该做的事情(类的设计要高内聚)
    • 开闭原则 (OCP)- 软件实体应该对扩展开发对修改关闭
    • 依赖倒转原则(DIP)- 面向抽象编程(在弱类型语言中已经被弱化)
    • 里氏替换原则(LSP) - 任何时候可以用子类对象替换掉父类对象
    • 接口隔离原则(ISP)- 接口要小而专不要大而全(Python中没有接口的概念)
    • 合成聚合复用原则(CARP) - 优先使用强关联关系而不是继承关系复用代码
    • 最少知识原则(迪米特法则,LoD)- 不要给没有必然联系的对象发消息

    说明:上面加粗的字母放在一起称为面向对象的SOLID原则。

  • GoF设计模式

    • 创建型模式:单例、工厂、建造者、原型
    • 结构型模式:适配器、门面(外观)、代理
    • 行为型模式:迭代器、观察者、状态、策略

    例子:可插拔的哈希算法。

    class StreamHasher():
        """哈希摘要生成器(策略模式)"""
    
        def __init__(self, alg='md5', size=4096):
            self.size = size
            alg = alg.lower()
            self.hasher = getattr(__import__('hashlib'), alg.lower())()
    
        def __call__(self, stream):
            return self.to_digest(stream)
    
        def to_digest(self, stream):
            """生成十六进制形式的摘要"""
            for buf in iter(lambda: stream.read(self.size), b''):
                self.hasher.update(buf)
            return self.hasher.hexdigest()
    
    def main():
        """主函数"""
        hasher1 = StreamHasher()
        with open('Python-3.7.1.tgz', 'rb') as stream:
            print(hasher1.to_digest(stream))
        hasher2 = StreamHasher('sha1')
        with open('Python-3.7.1.tgz', 'rb') as stream:
            print(hasher2(stream))
    
    
    if __name__ == '__main__':
        main()复制代码


迭代器和生成器

  • 和迭代器相关的魔术方法(__iter____next__

  • 两种创建生成器的方式(生成器表达式和yield关键字)

    def fib(num):
        """生成器"""
        a, b = 0, 1
        for _ in range(num):
            a, b = b, a + b
            yield a
       
       
    class Fib(object):
        """迭代器"""
        
        def __init__(self, num):
            self.num = num
            self.a, self.b = 0, 1
            self.idx = 0
       
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.idx < self.num:
                self.a, self.b = self.b, self.a + self.b
                self.idx += 1
                return self.a
            raise StopIteration()复制代码

并发编程

Python中实现并发编程的三种方案:多线程、多进程和异步I/O。并发编程的好处在于可以提升程序的执行效率以及改善用户体验;坏处在于并发的程序不容易开发和调试,同时对其他程序来说它并不友好。

  • 多线程:Python中提供了Thread类并辅以Lock、Condition、Event、Semaphore和Barrier。Python中有GIL来防止多个线程同时执行本地字节码,这个锁对于CPython是必须的,因为CPython的内存管理并不是线程安全的,因为GIL的存在多线程并不能发挥CPU的多核特性。

    """
    面试题:进程和线程的区别和联系?
    进程 - 操作系统分配内存的基本单位 - 一个进程可以包含一个或多个线程
    线程 - 操作系统分配CPU的基本单位
    并发编程(concurrent programming)
    1. 提升执行性能 - 让程序中没有因果关系的部分可以并发的执行
    2. 改善用户体验 - 让耗时间的操作不会造成程序的假死
    """
    import glob
    import os
    import threading
    
    from PIL import Image
    
    PREFIX = 'thumbnails'
    
    
    def generate_thumbnail(infile, size, format='PNG'):
        """生成指定图片文件的缩略图"""
    	file, ext = os.path.splitext(infile)
    	file = file[file.rfind('/') + 1:]
    	outfile = f'{PREFIX}/{file}_{size[0]}_{size[1]}.{ext}'
    	img = Image.open(infile)
    	img.thumbnail(size, Image.ANTIALIAS)
    	img.save(outfile, format)
    
    
    def main():
        """主函数"""
    	if not os.path.exists(PREFIX):
    		os.mkdir(PREFIX)
    	for infile in glob.glob('images/*.png'):
    		for size in (32, 64, 128):
                # 创建并启动线程
    			threading.Thread(
    				target=generate_thumbnail, 
    				args=(infile, (size, size))
    			).start()
    			
    
    if __name__ == '__main__':
    	main()复制代码

    多个线程竞争资源的情况

    """
    多线程程序如果没有竞争资源处理起来通常也比较简单
    当多个线程竞争临界资源的时候如果缺乏必要的保护措施就会导致数据错乱
    说明:临界资源就是被多个线程竞争的资源
    """
    import time
    import threading
    
    from concurrent.futures import ThreadPoolExecutor
    
    
    class Account(object):
        """银行账户"""
    
        def __init__(self):
            self.balance = 0.0
            self.lock = threading.Lock()
    
        def deposit(self, money):
            # 通过锁保护临界资源
            with self.lock:
                new_balance = self.balance + money
                time.sleep(0.001)
                self.balance = new_balance
    
    
    class AddMoneyThread(threading.Thread):
        """自定义线程类"""
    
        def __init__(self, account, money):
            self.account = account
            self.money = money
            # 自定义线程的初始化方法中必须调用父类的初始化方法
            super().__init__()
    
        def run(self):
            # 线程启动之后要执行的操作
            self.account.deposit(self.money)
    
    def main():
        """主函数"""
        account = Account()
        # 创建线程池
        pool = ThreadPoolExecutor(max_workers=10)
        futures = []
        for _ in range(100):
            # 创建线程的第1种方式
            # threading.Thread(
            #     target=account.deposit, args=(1, )
            # ).start()
            # 创建线程的第2种方式
            # AddMoneyThread(account, 1).start()
            # 创建线程的第3种方式
            # 调用线程池中的线程来执行特定的任务
            future = pool.submit(account.deposit, 1)
            futures.append(future)
        # 关闭线程池
        pool.shutdown()
        for future in futures:
            future.result()
        print(account.balance)
    
    
    if __name__ == '__main__':
        main()复制代码

    修改上面的程序,启动5个线程向账户中存钱,5个线程从账户中取钱,取钱时如果余额不足就暂停线程进行等待。为了达到上述目标,需要对存钱和取钱的线程进行调度,在余额不足时取钱的线程暂停并释放锁,而存钱的线程将钱存入后要通知取钱的线程,使其从暂停状态被唤醒。可以使用threading模块的Condition来实现线程调度,该对象也是基于锁来创建的,代码如下所示:

    """
    多个线程竞争一个资源 - 保护临界资源 - 锁(Lock/RLock)
    多个线程竞争多个资源(线程数>资源数) - 信号量(Semaphore)
    多个线程的调度 - 暂停线程执行/唤醒等待中的线程 - Condition
    """
    from concurrent.futures import ThreadPoolExecutor
    from random import randint
    from time import sleep
    
    import threading
    
    
    class Account():
        """银行账户"""
    
        def __init__(self, balance=0):
            self.balance = balance
            lock = threading.Lock()
            self.condition = threading.Condition(lock)
    
        def withdraw(self, money):
            """取钱"""
            with self.condition:
                while money > self.balance:
                    self.condition.wait()
                new_balance = self.balance - money
                sleep(0.001)
                self.balance = new_balance
    
        def deposit(self, money):
            """存钱"""
            with self.condition:
                new_balance = self.balance + money
                sleep(0.001)
                self.balance = new_balance
                self.condition.notify_all()
    
    
    def add_money(account):
        while True:
            money = randint(5, 10)
            account.deposit(money)
            print(threading.current_thread().name, 
                  ':', money, '====>', account.balance)
            sleep(0.5)
    
    
    def sub_money(account):
        while True:
            money = randint(10, 30)
            account.withdraw(money)
            print(threading.current_thread().name, 
                  ':', money, '<====', account.balance)
            sleep(1)
    
    
    def main():
        account = Account()
        with ThreadPoolExecutor(max_workers=10) as pool:
            for _ in range(5):
                pool.submit(add_money, account)
                pool.submit(sub_money, account)
    
    
    if __name__ == '__main__':
        main()复制代码
  • 多进程:多进程可以有效的解决GIL的问题,实现多进程主要的类是Process,其他辅助的类跟threading模块中的类似,进程间共享数据可以使用管道、套接字等,在multiprocessing模块中有一个Queue类,它基于管道和锁机制提供了多个进程共享的队列。下面是官方文档上关于多进程和进程池的一个示例。

    """
    多进程和进程池的使用
    多线程因为GIL的存在不能够发挥CPU的多核特性
    对于计算密集型任务应该考虑使用多进程
    time python3 example22.py
    real    0m11.512s
    user    0m39.319s
    sys     0m0.169s
    使用多进程后实际执行时间为11.512秒,而用户时间39.319秒约为实际执行时间的4倍
    这就证明我们的程序通过多进程使用了CPU的多核特性,而且这台计算机配置了4核的CPU
    """
    import concurrent.futures
    import math
    
    PRIMES = [
        1116281,
        1297337,
        104395303,
        472882027,
        533000389,
        817504243,
        982451653,
        112272535095293,
        112582705942171,
        112272535095293,
        115280095190773,
        115797848077099,
        1099726899285419
    ] * 5
    
    
    def is_prime(n):
        """判断素数"""
        if n % 2 == 0:
            return False
    
        sqrt_n = int(math.floor(math.sqrt(n)))
        for i in range(3, sqrt_n + 1, 2):
            if n % i == 0:
                return False
        return True
    
    
    def main():
        """主函数"""
        with concurrent.futures.ProcessPoolExecutor() as executor:
            for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)):
                print('%d is prime: %s' % (number, prime))
    
    
    if __name__ == '__main__':
        main()复制代码

    说明:多线程和多进程的比较

    以下情况需要使用多线程:

    1. 程序需要维护许多共享的状态(尤其是可变状态),Python中的列表、字典、集合都是线程安全的,所以使用线程而不是进程维护共享状态的代价相对较小。
    2. 程序会花费大量时间在I/O操作上,没有太多并行计算的需求且不需占用太多的内存。

    以下情况需要使用多进程:

    1. 程序执行计算密集型任务(如:字节码操作、数据处理、科学计算)。
    2. 程序的输入可以并行的分成块,并且可以将运算结果合并。
    3. 程序在内存使用方面没有任何限制且不强依赖于I/O操作(如:读写文件、套接字等)。
  • 异步处理:从调度程序的任务队列中挑选任务,该调度程序以交叉的形式执行这些任务,我们并不能保证任务将以某种顺序去执行,因为执行顺序取决于队列中的一项任务是否愿意将CPU处理时间让位给另一项任务。异步任务通常通过多任务协作处理的方式来实现,由于执行时间和顺序的不确定,因此需要通过回调式编程或者future对象来获取任务执行的结果。Python 3通过asyncio模块和awaitasync关键字(在Python 3.7中正式被列为关键字)来支持异步处理。

    """
    异步I/O - async / await
    """
    import asyncio
    
    
    def num_generator(m, n):
        """指定范围的数字生成器"""
        yield from range(m, n + 1)
    
    
    async def prime_filter(m, n):
        """素数过滤器"""
        primes = []
        for i in num_generator(m, n):
            flag = True
            for j in range(2, int(i ** 0.5 + 1)):
                if i % j == 0:
                    flag = False
                    break
            if flag:
                print('Prime =>', i)
                primes.append(i)
    
            await asyncio.sleep(0.001)
        return tuple(primes)
    
    
    async def square_mapper(m, n):
        """平方映射器"""
        squares = []
        for i in num_generator(m, n):
            print('Square =>', i * i)
            squares.append(i * i)
    
            await asyncio.sleep(0.001)
        return squares
    
    
    def main():
        """主函数"""
        loop = asyncio.get_event_loop()
        future = asyncio.gather(prime_filter(2, 100), square_mapper(1, 100))
        future.add_done_callback(lambda x: print(x.result()))
        loop.run_until_complete(future)
        loop.close()
    
    
    if __name__ == '__main__':
        main()复制代码

    说明:上面的代码使用get_event_loop函数获得系统默认的事件循环,通过gather函数可以获得一个future对象,future对象的add_done_callback可以添加执行完成时的回调函数,loop对象的run_until_complete方法可以等待通过future对象获得协程执行结果。

    Python中有一个名为aiohttp的三方库,它提供了异步的HTTP客户端和服务器,这个三方库可以跟asyncio模块一起工作,并提供了对Future对象的支持。Python 3.6中引入了async和await来定义异步执行的函数以及创建异步上下文,在Python 3.7中它们正式成为了关键字。下面的代码异步的从5个URL中获取页面并通过正则表达式的命名捕获组提取了网站的标题。

    import asyncio
    import re
    
    import aiohttp
    
    PATTERN = re.compile(r'\(?P.*)\<\/title\>'</span>)
    
    
    async def fetch_page(session, url):
        async with session.get(url, ssl=False) as resp:
            <span class="hljs-built_in">return</span> await resp.text()
    
    
    async def show_title(url):
        async with aiohttp.ClientSession() as session:
            html = await fetch_page(session, url)
            <span class="hljs-built_in">print</span>(PATTERN.search(html).group(<span class="hljs-string">'title'</span>))
    
    
    def main():
        urls = (<span class="hljs-string">'https://www.python.org/'</span>,
                <span class="hljs-string">'https://git-scm.com/'</span>,
                <span class="hljs-string">'https://www.jd.com/'</span>,
                <span class="hljs-string">'https://www.taobao.com/'</span>,
                <span class="hljs-string">'https://www.douban.com/'</span>)
        loop = asyncio.get_event_loop()
        tasks = [show_title(url) <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> urls]
        loop.run_until_complete(asyncio.wait(tasks))
        loop.close()
    
    
    <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
        main()<span class="copy-code-btn">复制代码</span></code></pre> 
          </div> 
          <blockquote> 
           <p>说明:<b>异步I/O与多进程的比较</b>。</p> 
           <p>当程序不需要真正的并发性或并行性,而是更多的依赖于异步处理和回调时,asyncio就是一种很好的选择。如果程序中有大量的等待与休眠时,也应该考虑asyncio,它很适合编写没有实时数据处理需求的Web应用服务器。</p> 
          </blockquote><p>Python还有很多用于处理并行任务的三方库,例如:joblib、PyMP等。实际开发中,要提升系统的可扩展性和并发性通常有垂直扩展(增加单个节点的处理能力)和水平扩展(将单个节点变成多个节点)两种做法。可以通过消息队列来实现应用程序的解耦合,消息队列相当于是多线程同步队列的扩展版本,不同机器上的应用程序相当于就是线程,而共享的分布式消息队列就是原来程序中的Queue。消息队列(面向消息的中间件)的最流行和最标准化的实现是AMQP(高级消息队列协议),AMQP源于金融行业,提供了排队、路由、可靠传输、安全等功能,最著名的实现包括:Apache的ActiveMQ、RabbitMQ等。</p><p>要实现任务的异步化,可以使用名为Celery的三方库。Celery是Python编写的分布式任务队列,它使用分布式消息进行工作,可以基于RabbitMQ或Redis来作为后端的消息代理。</p></li> 
        </ul> 
        <p><br></p> 
       </div> 
       <p><br></p> 
      </div> 
     </div> 
    </div>
                                </div>
                            </div>
                        </div>
                        <!--PC和WAP自适应版-->
                        <div id="SOHUCS" sid="1282109270392848384"></div>
                        <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                        <!-- 文章页-底部 动态广告位 -->
                        <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                    </div>
                    <div class="col-md-3">
                        <div class="row" id="ad">
                            <!-- 文章页-右侧1 动态广告位 -->
                            <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                                <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                            </div>
                            <!-- 文章页-右侧2 动态广告位 -->
                            <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                                <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                            </div>
                            <!-- 文章页-右侧3 动态广告位 -->
                            <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                                <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="container">
            <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(Python基础入门教程:Day16-20/Python语言进阶)</h4>
            <div id="paradigm-article-related">
                <div class="recommend-post mb30">
                    <ul class="widget-links">
                        <li><a href="/article/1835504723210366976.htm"
                               title="第四天旅游线路预览——从换乘中心到喀纳斯湖" target="_blank">第四天旅游线路预览——从换乘中心到喀纳斯湖</a>
                            <span class="text-muted">陟彼高冈yu</span>
    <a class="tag" taget="_blank" href="/search/%E5%9F%BA%E4%BA%8EGoogle/1.htm">基于Google</a><a class="tag" taget="_blank" href="/search/earth/1.htm">earth</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/%E7%9A%84%E6%97%85%E6%B8%B8%E8%A7%84%E5%88%92%E5%92%8C%E9%A2%84%E8%A7%88/1.htm">的旅游规划和预览</a><a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a>
                            <div>第四天:从贾登峪到喀纳斯风景区入口,晚上住宿贾登峪;换乘中心有4路车,喀纳斯①号车,去喀纳斯湖,路程时长约5分钟;将上面的的行程安排进行动态展示,具体步骤见”Googleearthstudio进行动态轨迹显示制作过程“、“Googleearthstudio入门教程”和“Googleearthstudio进阶教程“相关内容,得到行程如下所示:Day4-2-480p</div>
                        </li>
                        <li><a href="/article/1835504470440636416.htm"
                               title="Goolge earth studio 进阶4——路径修改与平滑" target="_blank">Goolge earth studio 进阶4——路径修改与平滑</a>
                            <span class="text-muted">陟彼高冈yu</span>
    <a class="tag" taget="_blank" href="/search/Google/1.htm">Google</a><a class="tag" taget="_blank" href="/search/earth/1.htm">earth</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a><a class="tag" taget="_blank" href="/search/%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/1.htm">进阶教程</a><a class="tag" taget="_blank" href="/search/%E6%97%85%E6%B8%B8/1.htm">旅游</a>
                            <div>如果我们希望在大约中途时获得更多的城市鸟瞰视角。可以将相机拖动到这里并创建一个新的关键帧。camera_target_clip_7EarthStudio会自动平滑我们的路径,所以当我们通过这个关键帧时,不是一个生硬的角度,而是一个平滑的曲线。camera_target_clip_8路径上有贝塞尔控制手柄,允许我们调整路径的形状。右键单击,我们可以选择“平滑路径”,这是默认的自动平滑算法,或者我们可</div>
                        </li>
                        <li><a href="/article/1835493753557708800.htm"
                               title="每日算法&面试题,大厂特训二十八天——第二十天(树)" target="_blank">每日算法&面试题,大厂特训二十八天——第二十天(树)</a>
                            <span class="text-muted">肥学</span>
    <a class="tag" taget="_blank" href="/search/%E2%9A%A1%E7%AE%97%E6%B3%95%E9%A2%98%E2%9A%A1%E9%9D%A2%E8%AF%95%E9%A2%98%E6%AF%8F%E6%97%A5%E7%B2%BE%E8%BF%9B/1.htm">⚡算法题⚡面试题每日精进</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a>
                            <div>目录标题导读算法特训二十八天面试题点击直接资料领取导读肥友们为了更好的去帮助新同学适应算法和面试题,最近我们开始进行专项突击一步一步来。上一期我们完成了动态规划二十一天现在我们进行下一项对各类算法进行二十八天的一个小总结。还在等什么快来一起肥学进行二十八天挑战吧!!特别介绍小白练手专栏,适合刚入手的新人欢迎订阅编程小白进阶python有趣练手项目里面包括了像《机器人尬聊》《恶搞程序》这样的有趣文章</div>
                        </li>
                        <li><a href="/article/1835462190216343552.htm"
                               title="第二十 python基础--语句" target="_blank">第二十 python基础--语句</a>
                            <span class="text-muted">九樱MOL</span>
    
                            <div>目录具体内容1:if语句的使用格式判断语句2:if-else的使用格式3:if-elif-else的使用格式4:if嵌套1:while循环的格式循环语句2:while循环嵌套3:for循环的格式一、判断语句在程序中如果某些条件满足,才能做某件事情,而不满足时不允许做,这就是所谓的判断1.1if语句的使用格式if要判断的条件:条件成立时,要做的事情案例:判断年纪,如果age大于18,输入成年age=</div>
                        </li>
                        <li><a href="/article/1835450513689243648.htm"
                               title="2023-08-20" target="_blank">2023-08-20</a>
                            <span class="text-muted">圆梦菌</span>
    
                            <div>魔力宝贝最详细新手教程,新手该如何完美开局,建议收藏转发2023-08-2010:34《魔力宝贝》手游体力是什么?魔力宝贝体力恢复机制是每10分钟回复1点;体力作用:挑战关卡需消耗体力体力获取方式1、好友每天可以赠送15次,也就是15点体力2、系统每天中午12点以及下午6点赠送25体3、在商城使用神石购买《魔力宝贝》手游战斗力如何提升?1、宠物强化宠物通过融合进阶后可以大幅度提升战力,最高级的宠物</div>
                        </li>
                        <li><a href="/article/1835449123252301824.htm"
                               title="Python入门之Lesson2:Python基础语法" target="_blank">Python入门之Lesson2:Python基础语法</a>
                            <span class="text-muted">小熊同学哦</span>
    <a class="tag" taget="_blank" href="/search/Python%E5%85%A5%E9%97%A8%E8%AF%BE%E7%A8%8B/1.htm">Python入门课程</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E9%9D%92%E5%B0%91%E5%B9%B4%E7%BC%96%E7%A8%8B/1.htm">青少年编程</a>
                            <div>目录前言一.介绍1.变量和数据类型2.常见运算符3.输入输出4.条件语句5.循环结构二.练习三.总结前言欢迎来到《Python入门》系列博客的第二课。在上一课中,我们了解了Python的安装及运行环境的配置。在这一课中,我们将深入学习Python的基础语法,这是编写Python代码的根基。通过本节内容的学习,你将掌握变量、数据类型、运算符、输入输出、条件语句等Python编程的基础知识。一.介绍1</div>
                        </li>
                        <li><a href="/article/1835441932583661568.htm"
                               title="ESP32-C3入门教程 网络篇⑩——基于esp_https_ota和MQTT实现开机主动升级和被动触发升级的OTA功能" target="_blank">ESP32-C3入门教程 网络篇⑩——基于esp_https_ota和MQTT实现开机主动升级和被动触发升级的OTA功能</a>
                            <span class="text-muted">小康师兄</span>
    <a class="tag" taget="_blank" href="/search/ESP32-C3%E5%85%A5%E9%97%A8%E6%95%99%E7%A8%8B/1.htm">ESP32-C3入门教程</a><a class="tag" taget="_blank" href="/search/https/1.htm">https</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E5%99%A8/1.htm">服务器</a><a class="tag" taget="_blank" href="/search/esp32/1.htm">esp32</a><a class="tag" taget="_blank" href="/search/OTA/1.htm">OTA</a><a class="tag" taget="_blank" href="/search/MQTT/1.htm">MQTT</a>
                            <div>文章目录一、前言二、软件流程三、部分源码四、运行演示一、前言本文基于VSCodeIDE进行编程、编译、下载、运行等操作基础入门章节请查阅:ESP32-C3入门教程基础篇①——基于VSCode构建HelloWorld教程目录大纲请查阅:ESP32-C3入门教程——导读ESP32-C3入门教程网络篇⑨——基于esp_https_ota实现史上最简单的ESP32OTA远程固件升级功能二、软件流程</div>
                        </li>
                        <li><a href="/article/1835439322715746304.htm"
                               title="258-各位相加" target="_blank">258-各位相加</a>
                            <span class="text-muted">不胖二十斤不改名zz</span>
    
                            <div>给定一个非负整数num,反复将各个位上的数字相加,直到结果为一位数。输入:38输出:2解释:各位相加的过程为:3+8=11,1+1=2。由于2是一位数,所以返回2。最简单的方法就是递归了。进阶:你可以不使用循环或者递归,且在O(1)时间复杂度内解决这个问题吗?假如一个三位数'abc',其值大小为s1=100*a+10*b+1*c,经过一次各位相加后,变为s2=a+b+c,减小的差值为(s1-s2)</div>
                        </li>
                        <li><a href="/article/1835414702142877696.htm"
                               title="Python编程 - 函数进阶" target="_blank">Python编程 - 函数进阶</a>
                            <span class="text-muted">易辰君</span>
    <a class="tag" taget="_blank" href="/search/Python%E6%A0%B8%E5%BF%83%E7%BC%96%E7%A8%8B/1.htm">Python核心编程</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                            <div>目录前言一、函数参数的高级用法(一)缺省参数(二)命名参数(三)不定长参数二、拆包(一)函数返回值拆包(二)通过星号拆包(三)总结三、匿名函数(一)函数定义(二)使用匿名函数四、递归函数(一)简介(二)基本结构(三)简单示例(四)优缺点总结前言上篇文章主要了解了函数基础,如何定义函数,函数种类以及局部变量和全局变量的差异等,接下来就讲解python函数较为进阶的知识点,若有任何想法欢迎一起沟通讨论</div>
                        </li>
                        <li><a href="/article/1835388111874519040.htm"
                               title="教师资格证常考的5个知识点" target="_blank">教师资格证常考的5个知识点</a>
                            <span class="text-muted">a3cb74a20840</span>
    
                            <div>知识点1:教育与人的发展(5规律、4因素、3动因)五大规律:顺序性—循序渐进阶段性—不搞“一刀切”不平衡性—抓关键期互补性—扬长避短个别差异性—因材施教考点精华:1.举例子对应五大规律;2.每个规律的教学启示;3规律特点。四大因素:遗传(地位:物质前提、可能性)环境(地位:多种可能、现实性)学校教育(主导)个人主观能动性(动力、决定)三大动因:内发论(1.孟子:性善论;2.弗洛伊德:性本能)外铄论</div>
                        </li>
                        <li><a href="/article/1835379533587509248.htm"
                               title="ansible的安装、使用" target="_blank">ansible的安装、使用</a>
                            <span class="text-muted">ytym00</span>
    
                            <div>简介高度模块化,调用特定的模块,完成特定的任务,基于Yaml,来完成批量任务的模板化,来支持playbook。基于Python语言实现,主要使用Paramiko、PyYAML和JinJa2三个关键模块,部署简单(agentless),主从模式,支持自定义模块,支持playbook,幂等性:允许重复执行N次,没有变化时,只会执行第一次。特点:1、Configuration(cfengine,chef</div>
                        </li>
                        <li><a href="/article/1835350283710984192.htm"
                               title="PCIe进阶之TL:Memory, I/O, and Configuration Request Rules & TPH Rules" target="_blank">PCIe进阶之TL:Memory, I/O, and Configuration Request Rules & TPH Rules</a>
                            <span class="text-muted">芯芯之火,可以燎原</span>
    <a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/%E7%A1%AC%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">硬件工程</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E4%B8%8E%E9%80%9A%E4%BF%A1/1.htm">信息与通信</a>
                            <div>1Memory,I/O,andConfigurationRequestRules下述规则适用于Memory请求、IO请求和配置请求。除了公共的header字段外,所有Memory请求、IO请求和配置请求还包括以下字段:(1)RequesterID[15:0]和Tag[9:0],组成了TransactionID。(2)LastDWBE[3:0]和1stDWBE[3:0]字段。对于TH字段置1的Mem</div>
                        </li>
                        <li><a href="/article/1835347004830609408.htm"
                               title="【Python基础】Python迭代器与生成器(两种强大工具)" target="_blank">【Python基础】Python迭代器与生成器(两种强大工具)</a>
                            <span class="text-muted">姑苏老陈</span>
    <a class="tag" taget="_blank" href="/search/Python%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8/1.htm">Python编程入门</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/python%E8%BF%AD%E4%BB%A3%E5%99%A8%E4%B8%8E%E7%94%9F%E6%88%90%E5%99%A8/1.htm">python迭代器与生成器</a>
                            <div>本文收录于《Python编程入门》专栏,从零基础开始,分享一些Python编程基础知识,欢迎关注,谢谢!文章目录一、前言二、迭代器2.1创建迭代器2.2自定义迭代器2.3处理大型文件三、生成器四、生成器表达式五、实际应用案例5.1数据库查询5.2网络数据流处理六、总结一、前言在Python中,迭代器与生成器是两种非常强大的工具,它们可以帮助我们有效地处理大量数据,特别是在需要逐个访问元素的情况下。</div>
                        </li>
                        <li><a href="/article/1835305090307682304.htm"
                               title="Python怎么判断两个字符串是否相等?" target="_blank">Python怎么判断两个字符串是否相等?</a>
                            <span class="text-muted">老男孩IT教育</span>
    <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                            <div>在Python语言中,字符串是一种十分常见的数据类型,在很多业务场景下,我们需要判断两个字符串是否相等,这也是一个非常基础的操作,那么该如何实现呢?以下是详细的内容:Python中判断两个字符串是否相等有两种方法:直接比较和使用字符串方法。1、直接比较在Python中,我们可以使用==运算符来比较两个字符串是否相等。例如:str1='hello'str2='world'ifstr1==str2:p</div>
                        </li>
                        <li><a href="/article/1835295766747377664.htm"
                               title="C# 开发教程-入门基础" target="_blank">C# 开发教程-入门基础</a>
                            <span class="text-muted">天马3798</span>
    <a class="tag" taget="_blank" href="/search/%E6%95%99%E7%A8%8B%E7%B3%BB%E5%88%97%E6%95%B4%E7%90%86/1.htm">教程系列整理</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                            <div>1.C#简介、环境,程序结构2.C#基本语法,变量,控制局域,数据类型,类型转换3.C#数组、循环,Linq4.C#类,封装,方法5.C#枚举、字符串6.C#面相对象,继承,封装,多态7.C#特性、属性、反射、索引器8.C#委托,事件,集合,泛型9.C#匿名方法10.C#多线程更多:JQuery开发教程入门基础Vue开发基础入门教程Vue开发高级学习教程</div>
                        </li>
                        <li><a href="/article/1835261483089489920.htm"
                               title="后端开发刷题 | 最长回文子串" target="_blank">后端开发刷题 | 最长回文子串</a>
                            <span class="text-muted">jingling555</span>
    <a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AF%95%E9%A2%98%E7%9B%AE/1.htm">笔试题目</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                            <div>描述对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度。数据范围:1≤n≤1000要求:空间复杂度O(1),时间复杂度O(n2)进阶:空间复杂度O(n),时间复杂度O(n)示例1输入:"ababc"返回值:3说明:最长的回文子串为"aba"与"bab",长度都为3示例2输入:"abbba"返回值:5示例3输入:"b"返回值:1思路分析:该题可以</div>
                        </li>
                        <li><a href="/article/1835228079501438976.htm"
                               title="PCIe进阶之TL:Common Packet Header Fields & TLPs with Data Payloads Rules" target="_blank">PCIe进阶之TL:Common Packet Header Fields & TLPs with Data Payloads Rules</a>
                            <span class="text-muted">芯芯之火,可以燎原</span>
    <a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/%E7%A1%AC%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">硬件工程</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E4%B8%8E%E9%80%9A%E4%BF%A1/1.htm">信息与通信</a>
                            <div>1TransactionLayerProtocol-PacketDefinitionTLP有四种事务类型:Memory、I/O、Configuration和Messages,两种地址格式:32bit和64bit。构成TLP时,所有标记为Reserved的字段(有时缩写为R)都必须全为0。接收者Rx必须忽略此字段中的值,PCIeSwitch必须对其进行原封不动的转发。请注意,对于某些字段,既有指定值</div>
                        </li>
                        <li><a href="/article/1835219887434330112.htm"
                               title="python语言爬虫爬取歌曲程序代码" target="_blank">python语言爬虫爬取歌曲程序代码</a>
                            <span class="text-muted">EYYLTV</span>
    <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a>
                            <div>importrequestssong_urls=[“http://music.163.com/song/media/outer/url?id=25795016.mp3”,“https://m703.music.126.net/20240915140140/670dfe5c0144991d4cb778d6662fd762/jd-musicrep-privatecloud-audio-public/o</div>
                        </li>
                        <li><a href="/article/1835219887958618112.htm"
                               title="python语言爬虫爬取歌曲代码X" target="_blank">python语言爬虫爬取歌曲代码X</a>
                            <span class="text-muted">EYYLTV</span>
    <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                            <div>importrequestssong_urls=[“https://m804.music.126.net/20240915142147/4e01caa69abda60b165e185607805ee1/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/30379084686/b56a/dbd5/39fc/792d87f5d7014bb78547ec3804eeaac5.m4a?au</div>
                        </li>
                        <li><a href="/article/1835204212070379520.htm"
                               title="抖音小黄车怎么开?抖音小黄车开通方法?" target="_blank">抖音小黄车怎么开?抖音小黄车开通方法?</a>
                            <span class="text-muted">日常购物技巧呀</span>
    
                            <div>抖音不仅可以刷短视频,用户还可以在抖音上卖商品,开通小黄车之后就可以卖商品啦,开通小黄车之前,需要申请开通商品橱窗功能;首先打开【抖音短视频】,点开界面右上角的【搜索图标】,搜索【电商小助手】,点击【电商小助手】;选中关注旁边的【私信】,选择界面下方的【申请入口】,点击【商品分享权限】,满足【实名认证】、【进阶要求】之后,选择界面下方的【立即申请】即可;开通商品橱窗之后,就可以挂小黄车啦,方法是不</div>
                        </li>
                        <li><a href="/article/1835192659690483712.htm"
                               title="ROM修改进阶教程------如何修改固件 线刷转卡刷 卡刷转线刷 操作中的一些注意事项" target="_blank">ROM修改进阶教程------如何修改固件 线刷转卡刷 卡刷转线刷 操作中的一些注意事项</a>
                            <span class="text-muted">安卓机器</span>
    <a class="tag" taget="_blank" href="/search/ROM%E4%BF%AE%E6%94%B9%E8%BF%9B%E9%98%B6%E6%95%99%E7%A8%8B/1.htm">ROM修改进阶教程</a><a class="tag" taget="_blank" href="/search/%E5%8D%A1%E5%88%B7%E8%BD%AC%E6%8D%A2%E7%BA%BF%E5%88%B7/1.htm">卡刷转换线刷</a><a class="tag" taget="_blank" href="/search/%E7%BA%BF%E5%88%B7%E8%BD%AC%E6%8D%A2%E5%8D%A1%E5%88%B7/1.htm">线刷转换卡刷</a><a class="tag" taget="_blank" href="/search/%E5%9B%BA%E4%BB%B6%E8%BD%AC%E6%8D%A2/1.htm">固件转换</a>
                            <div>在接待各种rom定制化服务中。有很多客户需要各种各样的需求。包括修改rom默认开启usb调试类默认开启开发者选项。修改不锁屏不休眠跳过开机引导以及一些内置app和可卸载app等等的定制项目。还有很多导出系统导出数据完整恢复类要求。今天给大家解析下如何将固件转换类的相关步骤解析通过博文可以了解;1--------线刷固件转换卡刷固件的注意事项以及步骤2--------卡刷固件转换线刷固件的注意事项以</div>
                        </li>
                        <li><a href="/article/1835133384452567040.htm"
                               title="爱的进阶" target="_blank">爱的进阶</a>
                            <span class="text-muted">懒方的羊</span>
    
                            <div>热恋时,你侬我侬。每一刻都不嫌多,最怕时间突然消逝,很多的呢喃还未说道。那简简单单的对望,都显得情深义重。真真是应了那句,有情饮水饱!不满时,锱铢必较。哪怕没有及时的回应,都显得漠不关心,不禁质疑,爱还在么?还有多少?是否已经厌倦?那忙碌的回答,又是否是不在意的敷衍?争吵是,互相伤害。开始彼此埋怨,陈年往事不停地诉说。开始觉得彼此都不愿付出了,却没发现彼此都在不停地索取。这时,两个人是不是在彼此的</div>
                        </li>
                        <li><a href="/article/1835128195632951296.htm"
                               title="《Android进阶之光》读书笔记" target="_blank">《Android进阶之光》读书笔记</a>
                            <span class="text-muted">soleil雪寂</span>
    <a class="tag" taget="_blank" href="/search/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/1.htm">读书笔记</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Android%E8%BF%9B%E9%98%B6%E4%B9%8B%E5%85%89/1.htm">Android进阶之光</a>
                            <div>文章目录第1章Android新特性1.1.Android5.0新特性1.2.RecyclerView1.1.4.3种Notification1.1.5.Toolbar与Palette1.1.6.Palette1.2.Android6.0新特性1.2.2.运行时权限机制1.3.Android7.0新特性第2章MaterialDesign2.2.DesignSupportLibrary常用控件详解第3</div>
                        </li>
                        <li><a href="/article/1835126172099375104.htm"
                               title="《Android进阶之光》— Android 书籍" target="_blank">《Android进阶之光》— Android 书籍</a>
                            <span class="text-muted">王睿丶</span>
    <a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/%E6%B0%B8%E6%97%A0%E6%AD%A2%E5%A2%83/1.htm">永无止境</a><a class="tag" taget="_blank" href="/search/%E3%80%8AAndroid%E8%BF%9B%E9%98%B6%E4%B9%8B%E5%85%89%E3%80%8B/1.htm">《Android进阶之光》</a><a class="tag" taget="_blank" href="/search/Android%E4%B9%A6%E7%B1%8D/1.htm">Android书籍</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/phoenix/1.htm">phoenix</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a>
                            <div>文章目录第1章Android新特性1第2章MaterialDesign48第3章View体系与自定义View87第4章多线程编程165第5章网络编程与网络框架204第6章设计模式271第7章事件总线308第8章函数响应式编程333第9章注解与依赖注入框架382第10章应用架构设计422第11章系统架构与MediaPlayer框架460出版年:2017-7简介:《Android进阶之光》是一本And</div>
                        </li>
                        <li><a href="/article/1835123902771195904.htm"
                               title="《android进阶之光》——多线程编程(上)" target="_blank">《android进阶之光》——多线程编程(上)</a>
                            <span class="text-muted">TAING要一直努力</span>
    <a class="tag" taget="_blank" href="/search/%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/1.htm">读书笔记</a>
                            <div>今天了解了下多线程编程,知识点如下:进程与线程:进程是什么?线程是什么?进程可以看作是程序的实体,是线程的容器,是受操作系统管理的基本运行单元,例如exe文件就是一个进程。线程是进程运行的一些子任务,是操作系统调度的最小单元,各线程拥有自己的计数器,堆栈,局部变量等,也可以访问线程间共享的内存。线程的状态有哪些?新创建,可运行,等待,超时等待,阻塞,终止怎么创建一个线程?-三种方法第一种,MyTr</div>
                        </li>
                        <li><a href="/article/1835119009960390656.htm"
                               title="继续探索通往桃花源的路-我为何参加进阶写作特训营" target="_blank">继续探索通往桃花源的路-我为何参加进阶写作特训营</a>
                            <span class="text-muted">安晴兰</span>
    
                            <div>记得一个月前写了一篇为何参加21天爱上写作训练营,我开始了这个写作的旅程。一个月后写了一篇参与课程的心得。我发现这段很短的时间,21天,回首一望,其实,自己才迈开了一步。老师给我们一些方法与技巧,告诉我们补给的重要,老师看着我们继续前行,因为这条写作路,是自己的选择。我相信老师一定希望我们勇往直前,笔从心的继续写下去,做个终生的写作者。这段时间我的写作产出量的确比不上其他多产的小伙伴,但我已达到老</div>
                        </li>
                        <li><a href="/article/1835118105613922304.htm"
                               title="android进阶之光!Android面试必备的集合源码详解,系列篇" target="_blank">android进阶之光!Android面试必备的集合源码详解,系列篇</a>
                            <span class="text-muted">程序员Sunbu</span>
    <a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a>
                            <div>前言面试:如果不准备充分的面试,完全是浪费时间,更是对自己的不负责。文末会给大家分享下我整理的Android面试专题及答案其中大部分都是大企业面试常问的面试题,可以对照这查漏补缺,当然了,这里所列的肯定不可能覆盖全部方式,不过对大家找工作肯定是有帮助!本月飞机到达上海,到今天第6天了,四家大公司华为,小米,映客,抖音,还有二家中小型公司。有几家已经面了几轮,下周还要面,挂了几家,不过目前已经选择了</div>
                        </li>
                        <li><a href="/article/1835102953678139392.htm"
                               title="js进阶第二天" target="_blank">js进阶第二天</a>
                            <span class="text-muted">LIT乐言</span>
    
                            <div>一、水平滚动条和垂直滚动条Snip20161124_1.png1.1核心技术点1)求滚动条的长度?2)拖动滚动条,求内容要走多少?滚动条的长度取决于滚动内容(滚动内容越长,滚动条越短);内容滚动的距离和滚动条走的距离是成倍数关系。1.2换算公式获取滚动条的长度:**滚动条的长度/盒子的长度=盒子的长度/内容的长度**滚动条长度=(盒子的宽度/内容的宽度)*盒子的宽度拖动滚动条,求内容走的长度:**</div>
                        </li>
                        <li><a href="/article/1835081050225733632.htm"
                               title="PCIe进阶之Gen3 Physical Layer Transmit Logic(二)" target="_blank">PCIe进阶之Gen3 Physical Layer Transmit Logic(二)</a>
                            <span class="text-muted">芯芯之火,可以燎原</span>
    <a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/%E7%A1%AC%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">硬件工程</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E4%B8%8E%E9%80%9A%E4%BF%A1/1.htm">信息与通信</a>
                            <div>1文章概述本文是接着上面一篇文章《Gen3PhysicalLayerTransmitLogic(一)》继续对Gen3PhysicalLayerTransmitLogic做进一步的解析,具体包含ByteStriping和Scrambling以及Serializer。1.1ByteStripingGen3x1OrderedSetConstruction如下所示:OrderedSetBlock由一个Sy</div>
                        </li>
                        <li><a href="/article/1835081050716467200.htm"
                               title="PCIe进阶之Gen3 Physical Layer Receive Logic(一)" target="_blank">PCIe进阶之Gen3 Physical Layer Receive Logic(一)</a>
                            <span class="text-muted">芯芯之火,可以燎原</span>
    <a class="tag" taget="_blank" href="/search/PCIe%E8%BF%9B%E9%98%B6/1.htm">PCIe进阶</a><a class="tag" taget="_blank" href="/search/%E7%A1%AC%E4%BB%B6%E5%B7%A5%E7%A8%8B/1.htm">硬件工程</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E4%B8%8E%E9%80%9A%E4%BF%A1/1.htm">信息与通信</a>
                            <div>1文章概述本篇文章是接着前面两篇文章进一步研究Gen3PhysicalLayerReceiveLogic的实现,具体包含DifferentialReceiver,CDR(ClockandDataRecovery)和ReceiverClockCompensationLogic三个部分的介绍和解析。1.1DifferentialReceiverGen3的DifferentialReceiver逻辑和之</div>
                        </li>
                                    <li><a href="/article/91.htm"
                                           title="java解析APK" target="_blank">java解析APK</a>
                                        <span class="text-muted">3213213333332132</span>
    <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/apk/1.htm">apk</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E8%A7%A3%E6%9E%90APK/1.htm">解析APK</a>
                                        <div>解析apk有两种方法 
    1、结合安卓提供apktool工具,用java执行cmd解析命令获取apk信息 
    2、利用相关jar包里的集成方法解析apk 
     
    这里只给出第二种方法,因为第一种方法在linux服务器下会出现不在控制范围之内的结果。 
     
     
    
    public class ApkUtil
    {
    	/**
    	 * 日志对象
    	 */
    	private static Logger	 </div>
                                    </li>
                                    <li><a href="/article/218.htm"
                                           title="nginx自定义ip访问N种方法" target="_blank">nginx自定义ip访问N种方法</a>
                                        <span class="text-muted">ronin47</span>
    <a class="tag" taget="_blank" href="/search/nginx+%E7%A6%81%E6%AD%A2ip%E8%AE%BF%E9%97%AE/1.htm">nginx 禁止ip访问</a>
                                        <div>   因业务需要,禁止一部分内网访问接口, 由于前端架了F5,直接用deny或allow是不行的,这是因为直接获取的前端F5的地址。 
       所以开始思考有哪些主案可以实现这样的需求,目前可实施的是三种: 
       一:把ip段放在redis里,写一段lua 
              二:利用geo传递变量,写一段</div>
                                    </li>
                                    <li><a href="/article/345.htm"
                                           title="mysql timestamp类型字段的CURRENT_TIMESTAMP与ON UPDATE CURRENT_TIMESTAMP属性" target="_blank">mysql timestamp类型字段的CURRENT_TIMESTAMP与ON UPDATE CURRENT_TIMESTAMP属性</a>
                                        <span class="text-muted">dcj3sjt126com</span>
    <a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                        <div>timestamp有两个属性,分别是CURRENT_TIMESTAMP 和ON UPDATE CURRENT_TIMESTAMP两种,使用情况分别如下: 
      
    1. 
      
    CURRENT_TIMESTAMP  
      
    当要向数据库执行insert操作时,如果有个timestamp字段属性设为 
      
    CURRENT_TIMESTAMP,则无论这</div>
                                    </li>
                                    <li><a href="/article/472.htm"
                                           title="struts2+spring+hibernate分页显示" target="_blank">struts2+spring+hibernate分页显示</a>
                                        <span class="text-muted">171815164</span>
    <a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a>
                                        <div>分页显示一直是web开发中一大烦琐的难题,传统的网页设计只在一个JSP或者ASP页面中书写所有关于数据库操作的代码,那样做分页可能简单一点,但当把网站分层开发后,分页就比较困难了,下面是我做Spring+Hibernate+Struts2项目时设计的分页代码,与大家分享交流。 
     
      1、DAO层接口的设计,在MemberDao接口中定义了如下两个方法: 
     
     
     
     
     
    public in</div>
                                    </li>
                                    <li><a href="/article/599.htm"
                                           title="构建自己的Wrapper应用" target="_blank">构建自己的Wrapper应用</a>
                                        <span class="text-muted">g21121</span>
    <a class="tag" taget="_blank" href="/search/rap/1.htm">rap</a>
                                        <div>        我们已经了解Wrapper的目录结构,下面可是正式利用Wrapper来包装我们自己的应用,这里假设Wrapper的安装目录为:/usr/local/wrapper。 
      
            首先,创建项目应用 
      
    &nb</div>
                                    </li>
                                    <li><a href="/article/726.htm"
                                           title="[简单]工作记录_多线程相关" target="_blank">[简单]工作记录_多线程相关</a>
                                        <span class="text-muted">53873039oycg</span>
    <a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a>
                                        <div>     最近遇到多线程的问题,原来使用异步请求多个接口(n*3次请求)     方案一 使用多线程一次返回数据,最开始是使用5个线程,一个线程顺序请求3个接口,超时终止返回     缺点       测试发现必须3个接</div>
                                    </li>
                                    <li><a href="/article/853.htm"
                                           title="调试jdk中的源码,查看jdk局部变量" target="_blank">调试jdk中的源码,查看jdk局部变量</a>
                                        <span class="text-muted">程序员是怎么炼成的</span>
    <a class="tag" taget="_blank" href="/search/jdk+%E6%BA%90%E7%A0%81/1.htm">jdk 源码</a>
                                        <div>转自:http://www.douban.com/note/211369821/ 
      
     学习jdk源码时使用-- 
        学习java最好的办法就是看jdk源代码,面对浩瀚的jdk(光源码就有40M多,比一个大型网站的源码都多)从何入手呢,要是能单步调试跟进到jdk源码里并且能查看其中的局部变量最好了。 
     
    可惜的是sun提供的jdk并不能查看运行中的局部变量</div>
                                    </li>
                                    <li><a href="/article/980.htm"
                                           title="Oracle RAC Failover 详解" target="_blank">Oracle RAC Failover 详解</a>
                                        <span class="text-muted">aijuans</span>
    <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                                        <div>Oracle RAC 同时具备HA(High Availiablity) 和LB(LoadBalance). 而其高可用性的基础就是Failover(故障转移). 它指集群中任何一个节点的故障都不会影响用户的使用,连接到故障节点的用户会被自动转移到健康节点,从用户感受而言, 是感觉不到这种切换。 
     
     Oracle 10g RAC 的Failover 可以分为3种: 
     1. Client-Si</div>
                                    </li>
                                    <li><a href="/article/1107.htm"
                                           title="form表单提交数据编码方式及tomcat的接受编码方式" target="_blank">form表单提交数据编码方式及tomcat的接受编码方式</a>
                                        <span class="text-muted">antonyup_2006</span>
    <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a><a class="tag" taget="_blank" href="/search/%E6%B5%8F%E8%A7%88%E5%99%A8/1.htm">浏览器</a><a class="tag" taget="_blank" href="/search/%E4%BA%92%E8%81%94%E7%BD%91/1.htm">互联网</a><a class="tag" taget="_blank" href="/search/servlet/1.htm">servlet</a>
                                        <div>原帖地址:http://www.iteye.com/topic/266705 
     
    form有2中方法把数据提交给服务器,get和post,分别说下吧。 
    (一)get提交 
    1.首先说下客户端(浏览器)的form表单用get方法是如何将数据编码后提交给服务器端的吧。 
       
    对于get方法来说,都是把数据串联在请求的url后面作为参数,如:http://localhost:</div>
                                    </li>
                                    <li><a href="/article/1234.htm"
                                           title="JS初学者必知的基础" target="_blank">JS初学者必知的基础</a>
                                        <span class="text-muted">百合不是茶</span>
    <a class="tag" taget="_blank" href="/search/js%E5%87%BD%E6%95%B0/1.htm">js函数</a><a class="tag" taget="_blank" href="/search/js%E5%85%A5%E9%97%A8%E5%9F%BA%E7%A1%80/1.htm">js入门基础</a>
                                        <div>JavaScript是网页的交互语言,实现网页的各种效果, 
    JavaScript 是世界上最流行的脚本语言。
    
    JavaScript 是属于 web 的语言,它适用于 PC、笔记本电脑、平板电脑和移动电话。
    
    JavaScript 被设计为向 HTML 页面增加交互性。
    
    许多 HTML 开发者都不是程序员,但是 JavaScript 却拥有非常简单的语法。几乎每个人都有能力将小的 </div>
                                    </li>
                                    <li><a href="/article/1361.htm"
                                           title="iBatis的分页分析与详解" target="_blank">iBatis的分页分析与详解</a>
                                        <span class="text-muted">bijian1013</span>
    <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/ibatis/1.htm">ibatis</a>
                                        <div>        分页是操作数据库型系统常遇到的问题。分页实现方法很多,但效率的差异就很大了。iBatis是通过什么方式来实现这个分页的了。查看它的实现部分,发现返回的PaginatedList实际上是个接口,实现这个接口的是PaginatedDataList类的对象,查看PaginatedDataList类发现,每次翻页的时候最</div>
                                    </li>
                                    <li><a href="/article/1488.htm"
                                           title="精通Oracle10编程SQL(15)使用对象类型" target="_blank">精通Oracle10编程SQL(15)使用对象类型</a>
                                        <span class="text-muted">bijian1013</span>
    <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a>
                                        <div>/*
     *使用对象类型
     */
    --建立和使用简单对象类型
    --对象类型包括对象类型规范和对象类型体两部分。
    --建立和使用不包含任何方法的对象类型
    CREATE OR REPLACE TYPE person_typ1 as OBJECT(
      name varchar2(10),gender varchar2(4),birthdate date
    );
    
    drop type p</div>
                                    </li>
                                    <li><a href="/article/1615.htm"
                                           title="【Linux命令二】文本处理命令awk" target="_blank">【Linux命令二】文本处理命令awk</a>
                                        <span class="text-muted">bit1129</span>
    <a class="tag" taget="_blank" href="/search/linux%E5%91%BD%E4%BB%A4/1.htm">linux命令</a>
                                        <div>awk是Linux用来进行文本处理的命令,在日常工作中,广泛应用于日志分析。awk是一门解释型编程语言,包含变量,数组,循环控制结构,条件控制结构等。它的语法采用类C语言的语法。 
      awk命令用来做什么? 
    1.awk适用于具有一定结构的文本行,对其中的列进行提取信息 
    2.awk可以把当前正在处理的文本行提交给Linux的其它命令处理,然后把直接结构返回给awk 
    3.awk实际工</div>
                                    </li>
                                    <li><a href="/article/1742.htm"
                                           title="JAVA(ssh2框架)+Flex实现权限控制方案分析" target="_blank">JAVA(ssh2框架)+Flex实现权限控制方案分析</a>
                                        <span class="text-muted">白糖_</span>
    <a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                        <div>  
    目前项目使用的是Struts2+Hibernate+Spring的架构模式,目前已经有一套针对SSH2的权限系统,运行良好。但是项目有了新需求:在目前系统的基础上使用Flex逐步取代JSP,在取代JSP过程中可能存在Flex与JSP并存的情况,所以权限系统需要进行修改。 
    【SSH2权限系统的实现机制】 
    权限控制分为页面和后台两块:不同类型用户的帐号分配的访问权限是不同的,用户使</div>
                                    </li>
                                    <li><a href="/article/1869.htm"
                                           title="angular.forEach" target="_blank">angular.forEach</a>
                                        <span class="text-muted">boyitech</span>
    <a class="tag" taget="_blank" href="/search/AngularJS/1.htm">AngularJS</a><a class="tag" taget="_blank" href="/search/AngularJS+API/1.htm">AngularJS API</a><a class="tag" taget="_blank" href="/search/angular.forEach/1.htm">angular.forEach</a>
                                        <div>angular.forEach   描述:   循环对obj对象的每个元素调用iterator, obj对象可以是一个Object或一个Array. Iterator函数调用方法: iterator(value, key, obj), 其中obj是被迭代对象,key是obj的property key或者是数组的index,value就是相应的值啦. (此函数不能够迭代继承的属性.)   </div>
                                    </li>
                                    <li><a href="/article/1996.htm"
                                           title="java-谷歌面试题-给定一个排序数组,如何构造一个二叉排序树" target="_blank">java-谷歌面试题-给定一个排序数组,如何构造一个二叉排序树</a>
                                        <span class="text-muted">bylijinnan</span>
    <a class="tag" taget="_blank" href="/search/%E4%BA%8C%E5%8F%89%E6%8E%92%E5%BA%8F%E6%A0%91/1.htm">二叉排序树</a>
                                        <div>
    import java.util.LinkedList;
    
    public class CreateBSTfromSortedArray {
    
    	/**
    	 * 题目:给定一个排序数组,如何构造一个二叉排序树
    	 * 递归
    	 */
    
    	public static void main(String[] args) {
    		int[] data = { 1, 2, 3, 4, </div>
                                    </li>
                                    <li><a href="/article/2123.htm"
                                           title="action执行2次" target="_blank">action执行2次</a>
                                        <span class="text-muted">Chen.H</span>
    <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/jsp/1.htm">jsp</a><a class="tag" taget="_blank" href="/search/XHTML/1.htm">XHTML</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/Webwork/1.htm">Webwork</a>
                                        <div>xwork 写道   <action name="userTypeAction" 
    class="com.ekangcount.website.system.view.action.UserTypeAction"> 
    <result name="ssss" type="dispatcher"> </div>
                                    </li>
                                    <li><a href="/article/2250.htm"
                                           title="[时空与能量]逆转时空需要消耗大量能源" target="_blank">[时空与能量]逆转时空需要消耗大量能源</a>
                                        <span class="text-muted">comsci</span>
    <a class="tag" taget="_blank" href="/search/%E8%83%BD%E6%BA%90/1.htm">能源</a>
                                        <div> 
     
            无论如何,人类始终都想摆脱时间和空间的限制....但是受到质量与能量关系的限制,我们人类在目前和今后很长一段时间内,都无法获得大量廉价的能源来进行时空跨越..... 
     
            在进行时空穿梭的实验中,消耗超大规模的能源是必然</div>
                                    </li>
                                    <li><a href="/article/2377.htm"
                                           title="oracle的正则表达式(regular expression)详细介绍" target="_blank">oracle的正则表达式(regular expression)详细介绍</a>
                                        <span class="text-muted">daizj</span>
    <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a>
                                        <div>    正则表达式是很多编程语言中都有的。可惜oracle8i、oracle9i中一直迟迟不肯加入,好在oracle10g中终于增加了期盼已久的正则表达式功能。你可以在oracle10g中使用正则表达式肆意地匹配你想匹配的任何字符串了。 
    正则表达式中常用到的元数据(metacharacter)如下: 
    ^ 匹配字符串的开头位置。 
    $ 匹配支付传的结尾位置。 
    * </div>
                                    </li>
                                    <li><a href="/article/2504.htm"
                                           title="报表工具与报表性能的关系" target="_blank">报表工具与报表性能的关系</a>
                                        <span class="text-muted">datamachine</span>
    <a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E5%B7%A5%E5%85%B7/1.htm">报表工具</a><a class="tag" taget="_blank" href="/search/birt/1.htm">birt</a><a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E6%80%A7%E8%83%BD/1.htm">报表性能</a><a class="tag" taget="_blank" href="/search/%E6%B6%A6%E4%B9%BE%E6%8A%A5%E8%A1%A8/1.htm">润乾报表</a>
                                        <div>在选择报表工具时,性能一直是用户关心的指标,但是,报表工具的性能和整个报表系统的性能有多大关系呢? 
    要回答这个问题,首先要分析一下报表的处理过程包含哪些环节,哪些环节容易出现性能瓶颈,如何优化这些环节。 
      
    一、报表处理的一般过程分析 
    1、用户选择报表输入参数后,报表引擎会根据报表模板和输入参数来解析报表,并将数据计算和读取请求以SQL的方式发送给数据库。 
      
    2、</div>
                                    </li>
                                    <li><a href="/article/2631.htm"
                                           title="初一上学期难记忆单词背诵第一课" target="_blank">初一上学期难记忆单词背诵第一课</a>
                                        <span class="text-muted">dcj3sjt126com</span>
    <a class="tag" taget="_blank" href="/search/word/1.htm">word</a><a class="tag" taget="_blank" href="/search/english/1.htm">english</a>
                                        <div>what 什么  
    your 你 
    name 名字 
    my 我的 
    am 是 
    one 一 
    two 二 
    three 三 
    four 四 
    five 五 
    class 班级,课 
      
    six 六 
    seven 七 
    eight 八 
    nince 九 
    ten 十 
    zero 零 
    how 怎样 
    old 老的 
    eleven 十一 
    twelve 十二 
    thirteen </div>
                                    </li>
                                    <li><a href="/article/2758.htm"
                                           title="我学过和准备学的各种技术" target="_blank">我学过和准备学的各种技术</a>
                                        <span class="text-muted">dcj3sjt126com</span>
    <a class="tag" taget="_blank" href="/search/%E6%8A%80%E6%9C%AF/1.htm">技术</a>
                                        <div>语言VB https://msdn.microsoft.com/zh-cn/library/2x7h1hfk.aspxJava http://docs.oracle.com/javase/8/C# https://msdn.microsoft.com/library/vstudioPHP http://php.net/manual/en/Html </div>
                                    </li>
                                    <li><a href="/article/2885.htm"
                                           title="struts2中token防止重复提交表单" target="_blank">struts2中token防止重复提交表单</a>
                                        <span class="text-muted">蕃薯耀</span>
    <a class="tag" taget="_blank" href="/search/%E9%87%8D%E5%A4%8D%E6%8F%90%E4%BA%A4%E8%A1%A8%E5%8D%95/1.htm">重复提交表单</a><a class="tag" taget="_blank" href="/search/struts2%E4%B8%ADtoken/1.htm">struts2中token</a>
                                        <div>struts2中token防止重复提交表单 
      
    >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
    蕃薯耀 2015年7月12日 11:52:32 星期日 
    ht</div>
                                    </li>
                                    <li><a href="/article/3012.htm"
                                           title="线性查找二维数组" target="_blank">线性查找二维数组</a>
                                        <span class="text-muted">hao3100590</span>
    <a class="tag" taget="_blank" href="/search/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">二维数组</a>
                                        <div>1.算法描述 
      
    有序(行有序,列有序,且每行从左至右递增,列从上至下递增)二维数组查找,要求复杂度O(n) 
      
    2.使用到的相关知识: 
    结构体定义和使用,二维数组传递(http://blog.csdn.net/yzhhmhm/article/details/2045816) 
      
    3.使用数组名传递 
    这个的不便之处很明显,一旦确定就是不能设置列值 
      
    //使</div>
                                    </li>
                                    <li><a href="/article/3139.htm"
                                           title="spring security 3中推荐使用BCrypt算法加密密码" target="_blank">spring security 3中推荐使用BCrypt算法加密密码</a>
                                        <span class="text-muted">jackyrong</span>
    <a class="tag" taget="_blank" href="/search/Spring+Security/1.htm">Spring Security</a>
                                        <div>spring security 3中推荐使用BCrypt算法加密密码了,以前使用的是md5, 
    Md5PasswordEncoder 和 ShaPasswordEncoder,现在不推荐了,推荐用bcrpt 
    Bcrpt中的salt可以是随机的,比如: 
     
     
     
    
    int i = 0;
    	while (i < 10) {
    		String password = "1234</div>
                                    </li>
                                    <li><a href="/article/3266.htm"
                                           title="学习编程并不难,做到以下几点即可!" target="_blank">学习编程并不难,做到以下几点即可!</a>
                                        <span class="text-muted">lampcy</span>
    <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/1.htm">编程语言</a>
                                        <div>不论你是想自己设计游戏,还是开发iPhone或安卓手机上的应用,还是仅仅为了娱乐,学习编程语言都是一条必经之路。编程语言种类繁多,用途各 异,然而一旦掌握其中之一,其他的也就迎刃而解。作为初学者,你可能要先从Java或HTML开始学,一旦掌握了一门编程语言,你就发挥无穷的想象,开发 各种神奇的软件啦。 
    1、确定目标 
    学习编程语言既充满乐趣,又充满挑战。有些花费多年时间学习一门编程语言的大学生到</div>
                                    </li>
                                    <li><a href="/article/3393.htm"
                                           title="架构师之mysql----------------用group+inner join,left join ,right join 查重复数据(替代in)" target="_blank">架构师之mysql----------------用group+inner join,left join ,right join 查重复数据(替代in)</a>
                                        <span class="text-muted">nannan408</span>
    <a class="tag" taget="_blank" href="/search/right+join/1.htm">right join</a>
                                        <div>1.前言。 
      如题。 
    2.代码 
    (1)单表查重复数据,根据a分组 
      
    
    
    SELECT m.a,m.b, INNER   JOIN (select a,b,COUNT(*) AS rank FROM test.`A` A   GROUP BY a HAVING rank>1 )k ON m.a=k.a
    
    
    
     
    (2)多表查询 , 
     使用改为le</div>
                                    </li>
                                    <li><a href="/article/3520.htm"
                                           title="jQuery选择器小结 VS 节点查找(附css的一些东西)" target="_blank">jQuery选择器小结 VS 节点查找(附css的一些东西)</a>
                                        <span class="text-muted">Everyday都不同</span>
    <a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/name%E9%80%89%E6%8B%A9%E5%99%A8/1.htm">name选择器</a><a class="tag" taget="_blank" href="/search/%E8%BF%BD%E5%8A%A0%E5%85%83%E7%B4%A0/1.htm">追加元素</a><a class="tag" taget="_blank" href="/search/%E6%9F%A5%E6%89%BE%E8%8A%82%E7%82%B9/1.htm">查找节点</a>
                                        <div>最近做前端页面,频繁用到一些jQuery的选择器,所以特意来总结一下: 
      
    测试页面: 
    <html>
    	<head>
    		<script src="jquery-1.7.2.min.js"></script>
    		<script>
    		/*$(function() {
    			$(documen</div>
                                    </li>
                                    <li><a href="/article/3647.htm"
                                           title="关于EXT" target="_blank">关于EXT</a>
                                        <span class="text-muted">tntxia</span>
    <a class="tag" taget="_blank" href="/search/ext/1.htm">ext</a>
                                        <div>  
    ExtJS是一个很不错的Ajax框架,可以用来开发带有华丽外观的富客户端应用,使得我们的b/s应用更加具有活力及生命力。ExtJS是一个用 javascript编写,与后台技术无关的前端ajax框架。因此,可以把ExtJS用在.Net、Java、Php等各种开发语言开发的应用中。 
      
      
      
    ExtJs最开始基于YUI技术,由开发人员Jack </div>
                                    </li>
                                    <li><a href="/article/3774.htm"
                                           title="一个MIT计算机博士对数学的思考" target="_blank">一个MIT计算机博士对数学的思考</a>
                                        <span class="text-muted">xjnine</span>
    <a class="tag" taget="_blank" href="/search/Math/1.htm">Math</a>
                                        <div> 在过去的一年中,我一直在数学的海洋中游荡,research进展不多,对于数学世界的阅历算是有了一些长进。为什么要深入数学的世界?作为计算机的学生,我没有任何企图要成为一个数学家。我学习数学的目的,是要想爬上巨人的肩膀,希望站在更高的高度,能把我自己研究的东西看得更深广一些。说起来,我在刚来这个学校的时候,并没有预料到我将会有一个深入数学的旅程。我的导师最初希望我去做的题目,是对appe</div>
                                    </li>
                    </ul>
                </div>
            </div>
        </div>
    
    <div>
        <div class="container">
            <div class="indexes">
                <strong>按字母分类:</strong>
                <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                    href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                    href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                    href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                    href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                    href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                    href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                    href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                    href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
            </div>
        </div>
    </div>
    <footer id="footer" class="mb30 mt30">
        <div class="container">
            <div class="footBglm">
                <a target="_blank" href="/">首页</a> -
                <a target="_blank" href="/custom/about.htm">关于我们</a> -
                <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
                <a target="_blank" href="/sitemap.txt">Sitemap</a> -
                <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
            </div>
            <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
    <!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
            </div>
        </div>
    </footer>
    <!-- 代码高亮 -->
    <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
    <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
    <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
    <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
    <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>
    
    
    
    
    
    </body>
    
    </html>