前言
Python,这门以简洁、易读著称的解释型编程语言,已经成为全球最受欢迎的编程工具之一。无论你是刚踏入编程世界的新手,还是希望快速开发应用的工程师,Python 都能以其丰富的库生态和清晰的语法,帮助你实现想法
我看的教学视频是尚硅谷的 写这篇文章的目的就是巩固自己所学
一、Python 安装与环境配置
开始写代码之前我们需要下载Python解释器 确保有相关的环境 这里以windows下载为例 其它的系统如Linux,mac一样的逻辑
1. 下载 Python
- 打开官方网站:Python 官网
https://www.python.org/
- 点击导航栏的Downloads,根据你的操作系统选择对应版本下载(建议选择最新的稳定版本,如 Python 3.x)
箭头所指的版本应该就是目前最新最稳定的版本了
点击Windows进来之后 左侧的这一列都是稳定的版本号了 我们下载这一列的就行
Explain: 看你系统是多少位的下载对应的即可 查看方式如下
如果你是ARM的处理器 也是要下载对应的即可
3.下载完成后,运行安装程序
⚠️安装小提示
- 勾选Add Python to PATH,这样可以在命令行直接使用
python命令。- 默认选项通常已经适合大部分用户,无需修改其他设置。
建议将这个目录改成了
2. 验证安装是否成功
安装完成后,打开命令行(Windows 下是 CMD(快捷方式Win+R)或 PowerShell,macOS/Linux 下是 Terminal),输入:python --version
如果出现类似Python 3.x.x的版本信息,就表示安装成功了 我的版本比较老了3.11.9
插一嘴 这个cmd的样式可以DIY 这里我提供一下方法如果大家想设置的话:
Cmd样式设置:
鼠标放到上面的白色选项栏中鼠标右击 然后点击设置
之后来到这个界面 左侧往下滑 点击命令提示符
这里可以设置背景图片的路径 以及透明度 我个人觉得百分之50就挺好
二、Python 第一个程序
安装完成后,我们可以尝试编写人生中的第一个 Python 程序:Hello, World!
- 打开刚刚的cmd窗口
- 输入python
- 输入以下代码:print("Hello, World!")
- 回车
恭喜你!你已经成功编写并运行了第一个 Python 程序
三、下载编辑器
我们需要一个方便 高效率的集成代码环境(IDE) 常见的有 Pycharm Vscode
通常有以下的功能:
- 代码编辑器:可以自定义代码编辑器
- 自动补全/语法高亮:提升编程体验
- 项目管理工具:组织文件,管理工程结构
- 调试器:更快的找出代码中的错误
打开jetbrains的官网 直接点击下面的连接即可https://www.jetbrains.com/pycharm/download/?section=windowshttps://www.jetbrains.com/pycharm/download/?section=windows
现在的不叫专业版了 叫完整版 和社区版 区别就是 之前你如果下了专业版 到了30天试用之后 连Pycharm都打不开 现在就不会有这个问题 直接下载这个即可(电脑是ARM架构的选下面那个)
当然也可以试用工具破解 这里就不演示了 大家可以去网上搜 或者私信我 我也可以帮助你
学习前期是不需要使用到付费功能的
按照提示安装即可 和解释器一样 修改安装目录(目标目录最好是英文) 看个人习惯
一.字面量知识总结
- 字面量就是直接写在代码里面中的具体值
- Python的字符串中可以包含任意字符 且必须使用引号包起来
- 字符串的引号 可以是单引号 双引号 三个单引号
- 写在Python文件头部的字符串,会被自动识别成docstring(文档字符串)
- 文档字符串的主要作用是:对当前Python文件进行一些说明 且文档字符串必须使用三个双引号
- 调整了Pycharm的设置:检查代码 Ai智能提示
二.标识符的命名规则
- 只能包含:数字字母下划线且不能以数字开头 不能包含空格
- 标识符区分大小写 例如:Name和name是两个不同的标识符
- 标识符不能使用关键字 例如:class pass
- 标识符尽量不要与内置函数同名
- 标识符虽然没有长度限制,但应追求:简洁清晰,具有描述性
- Python官方建议采用蛇形命名法(user_name) 除此之外还有小驼峰(userName) 大驼峰(UserName)命名法
三.常量
- 常量就是一旦被赋值就不希望改变的量(区别于变量)
- Python中一般约定使用全大写变量名来表示常量,涉及到多个单词时,用下划线做分割
- Python中没有强制的常量机制,Python中所谓的常量,其本质其实还是变量,只不过我们约定好不去修改,不像别的强语言类型(比如Java c)
四.注释
- 注释就是对代码的备注和解释,在代码执行时,通常不起任何作用
- 注释分为三类:单行注释:# 后的一行内容,会被视为注释;
多行注释:使用三个单引号,或三个双引号的方式编写(Python中其实没有真正的多行注释语法,上述方式编写的多行注释 本质是 一个字符串的字面量) - 文件编码注释:写在Python文件开头,用于指定当前文件的字符编码(Python3默认使用的是Utf-8编码(也叫万国码) 所以不需要再每个py文件开头写#coding=utf-8)
- 注释分为三类:单行注释:# 后的一行内容,会被视为注释;
数据类型:在Python中变量没有类型,数据有类型
整型就是没有小数点的数字,可以是正数 负数 也可以是0
当数很大时,我们可以使用下划线将数字进行分组,让数字变得更易读(例如:2_000_000)
Python中整数的上限值,取决于执行代码的计算机的内存和处理能力
浮点型就是带有小数点的数字
浮点型的科学计数法表示: 3.14e+3/3.14E+3(3.14*10的3次方) 3.14e9/3.14E9(3.14*10的9次方)
3.14e-2/3.14E-2(3.14*10的-2次方)
五.字符串
单引号和双引号的写法是等价的,二者都不能直接换行(要用圆括号才能换行)
三个单引号的写法,可以直接换行,并且可以作为多行注释使用 三个双引号还可以作为文档字符串使用
格式化输出: +号拼接 %s占位符 f-string(Python最推荐的形式)
Unicode编码 查看字符对应的编码ord() 将字符转换成编码chr() 字符串比较的是Unicode编码
布尔类型是Int类型的子类型 底层的本质是用1表示True 用0表示False
And返回的值不一定是布尔值 它返回的是某个参与计算的值本身
and 会先看左边 如果左边是假 就直接返回左边,否则返回右边 若参与and运算的值不是布尔值 那python会自动转换为布尔值,然后再进行逻辑操作
Or 会先看左边 如果左边为真 就直接返回左边 否则返回右边
Not取反 返回的值 一定是布尔值
六.循环
主要区别就是是否知道循环的次数
七.函数
关键字参数:使用函数时,通过形参名=值的形式传递实参
注意:使用关键字参数时,位置参数必须在关键字参数之前
函数限制传参的方式:
具体规则:/ 前面只能用位置参数,* 后面只能用关键字参数 两个同时使用时, / 必须在 * 前面
函数参数的默认值
参数默认值:定义函数时,通过形参名=值的形式,为参数指定一个默认值
默认参数必须放在必选参数的后面,或者说,某个形参,一旦设置了默认值,拿它后面的所有形参,也必须要写默认值!
For example: Print函数底层 设置了end默认值='\n'
函数可变参数
1.可变位置参数 定义函数时,在形参的名前加 * ,可以接收任意数量的位置参数,并打包成一个元组
2.可变关键字参数定义函数时,在形参的名前加 ** ,可以接收任意数量的关键字参数,并打包成一个字典
如果要一起使用的话 可变位置参数得在可变关键字参数之前
特殊的字面量---None
- None是一个特殊的字面量,它表示:空值/无意义/无值
- None的类型是NoneType.
- None转换为布尔值是False.
- None不能参与数学运算,也不能与字符串拼接
- 不给函数设置返回值,函数会默认返回None.
局部作用域和局部变量,会在函数调用时创建,在函数执行后销毁
全局作用域和全局变量,会在程序开始时创建,在程序结束后销毁
函数递归调用 指的是自己调用自己的一种操作
数据容器
数据容器: 一种能存放多个数据的数据类型
数据容器可以更高效地管理成批的数据,且便于存储,访问
容器中的每一个数据 称为每一个元素
Python中有很多种数据容器
不同的数据容器,有不同的特点,不同的语法,共性就是可以存储多个元素
列表
集合
面向对象基础
什么是面向对象? 编程思想,封装(就是将某些功能聚合起来 方便后续的调用 比如函数)继承(子承父业 子类继承父类的属性和方法)多态(同一个事物有着不同的形态)
面向对象的基本概念? 类和对象概念,类和对象编程语法,self使用
添加和获取对象属性? 属性概念,类外部,类内部获取属性
魔法方法?概念,__init__,__str__,__del__
面向对象和面向过程
- 编程思想
- 就是人们利用计算机来解决问题的思维
- 分类
- 面向过程
- 它是一种编程思想,强调的是以步骤(过程)为基础完成各种操作
- 面向对象
- 它是一种思想,强调的是以对象为基础完成各种操作,它是基于面向过程的
说到面向对象 不得不提的就是它的三大思想特点 :
- 更符合人们的思考习惯
- 把复杂的事情简单化
- 把人们(程序员)从执行者变成指挥者
- 它是一种思想,强调的是以对象为基础完成各种操作,它是基于面向过程的
- 面向过程
举例: 越符合当时的场景越好,例如:买电脑,洗衣服
总结:万物皆对象
面向对象的三大属性
- 封装
封装就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别,将抽象得到的数据和行为相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成"类",其中数据和函数都是类的成员
封装的目的是简化编程,增强安全性 使用者不必了解具体的实现细节,而只是要通过外部接口
以特定的访问权限来使用类的成员
- 多态 同一个函数接收不同的对象 有不同的效果
Self关键字:
在类外访问类的行为(函数) 需要通过对象名.的方式进行访问
在类内访问类的行为 需要通过 self.进行访问
Python 在类外可以给对象设置属性 对象.属性名=...
Python中类内访问成员 可以通过self. 的方式
魔法方法
特点:Python内置的函数 在特定的场景下会被自动调用
常用的魔法方法:
__init__在(每次)创建对象的时候,会自动触发该类的__init__() 函数,
__str__当使用print()函数时 ,会自动调用该对象所在类的str魔法方法 该魔法方法默认打印的是对象的地址值 无意义 一般会重写 改为打印 对象的各个属性,
__del__当.py文件执行结束 或者手动del释放对象资源,会自动调用该函数
定义类的三种语法:
class 类名: / class 类名(): / class 类名(object):
object是所有类的父类
继承的优点:提高代码的复用性弊端:耦合性变强了,父类不好的内容 子类想没有都不行
开发规则:高内聚(指的是类自己独立处理问题的能力) 低耦合(指的是类与类之间的关系)
MRO机制:Python中有MRO机制,可以查看某个对象,在调用函数时的顺序
类名.mro() or 类名.__mro__
多继承时,不同类中有相同的属性和方法时 按照从左往右,就近原则继承
子类重写父类同名方法和属性:
重写也叫作覆盖,就是当子类属性或方法与父类的属性或方法名字相同时,从父类继承下来的成员可以重新定义!
子类重写父类的属性和方法,优先会调用子类的属性和方法
子类访问父类成员
method_1:父类名.父类函数名(self) ---- 精准访问
method_2:super().父类函数名(self) ---- 只能访问最近的那个类,有就用 没有就报错(旧版本) 继续找下一个(新版) 推荐单继承使用
私有属性和私有方法:
在 Python 中,可以为属性和方法设置私有权限,即设置某个属性或方法不继承给子类。
设置私有属性和方法的方式:在属性或方法名前面加上__(双下划线),格式:
好处:提高了代码的安全性 以及复用性坏处:代码量增加了
多态入门:
- 要有继承
- 要有方法的重写 不然多态毫无意义
- 要有父类引用子类对象
抽象类解释:
在Python中 抽象类=接口 有抽象方法的类就是 抽象类 也叫接口
抽象方法 = 没有方法体的方法, 即:方法体是pass修饰的
作用: 抽象类一般充当父类,用于指定行业规范,准则 具体的交由子类来完成
对象属性和类属性:
它是一个名字 用来描述事物的外在特征的.
对象属性:属于每个对象的,即: 每个对象的属性值可能不同 修改A对象的属性 不影响对象B
定义到__init__魔法方法中的属性 只能通过对象名.的方式调用
类属性: 属于类的,即: 能被该类下所有的对象所共享. 要想改变类属性的值 必须通过 类名.的形式
类方法和静态方法:
类方法: 属于类的方法,可以通过类名. 还可以通过 对象名. 的方式来调用
定义类方法的时候,必须使用装饰器@classmethod 且第一个参数必须表示 类对象.
静态方法:属于类下所有对象所共享的方法,可以通过类名. 还可以通过 对象名. 的方式类调用
定义静态方法的时候,必须使用装饰器@staticmethod,且参数可传 可不传
区别: 如果函数中要用 类对象 就定义成类方法, 反之即可
闭包装饰器与深浅拷贝:
闭包就是 函数嵌套时,内层函数调用了外部函数的变量,且外层函数把内参函数返回,形成的带记忆功能的函数
nonlocal:是Python内置的关键字,可以实现在内部函数中 修改外部函数的变量值
闭包的条件: 有嵌套 有引用 有返回
闭包的核心作用:
- 延长变量生命周期
- 封装数据,实现"私有变量"效果
- 实现轻量级的"状态保持"
装饰器的作用:
不改变原有函数的基础上,给原有函数增加额外功能 其本质就是一个闭包函数
写法:1. 传统写法: 装饰后的函数名 = 装饰器名(被装饰的原函数) 装饰后的函数名()
2. 语法糖(最常见也最实用). 在要被装饰的原函数上。直接写@装饰器名,之后直接调用原函数即可
装饰器的内部函数格式 要和被装饰器的原函数保持一致
多个装饰器装饰一个原函数 是按照 由内向外的顺序来装饰的 用装饰器来做的话 看到的效果是从上到下执行的
装饰器的参数只能有一个 要传入多个参数的话 在该装饰器的外边再包裹一层,把该装饰器当作其内部函数返回即可
深浅拷贝:
浅拷贝就是copy模块的copy()函数 深拷贝就是copy模块中的deepcopy()
深拷贝主要是针对可变参数类型来讲的,深拷贝拷贝所有层 浅拷贝只拷贝第一层
网络编程介绍
概述:
就是用来实现网络互联的 不同计算机上运行的程序间 可以进行数据交互
三要素
IP地址:设备(电脑 手机 Ipad)在网络中唯一的标识
分类:
IPV4, 4字节 十进制 例如:192.168.88.100
IPV6 16字节 十六进制 宣传语: 可以让地球上的每一粒沙子都有自己的IP
两个DOS命令:
查看IP:
windows: ipconfig
Linux: ifconfig
测试网络连接:
ping ip地址 或 域名
端口号:程序在设备上的唯一标识
范围 0-65535,其中0-1023已经被系统占用或者用作保留端口,自定义端口时尽量规避这个范围
协议: 传输规范 规则
常用的协议:
TCP(常用) UDP
TCP特点:
1.面向有线连接
2.采用字节流传输数据 理论无大小限制
3.安全(可靠)协议
4.效率相对较低
5.区分客户端和服务端
网络编程介绍
概述: 网络编程也叫网络通信 Socket通信,即:通信双方都独有自己的Socket对象 数据在Socket之间通过数据报包(UDP协议) 或者字节流(TCP协议)的形式进行传输
For example:你和你遥远的朋友在聊天 表面是你们两个人在交互 其实是通过 两部手机(双方各自的手机)来交互的
代码写法(入门创建Socket对象)
# 导包 import socket # 创建Socket对象 # 参1: Address Family, 地址族, 即: Ipv4 还是 IpV6, 默认值: AF_INET(ipv4) AF_INET6(ipv6) # 参2: Socket Type, Socket类型, 即: TCP 还是 UDP, 默认值: SOCK_STREAM(TCP) SOCK_DGRAM(UDP) socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
服务器端写法
import socket socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 绑定地址和端口 socket_obj.bind(('127.0.0.1', 8080)) # 开始监听,参数5表示最大连接数 socket_obj.listen(5) # 接受客户端连接,返回一个新的socket对象和客户端地址信息 accept_socket, client_info = socket_obj.accept() # 向客户端发送欢迎信息 accept_socket.send(b'Welcome to Socket') # 接收客户端发送的数据,1024为缓冲区大小(字节) data = accept_socket.recv(1024) # 打印接收到的数据 print(data) # 关闭与客户端的连接 accept_socket.close() # 设置端口号重用 目的是:快速重启服务器(服务器关闭后,立即释放端口) 一般不需要设置这个 # 参1: Socket Level, Socket级别, 即: SOL_SOCKET # 参2: Option Name, 选项名称, 即: SO_REUSEADDR # 参3: Option Value, 选项值, 即: True/False socket_obj.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)客户端写法
import socket socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 客户端连接服务器 socket_obj.connect(('127.0.0.1', 8080)) # 接收服务器发送的数据并解码为UTF-8字符串 data = socket_obj.recv(1024).decode('utf-8') print(data) # 向服务器发送消息 socket_obj.send('The world is your oyster!'.encode('utf-8')) # 关闭连接 socket_obj.close()编解码
编码类似加密 解码类似解密
只要乱码了 就是解码和编码不一样
英文字母,数字,特殊字符无论什么码都占一个字节,中文在gbk中占2个字节,utf-8中占3个字节
二进制数据特殊写法 即:b'字母 数字 特殊符号', 该方式对中文无效
多线程
多任务的概念
概念: 指的是在同一时间内执行多个任务目的是:充分利用CPU资源 提高程序的执行效率
例如: 现在电脑安装的操作系统都是多任务操作系统 可以同时允许着多个软件
多任务的两种表现形式
并发:在一段时间内交替执行任务
并行:在一段时间内 真正的同时一起执行多个任务
进程的概念
进程就是CPU资源分配的最小单位它是操作系统进行资源分配和调度运行的基本单位
通俗理解: 一个正在运行的程序就是一个进程. 例如:正在运行的QQ,微信等他们都是一个进程
使用多线程完成多任务的步骤
# 导包 import multiprocessing # 创建子进程并指定执行的任务 sub_process = multiprocessing.Process(target=任务名) # 启动进程执行任务 if __name__ == '__main__': sub_process.start()
进程传参的两种方式
元组方式传参 元组方式传参一定要和任务函数的参数顺序保持一致
字典方式传参 字典方式传参字典中的key一定要和任务函数的参数保持一致
获取进程的编号
概述
在设备中, 每个程序(进程)都有自己的唯一进程id,当程序释放的时候,该进程id也会释放,即:进程id是可以重复使用的
目的
查看子进程和父进程的关系,方便管理
例如:杀死指定进程, 创建子进程
格式
# 查看当前进程的pid: os模块的getpid() multiprocessing#current_process()的pid属性 # 查看当前进程的ppid: os#getppid()
main中创建的进程,如果没有特殊规定,它的父进程都是main进程,而main进程的父进程都是Pycharm程序的pid
进程之间不会共享全局变量因为子进程相当于是父进程的"副本",会将父进程的"main外资源"拷贝一份
主进程会等待所有的子进程执行结束再结束
如果要设置主进程结束,子进程同步结束,方式如下:
设置子进程 为守护进程 .daemon()=True
强制关闭子进程 可能会导致子进程变成僵尸进程 .terminate()
线程
线程概念
线程就是CPU调度的基本单位 每个进程至少都有一个线程,而这个线程就是我们通常说的主线程
多线程的特点
线程执行具有随机性,原因是因为CPU在做着高效的切换
默认情况下 ,主线程会等待子线程结束再结束
(同一个进程的)线程间 数据共享
多线程操作共享数据 可能会出现安全问题 可以用互斥锁解决
互斥锁
对共享数据进行锁定 保证同一时刻只有一个线程去操作
注意:互斥锁是多个线程一起去抢 抢到锁的线程先执行 没有抢到锁的线程进行等待 等锁用完释放后 其它的等待的线程再去抢这个锁 未在合适的时候释放锁会出现死锁
# 导包 import threading # 互斥锁的创建 mutex = threading.Lock() # 上锁 mutex.acquire() # 释放锁 mutex.release()
进程和线程的区别
| 对比维度 | 进程 | 线程 |
|---|---|---|
| 基础定义与核心角色 | 操作系统资源分配的基本单位,可独立存在 | CPU调度执行的基本单位,必须依附在进程中,无进程则无线程 |
| 数量对应关系 | 一个程序可对应多个进程 | 一个进程默认提供 1 条线程,可创建多个线程 |
| 全局变量共享规则 | 进程之间不共享全局变量 | 线程之间共享全局变量,存在资源竞争问题,可通过「互斥锁」解决 |
| 创建与运行资源开销 | 资源开销大 | 资源开销小 |
| 多核 CPU 利用能力 | 可正常使用多核 CPU | 无法使用多核 CPU(Python 环境下) |
| 执行独立性 | 可独立执行 | 不能独立执行,必须依存于进程中 |
| Python 开发稳定性 | 多进程开发稳定性更强 | 单进程多线程开发稳定性相对较弱 |
协程
概念
协程就是一种可以被挂起 并且在挂起后 还可以恢复执行的函数
协程又称微线程 是一种用户态内的上下文切换技术
注意: 协程不是操作系统提供的 而是由程序员在用户态 实现的一种切换机制
协程函数
使用async关键字修饰的函数
协程对象
调用协程函数 就会得到协程对象
import asyncio async def work(): print("work开始") print("work执行中") print("work结束") return '工作结果' # 调用协程函数 会得到协程对象 coroutine_object = work() result = asyncio.run(coroutine_object) # asyncio.run方法做了3件事情 # 1.创建一个事件循环 # 2.将收到的协程对象 包装成一个任务 交给事件循环 # 3.启动事件循环 # asyncio.run会阻塞当前线程 直到任务执行完毕 并返回该任务 return的最终结果await 关键字的核心作用
1 挂起
await会暂停当前协程的执行,交出控制权
2 等待
遇到await关键字时,事件循环会安排 await 后面的对象去执行,并等待其完成,同时可以拿到执行结果。
执行 await 对象时的两种情况
情况一:对象中包含 await I/O 操作
示例:网络请求、文件读写等需要等待外部资源的操作。
行为:CPU 控制权交给事件循环,事件循环会调度执行其他任务,实现任务切换。
情况二:对象中不包含 await I/O 操作
示例:print 打印、数学计算、逻辑计算等纯CPU操作。
行为:事件循环无法拿到 CPU 控制权,无法调度其他任务,不会发生任务切换。
3 恢复
当 await 后的对象执行完毕,事件循环会恢复之前被挂起的协程,协程会从挂起的位置继续执行,并拿到返回值。
重要注意点
await 后面只能写可等待对象,常见类型包括:
协程对象
Future 对象
Task 对象
使用协程下载多个图片
import asyncio import aiohttp async def down_load(session, url): print("正在下载:", url) # 发送请求 response = await session.get(url) content = await response.read() # 从URL中提取唯一文件名,使用URL中的唯一标识部分 # 例如: D587_D042_0408GT_001.R3D_02599866.jpg filename = url.split('material/')[-1].split('.R3D_')[0] + '.jpg' print(filename) with open(filename, 'wb') as f: f.write(content) await response.release() print("下载完成:", filename) async def main(): url_list = [ 'https://public.ysjf.com/mediastorm/material/material/D587_D042_0408GT_001.R3D_02599866.jpg?x-oss-process=image/resize,w_500', 'https://public.ysjf.com/mediastorm/material/material/A020_A009_04097I_001.R3D_00229245.jpg?x-oss-process=image/resize,w_500', 'https://public.ysjf.com/mediastorm/material/material/D580_D015_0109Y5_001.R3D_00433725.jpg?x-oss-process=image/resize,w_500' ] # 创建会话对象(发请求的工具) async with aiohttp.ClientSession() as session: # 创建多个协程对象 coroutine_list = [down_load(session, url) for url in url_list] # 将多个协程对象交给事件循环 await asyncio.gather(*coroutine_list) asyncio.run(main())