挑战全网最全之python教程(持续补充更新)

本文详细介绍了Python的基础数据类型,包括原子型(int、float、string、boolean)和结构型(list、tuple、set、dict)。深入探讨了字符串的运算、列表的增删改查、元组的不可变性、集合的无序和不重复以及字典的操作。此外,还讲解了迭代器和生成器的概念与使用,以及函数的定义、参数、返回值和作用域。文章提到了面向对象编程中的类定义、构造方法、属性和方法,以及继承和多态。接着,介绍了装饰器、异常处理、模块和包的使用,以及标准库如sys、os、math和random的常见功能。最后,讨论了文件I/O、进程与线程的概念、多线程同步、进程间通信,并简要提及了正则表达式、网络编程、数据库操作和爬虫的基础知识。

python知识体系

一、数据类型

1、原子型

定义:一种值的集合 + 定义在值集合上的一组操作

特点:无法被改变

  • int
  • float
  • string
  • boolean

字符串详解

#1.转义字符 
	自行查阅
#2.字符运算
	如下表
#3.Python 三引号
	Python 三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。
#4.字符串内建函数
	自行查阅

字符串运算

操作符描述实例
+字符串连接>>>a + b ‘HelloPython’ 注意:-1 表示从右边起第一位
*重复输出字符串>>>a * 2 ‘HelloHello’
[]通过索引获取字符串中字符>>>a[1] ‘e’
[ : : ]截取字符串中的一部分>>>a[1:4:2] ‘el’
in成员运算符 - 如果字符串中包含给定的字符返回 True>>>“H” in a True
not in成员运算符 - 如果字符串中不包含给定的字符返回 True>>>“M” not in a True
r原始字符串:所有的字符串都是直接按照字面的意思来使用>>>print r’\n’ \n
%格式字符串print “My name is %s and weight is %d kg!” % (‘Zara’, 21)

2、结构型

定义:一种数据结构 + 定义在这种数据结构上的一组操作

  • list

  • tunlp

  • set

  • dict

2.1 列表(list)详解
特点:列表是动态的, 长度大小不固定, 可以任意的增加、删除、修改

语法:[a,b,...]                 eg: [ 1,b ]

1、增删改
增:append(obj) | insert(index, obj)
删:remove(obj) | del(list[index]) | pop(index)
改:list[index] = newObj

2、列表长度: len(list)
2.2 元组(tunlp)详解

元组是静态的, 长度大小固定, 不能增删改

eg: ( 1,a )

2.3 集合(set)详解

集合里面的元素无序,不重复的!不支持索引

eg: { 8, 9 }

2.4 字典(dict)详解
字典是由多个键值对组成的集合,键不可重复(重复的话会被覆盖)

1len(dict)

2、增删改查
增:dict1[‘newKey’] = value
删:pop(‘key’, defalutValue)
改:dict1[‘key’] = newValue
查:dict1[‘key’]

3、遍历
for key, value in student.items():


二、流程控制

  • if
  • for
  • while
  • break,continue

语法:

# if
    if X:
        ....
    elif:
        ....
    else:
        ....
    
# for
	for 变量 in 序列:
		语句
		....
        
# while
	while 表达式:
        语句
        ....

三、迭代器、生成器

1、迭代器

迭代器是一个可以被遍历的对象,提供了逐个访问元素的能力(通常用 for 循环)。它遵循 迭代器协议,即实现了两个方法:

  • iter():返回迭代器对象本身。
  • next():返回下一个元素,遍历结束时抛出 StopIteration 异常。

通俗理解:迭代器就像一个“指针”,每次调用 next() 就指向并返回序列中的下一个元素,直到没有元素为止。

常见例子:Python 的列表、元组、字符串等可以通过 iter() 函数转为迭代器

# 创建一个列表
my_list = [1, 2, 3]

# 转为迭代器
iterator = iter(my_list)

# 使用 next() 获取元素
print(next(iterator))  # 输出: 1
print(next(iterator))  # 输出: 2
print(next(iterator))  # 输出: 3

# 遍历完后,再次调用 next() 会抛出 StopIteration
try:
    print(next(iterator))
except StopIteration:
    print("No more elements!")

# 用 for 循环遍历(更常用)
iterator = iter(my_list)  # 重新创建迭代器
for item in iterator:
    print(item)  # 输出: 1, 2, 3

2、生成器

生成器是一种特殊的迭代器,它通过 yield 关键字 按需生成数据,而不是一次性将所有数据加载到内存。

通俗理解:生成器像一个“暂停和恢复”的函数,每次调用 next() 时执行到 yield 处,生成一个值并暂停,等下次调用再继续。

特点:

  • 惰性计算:数据按需生成,节省内存。
  • 自动实现迭代器协议(无需手动定义 iternext)。
  • 只能遍历一次,耗尽后需重新创建。

eg:

# 定义生成器函数:生成 1 到 n 的平方
def square_generator(n):
    for i in range(1, n + 1):
        yield i * i

# 创建生成器对象
gen = square_generator(3)

# 使用 next() 获取值
print(next(gen))  # 输出: 1 (1*1)
print(next(gen))  # 输出: 4 (2*2)
print(next(gen))  # 输出: 9 (3*3)

# 或者用 for 循环
#在 Python 中,for 循环会自动实现 next() 功能。
gen = square_generator(3)  # 重新创建
for square in gen:
    print(square)  # 输出: 1, 4, 9

说明:

  • yield i * i 每次生成一个平方值并暂停。
  • 调用 next(gen) 或 for 循环时,函数从上一次暂停处继续执行。
  • 生成器只计算当前需要的平方,节省内存

字节面试题
统计1T的nginx 访问日志文件,统计后端url访问次数,并取出前十的url及其访问次数。后端的url以 /api 开头


#生成一个生成器,读取文件
def read_log(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            yield line
#分析日志
def analysis_log(lines):
    #统计nginx访问日志中url的访问次数,只统计后端接口的访问次数
    #223.104.84.107 - - [18/Apr/2025:04:05:25 +0000] "POST /api/bazi/paipan HTTP/1.1" 200 226 "http://47.107.237.220/bazi" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36"

    url_count = {}
    for line in lines:
        #取出url
        url = line.split(' ')[6]
        #只统计后端接口的访问次数
        if url.startswith('/api/'):
            url_count[url] = url_count.get(url, 0) + 1
    return url_count

#统计前10的url
def analysis_top_10(url_count):
    #根据url的访问次数排序,不要用语法糖
    sorted_url_count = sorted(url_count.items(), key=lambda x: x[1], reverse=True)
    #取前10
    return sorted_url_count[:10]

def main():
    file_path = 'access.log'
    lines = read_log(file_path)
    url_count = analysis_log(lines)
    top_10 = analysis_top_10(url_count)
    print(top_10)


if __name__ == "__main__":
    main()

四、函数

1、 定义与使用

定义:
def fun_name(arg1,arg2):
语句

return value

使用:
fun_name(arg1,arg2)

2、 参数

  • 必须参数
  • 关键字参数
  • 默认参数
  • 可变参数
1. 必须参数
	def test(a,b):
    	pass

2. 关键字参数
	test(a="tmli",b=18)

3. 默认参数
	def test(a,b=18):
    	pass	

4. 可变参数
	def test(*args,**kwargs):
        pass
    
    " *args "    获取的是一个元组
    " **kwargs " 获取的是一个字典

3、 变量作用域

  • 局部变量:仅函数内部使用
  • 全局变量: 整个程序范围内使用

4、 返回值

​ 如果想获取函数中的局部变量,可以使用return关键字返回

5、 Lambda表达式(匿名函数)

def add(x,y):
    retutn x+y
    
lambda x,y:x+y

五、面向对象

1、定义和使用

class animal:
	pass

dog=animal()

2、构造方法

class animal:
	def __init__(self):
		语句

类在实例化时会自动调用构造方法,用于创建新的类实例

3、类的属性,方法

属性(成员变量、类变量),必须是“self.” 的方式赋值。直接定义的变量在函数执行完就会被销毁

类里面方法的第一次参数必须是self,在构造方法中我们可以初始化一些属性:

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

    def eat(self):
        print("eating!!!")

def main():
	dog = animal("wangwang")
	dog.eat()

if __name__ == "__main__":
    main()

4、类的私有属性,私有方法

在类中定义变量或者函数时以双下划线开头。

私有属性和方法只能在类中使用

案例:学生类 (Student)
我们创建一个 Student 类,管理学生信息:

私有属性:__age(学生年龄,敏感数据)。
私有方法:__is_valid_age(验证年龄是否合法)。
普通方法:设置年龄 (set_age) 和获取年龄 (get_age)。

class Student:
    def __init__(self, name):
        self.name = name
        # 私有属性:年龄
        self.__age = 0

    # 私有方法:验证年龄是否合法
    def __is_valid_age(self, age):
        return 0 < age <= 120

    # 普通方法:设置年龄
    def set_age(self, age):
        if self.__is_valid_age(age):
            self.__age = age
            return f"{self.name}'s age set to {age}"
        else:
            return "Invalid age!"

    # 普通方法:获取年龄
    def get_age(self):
        return f"{self.name}'s age is {self.__age}"

# 测试代码
student = Student("Bob")
print(student.set_age(20))      # 输出: Bob's age set to 20
print(student.get_age())        # 输出: Bob's age is 20
print(student.set_age(-5))      # 输出: Invalid age!

# 尝试直接访问私有属性(会报错)
try:
    print(student.__age)
except AttributeError:
    print("Cannot access private attribute __age directly!")


5、类方法和静态方法

1、静态方法 (staticmethod)

定义:

  • 静态方法是通过 @staticmethod 装饰器定义的类方法。
  • 它不接收任何隐式参数,既不接收实例(self),也不接收类(cls)。

特点:

  • 无需访问实例或类的状态:静态方法不依赖于实例或类的属性/方法,因此可以独立调用。
  • 调用方式:可以通过类名或实例调用,但通常通过类名调用更直观。
  • 用途:通常用于定义与类相关的工具函数或逻辑,这些函数不需要访问类的状态,但从语义上与类相关。

2、类方法 (classmethod)
定义:

  • 类方法是通过 @classmethod 装饰器定义的类方法。
  • 它接收类本身作为第一个隐式参数,习惯命名为 cls。
  • 类方法可以访问和修改类的状态(如类属性),但不能直接访问实例的属性。

特点:

  • 接收类作为参数:第一个参数 cls 指向类本身,可以用来访问类属性或调用其他类方法。
  • 调用方式:可以通过类名或实例调用,但通常通过类名调用更常见。
  • 用途:常用于定义需要操作类状态或实现替代构造函数的场景。

eg:

class PetStore:
    # 类属性:记录宠物总数
    total_pets = 0

    def __init__(self, name):
        self.name = name
        # 每添加一只宠物,总数加 1
        PetStore.total_pets += 1

    # 类方法:获取宠物总数
    @classmethod
    def get_total_pets(cls):
        return f"{cls.__name__} has {cls.total_pets} pets"

    # 静态方法:检查宠物名字是否合法
    @staticmethod
    def is_valid_name(name):
        return name.strip() != ""

# 测试代码
def main():
    # 使用静态方法检查名字
    print(PetStore.is_valid_name("Buddy"))  # 输出: True
    print(PetStore.is_valid_name(""))       # 输出: False

    # 创建宠物
    pet1 = PetStore("Buddy")
    print(pet1.name)  # 输出: Buddy
    print(PetStore.get_total_pets())  # 输出: PetStore has 1 pets

    pet2 = PetStore("Luna")
    print(PetStore.get_total_pets())  # 输出: PetStore has 2 pets

if __name__ == "__main__":
    main()

6、继承与多态

继承

**是什么:**本质就是在一个类的基础上定制一个新类,新类不仅可以继承父类的方法和属性,还能添加新的。python支持继承多个父类

特点:
如果子类定义了构造方法,父类的构造方法不会被调用(多态)
子类不能继承父类的私有方法,私有属性

多态

子类和父类有相同的方法时,子类方法会覆盖父类的方法

六、常见设计模式

在实际开发中,最常用的设计模式通常有以下几种:

创建型

  • 单例模式:确保一个类只有一个实例,如数据库连接池、配置管理器
  • 工厂方法:将对象的创建委托给专门的工厂类,隐藏具体实现细节

结构型

  • 装饰器模式:动态地给对象添加功能,常见于I/O流处理、Web中间件
  • 适配器模式:让不兼容的接口能够协同工作,如旧系统集成

行为型

  • 观察者模式:定义对象间的一对多依赖关系,适用于事件处理系统
  • 策略模式:定义算法族并封装,使它们可互换,如支付方式选择
  • 迭代器模式:提供统一的方式遍历集合,不暴露内部结构

这些模式之所以常用,是因为它们解决了软件开发中反复出现的基本问题,如灵活创建对象、组织代码结构、处理对象间通信等。根据不同的编程语言和应用领域,使用频率可能有所不同。

单例模型

确保一个类只有一个实例

适用场景:数据库连接、配置管理器、日志记录器

class Singleton:
    _instance = None
    
    def __new__(cls):
        if cls._instance is None:
        	#super() 获取父类引用(这里是 object,因为所有 Python 类默认继承自 object)
        	#super().__new__(cls) 调用 object.__new__(cls),创建一个全新的 Singleton 类实例
            cls._instance = super().__new__(cls)
            cls._instance.value = "单例对象的数据"
        return cls._instance

# 测试
s1 = Singleton()
s2 = Singleton()
print(s1 is s2)  # 输出: True
print(s1.value)  # 输出: 单例对象的数据

在 Python 中,new 是一个特殊方法,主要用于控制对象的创建过程。它属于类的静态方法,在对象实例化时首先被调用,负责创建并返回一个新的对象实例

工厂方法模式

适用场景:根据条件创建不同但相关的对象

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "汪汪!"

class Cat(Animal):
    def speak(self):
        return "喵喵!"

class AnimalFactory:
    def create_animal(self, animal_type):
        if animal_type == "dog":
            return Dog()
        elif animal_type == "cat":
            return Cat()
        else:
            raise ValueError(f"不支持的动物类型: {animal_type}")

# 使用工厂
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")

print(dog.speak())  # 输出: 汪汪!
print(cat.speak())  # 输出: 喵喵!

装饰器模式

适用场景:在不修改原代码的情况下添加功能,如日志、缓存、权限检查

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"调用函数: {func.__name__}")
        result = func(*args, **kwargs)
        print(f"函数 {func.__name__} 返回: {result}")
        return result
    return wrapper

@log_decorator
def add(a, b):
    return a + b

# 测试
result = add(3, 5)  # 输出函数调用信息和结果

def wrapper(*args, **kwargs) 是 Python 中一种非常灵活的函数定义方式,允许函数接收任意数量的位置参数和关键字参数。这种语法在编写装饰器、包装函数或需要传递可变数量参数的函数时特别有用。

基本解释
*args: 收集所有位置参数到一个元组中
**kwargs: 收集所有关键字参数到一个字典中

eg:

def show_args(*args):
    print(f"args 的类型是: {type(args)}")
    print(f"args 的内容是: {args}")
    
    # 可以像处理元组一样处理 args
    for i, arg in enumerate(args):
        print(f"第 {i+1} 个参数是: {arg}")

# 调用函数,传入多个位置参数
show_args(10, "hello", [1, 2, 3])


###
args 的类型是: <class 'tuple'>
args 的内容是: (10, 'hello', [1, 2, 3])1 个参数是: 102 个参数是: hello
第 3 个参数是: [1, 2, 3]
###



def show_kwargs(**kwargs):
    print(f"kwargs 的类型是: {type(kwargs)}")
    print(f"kwargs 的内容是: {kwargs}")
    
    # 可以像处理字典一样处理 kwargs
    for key, value in kwargs.items():
        print(f"参数 '{key}' 的值是: {value}")

# 调用函数,传入多个关键字参数
show_kwargs(name="Alice", age=30, city="Beijing")


###
kwargs 的类型是: <class 'dict'>
kwargs 的内容是: {'name': 'Alice', 'age': 30, 'city': 'Beijing'}
参数 'name' 的值是: Alice
参数 'age' 的值是: 30
参数 'city' 的值是: Beijing

###

适配器模式

让不兼容的接口能够协同工作,如旧系统集成

# 已有的接口
class OldSystem:
    def old_request(self, string):
        return f"旧系统处理: {string}"

# 目标接口
class NewSystem:
    def new_request(self, data):
        pass

# 适配器
class SystemAdapter(NewSystem):
    def __init__(self, old_system):
        self.old_system = old_system
        
    def new_request(self, data):
        # 转换请求格式
        result = self.old_system.old_request(data)
        return f"适配后的结果: {result}"

# 使用
old = OldSystem()
adapter = SystemAdapter(old)
result = adapter.new_request("测试数据")
print(result)  # 输出: 适配后的结果: 旧系统处理: 测试数据

观察者模式

定义对象间的一对多依赖关系,适用于事件处理系统

适用场景:事件处理系统、消息推送

class Subject:
    def __init__(self):
        self._observers = []
        self._state = None
        
    def attach(self, observer):
        self._observers.append(observer)
        
    def notify(self):
        for observer in self._observers:
            observer.update(self._state)
    
    #将方法转换为只读属性
	#允许使用 subject.state 语法访问 _state 值,不需要调用方法(不用写括号)
    @property
    def state(self):
        return self._state
    
    #定义当属性被赋值时执行的代码
    #允许使用 subject.state = value 语法设置值
    #在设置状态值的同时自动调用 notify() 通知所有观察者
    @state.setter
    def state(self, value):
        self._state = value
        self.notify()
        
class Observer:
    def update(self, state):
        pass
        
class ConcreteObserver(Observer):
    def __init__(self, name):
        self.name = name
        
    def update(self, state):
        print(f"观察者 {self.name} 收到通知: 状态变为 {state}")

# 使用
subject = Subject()
observer1 = ConcreteObserver("观察者1")
observer2 = ConcreteObserver("观察者2")

subject.attach(observer1)
subject.attach(observer2)

subject.state = "新状态"
# 输出:
# 观察者 观察者1 收到通知: 状态变为 新状态
# 观察者 观察者2 收到通知: 状态变为 新状态

虽然两个方法都叫 state,但它们有不同的功能:

@property 装饰的 state 方法:处理读取操作
@state.setter 装饰的 state 方法:处理写入操作

七、装饰器

看了那么多篇,就这篇通俗易懂,我在这里就不自己总结

https://blog.csdn.net/zhh763984017/article/details/120072425

七、异常与异常处理

1、异常

运行时检测到的错误被称为异常。通常检测到异常,程序会中断。

2、异常处理

有时候我们希望某些错误不会影响到程序的完整运行,这时候我们可以进行异常处理!

语法:

try:
    业务语法块
expert 异常类型:
	处理异常语法块
...
else: 
    无异常语法块
finally:
    无论是否有异常都会执行语法块

3、抛出异常

除了系统抛出的异常,我们也可以自动抛出异常。

raise Exception("这是错误信息")

4、自定义异常

当内建的类无法满足需求是,我们需要自定义异常

自定义异常需要继承Exception

class MyException(Exception):
    def __init__(self):
        pass
    
    """
    返回一个对象的描述信息,python中调用print()打印实例化对象时会调用__str__()如果__str__()中有返回值,就会打印其中的返回值。
    
    """
    def __str__(self):
        return "这是个自定义异常"
    

八、模块

1、模块

1.1 是什么

模块就是 定义重复利用代码的 python文件, 可用 import 或者 from…import… 导入使用

import //导入模块文件

from…import… //从指定模块文件中导入指定的函数

1.2 __ name __ 变量

模块的模块名可以通过全局变量 “__ name __ ” 获取

module.__name__     //模块module的名字

__name__    //当前模块名称,当模块被运行时模块名为“__main__”,可以用这个特性判断当前文件是被运行还是作为模块导入
1.3 dir函数

dir函数可以列出对象的 模块标识符(函数,类,变量)

print(dir(os))

2、包

2.1 是什么

包是用来管理模块的,简单来说包就是文件夹,里面必须要有__ init __.py 文件,该文件用于标识当前文件夹是一个包

2.2 包在多目录中使用

当你导入一个模块或者包的时候,python解析器对模块位置的搜索顺序是:

  1. 首先查找当前目录
  2. 如果不在当前目录,python则会搜索在shell变量PYTHONPATH下的每一个目录
  3. 如果都找不到,python就会查看默认路径。以linux为例,默认路径一般为/usr/local/lib

模块搜索路径存储在system模块的sys.path变量中,变量包含当前目录、PYTHONPATH下的目录、由安装过程决定的默认目录

3、标准库

python官方提供的包和模块,我们称为标准库,他会随着python解析器安装到计算机中

3.1 sys

sys模块提供了很多函数和变量来处理python运行环境的不同部分

sys.platform //识别操作系统
sys.argv     //获取命令行的参数(执行脚本是传入的参数)
sys.exit     //退出程序
sys.path    //获取模块的搜索路径
sys.modules  //找到已导入模块

扩展

  1. 与类和实例无绑定关系的function都属于函数(function);
  2. 与类和实例有绑定关系的function都属于方法(method);
3.2 os

os模块封装了操作系统的文件和目录操作。

os.getcwd   //获取当前文件执行路径
os.chdir    //切换当前路径
os.rename    //文件重命名
os.mkdir(path) //创建目录
os.makedirs     //创建多重目录
os.environ.items()  //获取系统环境变量

os.path.dirname(__file__)    //当前文件所在位置(__file__为内置变量,表示文件绝对路径)
os.path.exists  //判断路径是否存在
os.path.isfile  //判断路径是否是文件
os.path.isdir  //判断路径是否是目录


3.3 math

math封装了许多运算和函数操作

3.4 random

random模块包含了很多随机数相关的方法

4、第三方库

使用pip命令管理第三方库

语法:
pip list         //列出已安装软件包
pip [install/uninstall]  软件包名==版本号   //安装或卸载 
pip install -r requirements.txt          //批量安装
pip search 关键字         

pip install 软件包名==版本号 -i 源地址

九、文件与IO

1、文件内容操作

内置函数open可以对文件内容进行处理(读,写,改)

1.1 打开文件

内置函数open打开文件, 无论是读还是写都要先打开文件

例子:
f=open(file,mode='r',encoding=None,buffering=-1)
1.2 文件基本操作
f.read()    //读
f.readline()      //按行读,readlines() 全部读出返回一个数组
f.write()     //写
f.writelines() //按行写

1.3 关闭文件对象(close)

为了安全起见,无论是读还是写都要关闭文件对象,虽然程序结束也会自动关闭

f.close

扩展:

如果读写过程有异常,建议try捕获处理

1.4 案例
遍历日志文件的每一行(这种写法会自动帮我们关闭文件对象,不需要执行close)
with open('log.txt','r') as f:
  for line in f.readlines():
    print(line)  

十、进程与线程

1、介绍

1.1 是什么

进程:操作系统进行资源分配的基本单位
线程:cpu运算调度的基本单位

1.2 两者之间的关系

一个进程可以有多个线程;进程中的线程可以共享该进程的全部资源

在使用python xx.py 运行时,内部就创建一个进程(主进程),在进程中创建了一个线程(主线程),由线程逐行运行代码。

1.3 CPython

CPython是最流行的python解析器。

CPython 使用了 全局解析器锁(GIL) 来实现线程同步,即任意时刻一个进程只能有一个线程被cpu执行!这样做是为了防止多个线程同时执行python字节码。因此就算多核心的cpu也禁止一个进程里面的多线程的并行,浪费了大量的cpu性能。所以可以用多进程可以充分利用cpu资源

1.4 使用场景
  • 计算密集型,用多进程,例如:大量的数据计算(算法)。
  • IO密集型,用多线程,例如:文件读写、网络数据传输 。

2、线程

2.1 多线程

多线程是指在操作系统上并发执行多个线程的技术。一个1核的cpu只能运行一个线程,但是操作系统可以快速切换不同的线程,由于时间间隔太小,给用户造成一种同时执行的假象!

在python中我们一般使用threading模块中的Thread类实现多线程

方法1


from threading import Thread
import time


def work(id):
    print("{id} 正在工作".format(id=id))
    print("{id} thread is over".format(id=id))


def main():
    threads = []

    # 创建线程
    for i in range(5):
        thread = Thread(target=work, args=(i,))
        threads.append(thread)
    # 启动线程
    for i in range(5):
        threads[i].start()

    # join()方法只有等待线程执行完毕才会往下继续执行
    for i in range(5):
        thread[i].join()
    print("end!!!!!")


if __name__ == "__main__":
    main()

方法2:

from threading import Thread
import time


class mythread(Thread):
    def __init__(self, id):
        super(mythread, self).__init__()
        self.id = id

    def run(self):
        print("{id} 正在工作".format(id=self.id))
        time.sleep(2)
        print("{id} thread is over".format(id=self.id))


def main():
    threads = []

    # 创建线程
    for i in range(5):
        thread = mythread(i)
        threads.append(thread)
    # 启动线程
    for i in range(5):
        threads[i].start()

    # 等待线程执行完毕
    for i in range(5):
        thread.join()
    print("end!!!!!")


if __name__ == "__main__":
    main()

2.2 线程同步

确保每次只有一个线程在执行

from threading import Thread, Lock
import time


class mythread(Thread):
    def __init__(self, id):
        super(mythread, self).__init__()
        self.id = id

    def run(self):
        # 获取锁
        t_lock.acquire()
        print("{id} 正在工作".format(id=self.id))
        # 释放锁
        t_lock.release()
        t_lock.acquire()
        time.sleep(2)
        print("{id} thread is over".format(id=self.id))
        t_lock.release()


def main():
    threads = []

    # 创建线程
    for i in range(5):
        thread = mythread(i)
        threads.append(thread)
    # 启动线程
    for i in range(5):
        threads[i].start()

    # 等待线程执行完毕
    for i in range(5):
        thread.join()
    print("end!!!!!")


if __name__ == "__main__":
    t_lock = Lock()
    main()

2.3 线程队列

队列可以通过控制锁(锁定、释放等)来实现线程之间的数据共享

在python中我们通常采用Queue模块实现队列功能,遵循先进先出的规则

from threading import Thread
import queue
import time

work_q = queue.Queue(maxsize=6)
result_q = queue.Queue(maxsize=6)


class myThread(Thread):
    def __init__(self, id):
        super(myThread, self).__init__()
        self.id = id

    def run(self):
        while not work_q.empty():
            # 从工作队列中去取数据
            work = work_q.get()
            out = "{id} is work".format(id=self.id)
            # 模拟工作耗时
            time.sleep(2)
            # 将数据存进结果队列中
            result_q.put(out)


def main():
    # 工作队列中放入数据
    for i in range(6):
        work_q.put(i)
    # 开启两个线程
    for i in range(2):
        myThread(i).start()

    # 取出并输出队列的数据
    for i in range(6):
        print(result_q.get())


if __name__ == "__main__":
    main()

3. 进程

调用外部命令也是调用进程的方式,os模块提供了许多调用外部命令的的函数,如system、exec系列函数。subprocess模块。multiprocessing.Process。

此处只讲解multiprocessing.Process实现多进程,进程同步,进程队列。

3.1 multiprocessing.Process多进程

multiprocessing实现多进程的方式和多线程相似。multiprocessing.Queue可以在多线程中进行通信,

from multiprocessing import Process, Queue
import time


class myprocess(Process):
    def __init__(self, id, q):
        super(Process, self).__init__()
        self.id = id
        self.q = q

    def run(self):
        print("{id} 正在工作".format(id=self.id))
        time.sleep(2)
        print("{id} process is over".format(id=self.id))
        out = "{id} result!!!".format(id=self.id)
        self.q.put(out)


def main():
    result_q = Queue()
    processes = []

    # 创建线程
    for i in range(5):
        thread = myprocess(i, result_q)
        processes.append(thread)
    # 启动线程
    for i in range(5):
        processes[i].start()

    # 等待线程执行完毕
    for i in range(5):
        processes[i].join()
    while not result_q.empty():
        print(result_q.get())
        time.sleep(1)


if __name__ == "__main__":
    main()

3.2 进程池

进程池可以提供指定数目的进程供用户使用,每当有新的请求提交到pool时,如果pool还没满,就可以创建一个新的进程来执行该请求;如果pool中的进程数已经达到规定的最大值,那么请求就会等待,直到池中有进程结束才会创建新的进程来执行它。

from multiprocessing import Pool
import time


def run(id):
    print("{id} 正在工作".format(id=id))
    time.sleep(2)
    print("{id} process is over".format(id=id))


def main():
    pool = Pool(processes=3)

    # 向线程池中加入要执行的任务
    for i in range(5):
        pool.apply_async(run, args=(i,))
    # 关闭线程池,不能再有新的任务被加入到线程池
    pool.close()
    # 等待所有子进程结束
    pool.join()


if __name__ == "__main__":
    main()

线程池可以使用multiprocess.dummp.Pool函数,使用基本和上述一致

4. 协程

协程,又称微线程。协程的作用是在执行函数A时可以随时中断去执行函数B,然后中断函数B继续执行函数A(可以自由切换)。但这一过程并不是函数调用,这一整个过程看似像多线程,然而协程只有一个线程执行。

优势:

  • 执行效率极高,因为子程序切换(函数)不是线程切换,由程序自身控制,没有切换线程的开销。所以与多线程相比,线程的数量越多,协程性能的优势越明显。
  • 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在控制共享资源时也不需要加锁,因此执行效率高很多。

十一、正则表达式

十二、网络编程

十三、操作数据库

十四、爬虫

1、urllib

get请求

from urllib import request
# 创建请求类
request = request.Request("https://www.baidu.com")   
#发起请求
response = request.urlopen(request)
# 用decode解码读到的内容 
print(response.read().decode("utf-8"))



post请求

from urllib import request,parse
url = "http://httpbin.org/post"
headers = {
    #伪装一个火狐浏览器
    "User-Agent":'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
    "host":'httpbin.org'
}
dict = {
    "name":"Germey"
}

# Request传入的data必须是bytes (字节流)类型,如果是一个字典,可以先用 urlencode() 转成字符串,再用bytes()转成字节流类型
data = bytes(parse.urlencode(dict),encoding="utf8")
req = request.Request(url=url,data=data,headers=headers,method="POST")
response = request.urlopen(req)
print(response.read().decode("utf-8"))
print(response.getcode())
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值