上一篇我们搭好了 Python 环境、写出了第一个程序,今天就进入核心环节 ——Python 基础知识!这些内容看似简单,却是处理大模型参数、清洗训练数据、编写模型逻辑的 “基本功”,比如大模型的学习率、训练轮数、损失值,都需要用变量和数据类型来存储,运算符则能帮我们计算模型准确率、判断训练是否达标,一定要吃透~
第 3 章 基础知识
3.1注释
3.1.1什么是注释
注释是对代码的解释说明。
注释是给程序员看的,在代码执行的时候不起任何作用,不影响程序的结构。
3.1.2注释的作用
Ø提高代码的可读性。
Ø屏蔽掉暂时不需要的代码
Ø可以定位程序中出错的位置
3.1.3单行注释(行注释)
Python中 # 后的一行内的内容会被视为注释
# print("hello world")
print("hello world") # 打印hello world
为了保持注释的整洁,Python官方建议在#和注释的内容之间加一个空格,在语句和#之间加两个空格。
3.1.4多行注释(块注释)
Python中使用三个引号开始,三个引号结束(单引号或者双引号都可以),为多行注释
多行注释在说明文字需要换行时使用,不能嵌套
"""
Hello World
hello world
"""
但实际上它是一个多行字符串
print(
"""
Hello World
hello world
"""
)
3.2变量
3.2.1什么是变量
变量是指在程序执行过程中,其值可以改变的量。在内存的数据区中,会为变量分配存储空间来存放变量的值,这个内存空间的地址对应着变量名称,所以在程序中可以通过变量名称来区分和使用这些内存空间。它的唯一目的是在内存中标记和存储数据,这些数据可以在整个程序中使用。
可以将变量理解为一个可以赋给值的标签,也可以说变量指向特定的值。
3.2.2变量的创建
变量创建方式:变量名 = 变量值
Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。
等号(=)用来给变量赋值。
等号(=)运算符左边是一个变量名,等号(=)运算符右边是存储在变量中的值。
var1=2# 定义一个变量,变量名为var1,变量值为2
var2=3# 定义一个变量,变量名为var2,变量值为3
result=var1+var2# 定义一个变量,变量名为result,变量值为var1和var2相加的结果
print(result) # 打印result变量的值
name="张三"
age=18
weight=1000.3
多个变量的创建:
var1=var2=var3=10# 多个变量的值相同
var4, var5, var6=10, 20, 30# 多个变量的值不同
3.2.3标识符命名规则
1)标识符
程序中可以自己命名的地方
2)命名规则
Ø只能包含字母、数字和下划线,且不能以数字开头。
Ø区分大小写,即Name和name是两个不同的标识符。
Ø不要和关键字重复。
Ø应既简短又具有描述性。
Ø注意:Python源文件不遵循命名规范不影响程序的执行,但不建议
3)关键字
Python 有一组关键字,这些关键字不能用作变量名、函数名或任何其他标识符。

Python 的标准库提供了一个 keyword 模块,可以输出当前版本的所有关键字:

4)标识符命名方法
常见的命名方法有三种:
Ø大驼峰命名法(upper camel case):每个单词首字母大写,例如UpperCamelCase。
Ø小驼峰命名法(lower camel case):第一个单词首字母小写, 之后每个单词首字母大写,例如lowerCamelCase。
Ø蛇形命名法(snake case):单词间用下划线连接,例如snake_case。
3.2.4变量的修改
在程序中可随时修改变量的值,而Python将始终记录变量的最新值。
message="hello world"
print(message)
message="hello world hello world"
print(message)
Python还支持方便的对变量相互替换
var1=2
var2=20
print(var1, var2) # 2 20
var1, var2=var2, var1
print(var1, var2) # 20 2
3.2.5常量
在程序中定义后就不再修改的值为常量,Python中没有内置的常量类型。一般约定使用全大写变量名来表示常量。
PI=3.1415926
E=2.718282
3.3进制以及源码、反码和补码
3.3.1进制
计算机世界中只有二进制,所以计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。常见的进制
(1)二进制:0、1,满2进1。
(2)八进制:0-7,满8进1。
(3)十进制:0-9,满10进1。
(4)十六进制:0 - 9及A-F,满16进1。十六进制中,除了 0 到 9 十个数字外,还引入了字母,以便表示超过9的值。字母A对应十进制的10,字母B对应十进制的11,字母 C、D、E、F 分别对应十进制的 12、13、14、15。
二进制 | 八进制 | 十进制 | 十六进制 |
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
10 | 2 | 2 | 2 |
11 | 3 | 3 | 3 |
100 | 4 | 4 | 4 |
101 | 5 | 5 | 5 |
110 | 6 | 6 | 6 |
111 | 7 | 7 | 7 |
1000 | 10 | 8 | 8 |
1001 | 11 | 9 | 9 |
1010 | 12 | 10 | A |
1011 | 13 | 11 | B |
1100 | 14 | 12 | C |
1101 | 15 | 13 | D |
1110 | 16 | 14 | E |
1111 | 17 | 15 | F |
10000 | 20 | 16 | 10 |
10001 | 21 | 17 | 11 |
3.3.2不同进制表示整数
(1)二进制:以0b或0B开头表示。
(2)八进制:以0o开头表示
(3)十进制:正常数字表示。
(4)十六进制:以0x或0X开头表示,此处的A-F不区分大小写。
# 十进制
dec=10
# 二进制 以0b开头
binary_number=0b1010
# 八进制 以0o开头
octal_number=0o12
# 十六进制 以0x开头
hex_number=0xA
print(dec)
print(binary_number)
print(octal_number)
print(hex_number)
print("~~~~~~~~~~~~~~~~")
print("十进制数为:", dec)
print("转换为二进制为:", bin(dec))
print("转换为八进制为:", oct(dec))
print("转换为十六进制为:", hex(dec))
输出:
10
10
10
10
~~~~~~~~~~~~~~~~
十进制数为: 10
转换为二进制为: 0b1010
转换为八进制为: 0o12
转换为十六进制为: 0xa
3.3.3二进制转换成十进制
(1)规则:从最低位开始,将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和。
(2)案例:请将二进制 1011 转成十进制的数。

3.3.4十进制转换成二进制
(1)规则:将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对应的二进制。
(2)案例:请将 56 转成二进制。

3.3.5十六进制转换成十进制
(1)规则:从最低位开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和。
(2)案例:请将0x34A转成十进制的数。

如果是8进制转换为10进制,就乘以8的(位数-1)次方,然后求和
3.3.6十进制转换成十六进制
(1)规则:将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对应的十六进制。
(2)案例:请将356转成十六进制。

如果将十进制转换为八进制,将该数不断除以8,直到商为0为止,然后将每步得到的余数倒过来。
3.3.7二进制转换成十六进制
(1)规则:低位开始,将二进制数每四位一组,转成对应的十六进制数即可。
因为2的4次方等于16 ,所以将二进制数从右向左每 4 位分成一组。如果二进制数的位数不是 4 的倍数,则在最左边补零,使其成为 4 的倍数
(2)案例:请将1001011转成十六进制。

如果二进制转换为八进制,3位分一组
3.3.8十六进制转换成二进制
(1)规则:将十六进制数每1位,转成对应的4位的一个二进制数即可。
(2)案例:请将0x23B转成二进制。

如果八进制转换为二进制,1位八进制转成3位二进制数
3.3.9原码、反码、补码
计算机底层存储数据时使用的是二进制数字,但是计算机在存储一个数字时并不是直接存储该数字对应的二进制数字,而是存储该数字对应二进制数字的补码。先了解概念
1)机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为机器数。机器数可以是有符号的,用机器数的最高位存放符号位,0表示正数,1表示负数。
2)真值
因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值),以机器数10000001为例,其真正表示的值(首位为符号位)为-1,而形式值(首位就是代表1)为129;因此将带符号的机器数的真正表示的值称为机器数的真值。
3)原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。
Ø正数的原码:就是它对应的二进制数。
Ø负数的原码:它的绝对值对应的二进制数,且最左边位变为1。
Ø0的原码:仍然是0。
十进制的正负1,用8位二进制的原码表示如下:
+1 原码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ]
4)反码
Ø正数的反码:和原码相同。
Ø负数的反码:在其原码的基础上,符号位不变,其余各位取反。
Ø0的反码:仍然是0。
十进制的正负1,用8位二进制的反码表示如下:
+1 原码:[ 0000 0001 ]反码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ]反码:[ 1111 1110 ]
需要注意的是,反码通常是用来由原码求补码或者由补码求原码的过渡码。
5)补码
Ø正数的补码:和原码、反码相同。
Ø负数的补码:反码的基础上加1。
Ø0的补码:仍然是0。
十进制的正负1,用8位二进制的补码表示如下:
+1 原码:[ 0000 0001 ]反码:[ 0000 0001 ]补码:[ 0000 0001 ]
-1 原码:[ 1000 0001 ]反码:[ 1111 1110 ]补码:[ 1111 1111 ]
6)总结
(1)正数的原码、反码、补码都一样,三码合一。
(2)负数的反码:它的原码符号位不变,其它位取反(0 -> 1,1 -> 0);负数的补码:它的反码+1。
(3)0的反码,补码都是0。
3.3.10计算机为什么用补码

3.3.11计算案例
需求:计算10 – 12,使用补码描述计算机内部的计算过程。

3.4基本数据类型
在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对象的类型。Python 3中常见的数据类型分类如下,主要类型有六种:
Ø基本数据类型
数值
整数(int)、浮点数(float)、复数(complex)、布尔(bool)
Ø字符串(str)
Ø容器数据类型
列表(list)
元组(tuple)
集合(set)
字典(dist)
Ø特殊数据类型
None
表示空值或缺失值,只有一个值 None。常用于函数没有返回值时,或者表示变量没有被赋值。

上图的int、float、complex、bool都属于Number(数字)数据类型。
Ø不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组)。
Ø可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。
3.4.1int整型
Python可以处理任意大小的整数,包括负整数。
1)整数分隔符
书写很大的数时,可使用下划线将其中的数字分组,使其更清晰易读。
num1=1_000_000_000_000_000
print(num1) # 1000000000000000
存储这种数时,Python会忽略其中的下划线。在Python看来,1_000_000_000_000_000 与1000000000000000 没什么不同。这种表示法适用于整数和浮点数,但只有Python 3.6及以上版本支持。
2)type 与 isinstance 类型判断
可以使用 type() 来查看变量类型,使用 isinstance() 来判断变量类型。
type() 和 isinstance() 的区别在于 type() 不会认为子类是一种父类类型,isinstance() 会认为子类是一种父类类型。
num1=True
num2=10
print(type(num1)) #
print(type(num2)) #
print(type(num1) ==type(num2)) # False
print(isinstance(num1, bool)) # True
print(isinstance(num1, int)) # True,Python3中,bool是int的子类
print(isinstance(num2, int)) # True
3)小整数池
Python将 [-5, 256] 的整数维护在小整数对象池中。这些整数提前创建好且不会被垃圾回收,避免了为整数频繁申请和销毁内存空间。不管在程序的什么位置,使用的位于这个范围内的整数都是同一个对象。
4)大整数池
一开始大整数池为空,每创建一个大整数就会向池中存储一个。
注意事项
Ø不同的 Python 实现:小整数池的范围和实现细节可能因 Python 的不同实现(如 CPython、Jython、IronPython 等)而有所不同。上述提到的[-5, 256]范围是 CPython 的默认实现。
Ø有时连续赋值的相同大整数也可能指向同一对象,这是因为Python环境的优化机制,但是这个优化不是绝对的,也取决于解释器以及交互式以及脚本环境。
3.4.2float浮点型
Python将所有带小数点的数称为浮点数。要注意在使用浮点数进行计算时可能会存在微小误差,可以通过导入decimal解决
num1=0.1
num2=0.2
print(num1+num2) # 0.30000000000000004
fromdecimalimportDecimal
num3=Decimal('1.0')
num4=Decimal('0.9')
print(num3-num4)
也可以使用科学计数法表示浮点数。
num1=1.3e7
print(num1) # 13000000.0
3.4.3bool布尔型
布尔型变量只有 True 和 False,用于真假的判断。
bool1=True
bool2=False
print(bool1, bool2) # True False
Python3中,bool 是 int 的子类,True 和 False 可以和数字相加。
True==1、False==0 会返回 True
is 运算符用于比较两个对象的身份(即它们是否是同一个对象,是否在内存中占据相同的位置),而不是比较它们的值。
print(True==1) # True
print(False==0) # True
print(Trueis1) # False
print(Falseis0) # False
在Python中,能够解释为假的值不只有False,还有:
ØNone
Ø0
Ø0.0
ØFalse
Ø所有的空容器(空列表、空元组、空字典、空集合、空字符串)
3.4.4String字符串初识
字符串就是一系列字符。在Python中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号。可使用反斜杠 \ 转义特殊字符。
str1='This is a "string"'
str2="This is a 'string' too"
print(str1) # This is a "string"
print(str2) # This is a 'string' too
也可以方便的在字符串中包含单引号或双引号。
str1="This is a 'string'"
str2='This is a "string" too'
print(str1) # This is a 'string'
print(str2) # This is a "string" too
也可以使用三个引号表示多行字符串。三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。让程序员从引号和特殊字符串的泥潭里面解脱出来,自始至终保持一小块字符串的格式是所谓的WYSIWYG(所见即所得)格式的。
一个典型的用例是,当你需要一块HTML或者SQL时,使用三个引号就很简单
str1="""hello world
HELLO WORLD"""
print(str1)
在字符中使用特殊字符时,Python用反斜杠 \ 转义字符:
转义字符 | 说明 |
\ | 在行尾作为续行符 |
\\ | 反斜杠符号 |
\' | 单引号 |
\" | 双引号 |
\b | 退格 |
\n | 换行 |
\t | 横向制表符 |
\r | 回车,回到行首 |
1)intern机制
每个(字符串),不夹杂空格或者特殊符号,默认开启intern机制,共享内存,靠引用计数决定是否销毁。相同的字符串默认只保留一份,当创建一个字符串,它会先检查内存里有没有这个字符串,如果有就不再创建新的了。
2)字符串缓冲池
单个字母,长度为1的 ASCII 字符会被 interned,包括空字符。
3.4.5数据类型转换
1)自动类型转换(隐式转换)
对两种不同类型的数据进行运算,较小的数据类型(整数)就会转换为较大的数据类型(浮点数)以避免数据丢失,计算结果为浮点型:
num1=2
num2=3.0
print(num1+num2) # 5.0
特别的,两个整型进行除法运算结果也是浮点型:
num1=9
num2=1
print(num1/num2) # 9.0
而整型和字符串相加会报错,此时Python无法进行隐式转换完成计算:
num1=123
str1="456"
print(num1+str1) # 报错
2)强制类型转换(显式转换)
可以通过函数对数据类型进行转换。
函数 | 说明 |
int(x [,base]) | 将x转换为一个整数,x若为字符串可用base指定进制 |
float(x) | 将x转换为一个浮点数 |
complex(real[,imag]) | 创建一个实部为real,虚部为imag的复数 |
str(x) | 将对象x转换为一个字符串 |
repr(x) | 将对象x转换为一个字符串,可以转义字符串中的特殊字符 |
eval(x) | 执行x字符串表达式,并返回表达式的值 |
bin(x) | 将一个整数转换为一个二进制字符串 |
oct(x) | 将一个整数转换为一个八进制字符串 |
hex(x) | 将一个整数转换为一个十六进制字符串 |
ord(x) | 将一个字符转换为它的ASCII整数值 |
chr(x) | 将一个整数转换为一个Unicode字符 |
tuple(s) | 将序列s转换为一个元组 |
list(s) | 将序列s转换为一个列表 |
set(s) | 转换s为可变集合 |
num_int=123
num_str="456"
print("num_int 数据类型为:",type(num_int))
print("类型转换前,num_str 数据类型为:",type(num_str))
num_str=int(num_str) # 强制转换为整型
print("类型转换后,num_str 数据类型为:",type(num_str))
num_sum=num_int+num_str
print("num_int 与 num_str 相加结果为:",num_sum)
print("sum 数据类型为:",type(num_sum))
输出:
num_int 数据类型为:
类型转换前,num_str 数据类型为:
类型转换后,num_str 数据类型为:
num_int 与 num_str 相加结果为: 579
sum 数据类型为:
3.4.6字符的编码和解码
# 创建一个 字符串类型数据
str1='你好中国'
print(str1)
print(type(str1))
# 将字符串数据类型转换为字节型数据的过程成为编码 encode,需要指定编码类型
byte1=str1.encode(encoding='utf8')
# 4个字符转换为了12个字节, 所以一个汉字占用3个字节
print(byte1) # b'\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\xad\xe5\x9b\xbd'
print(type(byte1)) #
# 在进行编码集使用时,一定要注意,使用什么编码集编码,就要使用它解码,否则报错.
# 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byt
# byte2 = str1.encode(encoding='gbk')
# print(byte2)
# print(type(byte2))
# 将字节型数据转换为字符型数据的过程称为解码 decode
str2=byte1.decode(encoding='utf8')
print(str2) # 你好中国
print(type(str2)) #
3.5输入与输出
3.5.1输入
如果接收用户在键盘上输入一些字符,Python提供了一个input()函数,可以让用户输入字符串,并存放到一个字符串变量里。
语法:字符串变量 = input(“提示信息”)
# Python开始等待你的输入。这时,你可以输入任意字符,然后按回车后完成输入。
input_str=input("请输入:")
# 输入完成后,不会有任何提示,刚才输入的内容存放到input_str变量里了
print("input_str数据类型为:",type(input_str))
# 输出input_str查看变量内容
print(input_str)
3.5.2输出
1)普通输出
使用 print() 可将内容打印。
print("Hello Python")
多个内容之间可以使用逗号隔开。
print("Hello", " Python")
可以使用 end= 来控制 print() 以什么结尾。
print("使用\\n结尾", end="\n") # 用\n结尾,等同于print("使用\\n结尾")
print('使用""结尾', end="") # 用空字符串结尾
print("Hello")
2)格式化输出
(1)字符串中使用 % 占位
int1=10
float1=3.14159
str1="int1 = %d, float1 = %f"% (int1, float1)
print(str1) # int1 = 10, float1 = 3.141590
格式符号列表:
格式符号 | 说明 |
%d | 十进制整数 |
%f | 浮点数,%.nf可指定显示小数点后n位 |
%s | 字符串 |
%o | 八进制整数 |
%x | 十六进制整数 |
%e | 科学计数法 |
(2)字符串.format()
方式1:不设置指定位置,按默认顺序
int1=10
float1=3.14159
bool1=True
str2="int1 = {}, float1 = {}, bool1 = {}".format(int1, float1, bool1)
print(str2) # int1 = 10, float1 = 3.14159, bool1 = True
方式2:设置指定位置,不能和方式1混合使用
int1=10
float1=3.14159
bool1=True
str2="int1 = {0}, float1 = {1}, bool1 = {2}".format(int1, float1, bool1)
print(str2) # int1 = 10, float1 = 3.14159, bool1 = True
方式3:设置参数
int1=10
float1=3.14159
bool1=True
str2="int1 = {i1}, float1 = {f1}, bool1 = {b1}".format(i1=int1, f1=float1, b1=bool1)
print(str2) # int1 = 10, float1 = 3.14159, bool1 = True
(3)数字格式化:
float1=31415.9
str2="{:*^20,.2f}".format(float1)
print(str2) # *****31,415.90******
: 后可以添加多个参数对数字格式化:
Ø*:以 * 填充空白,不写则默认以空格填充。
Ø^:可选 < 、 ^ 、 > ,分别是左对齐、居中、右对齐。
Ø20:数字宽度为20,数字长度不足20则进行填充。
Ø,:可选 , 和 _ ,每3位进行分隔。
Ø.2f:小数点后保留2位。
案例:

(4)使用大括号 {} 来转义大括号
print ("{0} 对应的位置是 {0}".format("hello")) #hello 对应的位置是 hello
print ("{} 对应的位置是 {{0}}".format("hello")) #hello 对应的位置是 {0}
(5)f-字符串
字符串前加上一个 f ,字符串中的{}内写入变量名。
int1=10
float1=3.14159
str3=f"int1 = {int1}, float1 = {float1}"
print(str3) # int1 = 10, float1 = 3.14159
{}内变量名后可以加上 = ,打印时会在变量值前加上 变量名=。
int1=10
float1=3.14159
str3=f"{int1 = }, {float1 = }"
print(str3) # int1 = 10, float1 = 3.14159
{}外再套一层{},即{{}},会转义。
int1=10
float1=3.14159
str3=f"{{int1 = }}, {{float1 = }}"
print(str3) # {int1 = }, {float1 = }
3.6运算符
3.6.1算数运算符
运算符 | 说明 | 实例 |
+ | 加 | a + b |
- | 减、或取负 | a - b、-a |
* | 乘 | a * b |
/ | 除 | a / b |
// | 整除,除后向下取整 | a // b |
% | 模,返回除法的余数 | a % b |
** | 幂 | a ** b |
# -------------算术运算符---------------
a=20
b=10
c=a+b
print(a , "+" , b , "的结果为" , c)
c=a-b
print(a , "-" , b , "的结果为" , c)
c=a*b
print(a , "*" , b , "的结果为" , c)
c=a/b#注意:结果为浮点类型
print(a , "/" , b , "的结果为" , c)
c=a%b
print(a , "%" , b , "的结果为" , c)
a=2
b=3
c=a**b
print(a , "的" , b , "次方结果为" , c)
a=10
b=3
c=a//b
print(a , "//" , b , "的结果为" , c)
print("-" * 30) # 输出30次-
输出结果:
20 + 10 的结果为 30
20 - 10 的结果为 10
20 * 10 的结果为 200
20 / 10 的结果为 2.0
20 % 10 的结果为 0
2 的 3 次方结果为 8
10 // 3 的结果为 3
------------------------------
3.6.2赋值运算符
运算符 | 说明 | 实例 |
= | 赋值 | a = 1 |
+= | 加法赋值 | a += 2,等同于a = a + 2 |
-= | 减法赋值 | a -= 2,等同于a = a - 2 |
*= | 乘法赋值 | a *= 2,等同于a = a * 2 |
/= | 除法赋值 | a /= 2,等同于a = a / 2 |
//= | 整除赋值 | a //= 2,等同于a = a // 2 |
%= | 模赋值 | a %= 2,等同于a = a % 2 |
**= | 幂赋值 | a **= 2,等同于a = a ** 2 |
:= | 海象运算符,在表达式中同时进行赋值和返回赋值的值。Python3.8 版本新增 | num1=20 print((num2:=3**2) >num1) print(num2) |
# -------------赋值运算符---------------
num3=30
num4=40
num5=num3+num4
print(num5)
num3+=50# num3 = num3 + 50
print(num3)
输出结果:
70
80
3.6.3比较运算符
运算符 | 说明 | 实例 |
== | 相等,比较两者的值 | a == b |
!= | 不相等 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
注意:除了不同数据类型的数据不能比较大小
# -------------比较运算符---------------
num1=10
num2=20
print(num1==num2) # False
print(num1!=num2) # True
print(num1>num2) # Flase
print(num1<num2) # True
print(num1>=num2) # False
print(num1<=num2) # True
num3='abc'
# 注意:不同的数据类型之间不能进行大小的比较
print(num1>num3)
# 如果是字符串比较大小,是从最左边开始逐个比较字符串中相应位置的字符的ASCII码
print('5'>'6') # False
print('15'>'6') # False
3.6.4逻辑运算符
运算符 | 说明 |
and | 与,x and y,若x为False返回x的值,否则返回y的值 |
or | 或,x or y,若x为True返回x的值,否则返回y的值 |
not | 非,not x,若x为True返回False,若x为False返回True |
# -------------逻辑运算符---------------
b1=False
b2=True
print(b1andb2) # False
print(b1orb2) # True
print(not(b1)) # True
print(5and8) # 8 非0表示True,0表示False
print(0and8) # 0
print(5or8) # 5
print(0or8) # 8
print(not(5)) # False
3.6.5位运算符
运算符 | 说明 | 实例 |
& | 按位与 | a & b |
| | 按位或 | a | b |
^ | 按位异或 | a ^ b |
~ | 按位取反 | ~ a |
<< | 按位左移 | a << 1 |
>> | 按位右移 | a >> 1 |
1)原码反码补码
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号,正数为0,负数为1。
| 正数7 | 负数-7 |
原码 | 符号位加上真值的绝对值00000111 | 符号位加上真值的绝对值10000111 |
反码 | 等于原码00000111 | 原码符号位不变,其余位取反 11111000 |
补码 | 等于原码00000111 | 反码的基础上+1 11111001 |
位运算时,以补码形式进行计算。
2)正数的与、或、异或、非运算

测试代码:
num1=17
num2=13
print(f"正数与运算: {num1} & {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1&num2:3} : {num1&num2:08b}")
print()
print(f"正数或运算: {num1} | {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1|num2:3} : {num1|num2:08b}")
print()
print(f"正数异或运算: {num1} ^ {num2}")
print(f"{num1:3} : {num1:08b}")
print(f"{num2:3} : {num2:08b}")
print(f"{num1^num2:3} : {num1^num2:08b}")
print()
print(f"非运算: ~{num1}")
print(f"{num1:3}原码 : {num1:08b}")
print(f"{num1:3}取反 : {(1<<8) -1^num1:08b},得到结果的补码")
print(f"{~num1:3}原码 : {~num1:08b},计算出结果的原码")
3)有负数的与、或运算

测试代码:
num1=17
num2=13
num3=-12
print(f"有负数的与运算: {num3} & {num1}")
print(f"{num3:3}原码 : {num3:08b}")
print(f"{num3:3}反码 : {(1<<8) -1+num3:08b}")
print(f"{num3:3}补码 : {(1<<8) +num3:08b}")
print(f"{num1:3}补码 : {num1:08b}")
print(f"{num1&num3:3}补码 : {num1&num3:08b},得到结果")
print()
print(f"有负数的或运算: {num3} | {num1}")
print(f"{num3:3}原码 : {num3:08b}")
print(f"{num3:3}反码 : {(1<<8) -1+num3:08b}")
print(f"{num3:3}补码 : {(1<<8) +num3:08b}")
print(f"{num1:3}补码 : {num1:08b}")
print(f"{num1|num3:3}补码 : {(1<<8) + (num1|num3):08b},得到结果的补码")
print(f"{num1|num3}原码 : {num1|num3:08b},计算出结果的原码")
4)按位左移、右移运算

测试代码:
num1=17
num2=-12
offset=1
print(f"左移运算: {num1} << {offset}")
print(f"{num1:3} : {num1:08b}")
print(f"{num1<<offset:3} : {num1<<offset:08b}")
print()
offset=2
print(f"左移运算: {num2} << {offset}")
print(f"{num2:3}原码\t\t: {num2:08b}")
print(f"{num2:3}反码\t\t: {(1<<8) -1+num2:08b}")
print(f"{num2:3}补码\t\t: {(1<<8) +num2:08b}")
print(f"{num2:3}补码<<{offset}\t: {(((1<<8) +num2) <<2) &0xff:08b},得到结果的补码")
print(f"{num2<<offset:3}\t\t\t: {num2<<offset:08b},计算出原码")
print()
offset=3
print(f"右移运算: {num1} >> {offset}")
print(f"{num1:3} : {num1:08b}")
print(f"{num1>>offset:3} : {num1>>offset:08b}")
print()
offset=3
print(f"右移运算: {num2} >> {offset}")
print(f"{num2:3}原码\t\t: {num2:08b}")
print(f"{num2:3}反码\t\t: {(1<<8) -1+ num2:08b}")
print(f"{num2:3}补码\t\t: {(1<<8) +num2:08b}")
print(f"{num2:3}补码>>{offset}\t: {(((1<<8) +num2) >>offset) | (0xff>>5<<5):08b},得到结果的补码")
print(f"{num2>>offset:3}\t\t\t: {num2>>offset:08b},计算出原码")
3.6.6成员运算符
运算符 | 说明 | 实例 |
in | 在指定的序列中找到值返回 True,否则返回 False | a in ['a', 'b', 'c'] |
not in | 在指定的序列中没有找到值返回 True,否则返回 False | a not in ['a', 'b', 'c'] |
# -------------成员运算符---------------
num6=1
num7=20
test_list= [1,2,3,4,5]
print(test_list)
print(num6intest_list) # True 判断1是不是列表中的的成员
print(num7notintest_list) # True
3.6.7身份运算符
运算符 | 说明 | 实例 |
is | 判断两个标识符是不是引用自相同对象 | a is b,类似id(a) == id(b)。如果引用的是同一个对象则返回True,否则返回False |
not is | 判断两个标识符是不是引用自不同对象 | a is not b,类似id(a) != id(b)。如果引用的不是同一个对象则返回True,否则返回False |
# -------------身份运算符---------------
m=20
n=20
q=30
print(misn) # True 判断m和n在内存中是否指向同一个地址
print(nisq) # False
print(nisnotq) # True
# id() 用于获取对象在内存中的地址
print(id(m) ==id(n)) # True
print("-"*30)
# -------------is和==的区别---------------
a= [1,2,3]
b=a
print(bisa) # True
print(b==a) # True
b=a[:]
print(b)
print(bisa) # False
print(b==a) # True
3.6.8运算符优先级

3.7Python编码规范
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。为确保所有人编写的代码的结构都大致一致, Python 程序员都遵循一些格式设置约定。
PEP8(Python Enhancement Proposal ,PEP)是最古老的PEP之一,它向 Python 程序员提供了代码格式设置指南。 https://python.org/dev/peps/pep-0008/
下面的列出一些基本的规范:
3.7.1缩进
在 Python 中,代码块的结束不像其他一些编程语言(如 C、Java 等)使用大括号 {} 来明确界定,而是通过缩进来表示。PEP 8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。在文本处理文档中,大家常常使用制表符而不是空格来缩进。对于文本处理文档来说,这样做的效果很好,但混合使用制表符和空格会让 Python 解释器感到迷惑。每款文本编辑器都提供了一种设置,可将输入的制表符转换为指定数量的空格。你在编写代码时应该使用制表符键,但一定要对编辑器进行设置,使其在文档中插入空格而不是制表符。
在程序中混合使用制表符和空格可能导致极难解决的问题。如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
3.7.2行长
很多 Python 程序员都建议每行不超过 80 字符。最初制定这样的指南时,在大多数计算机中,终端窗口每行只能容纳 79 字符;当前,计算机屏幕每行可容纳的字符数多得多,为何还要使用 79 字符的标准行长呢?这里有别的原因。专业程序员通常会在同一个屏幕上打开多个文件,使用标准行长可以让他们在屏幕上并排打开两三个文件时能同时看到各个文件的完整行。 PEP 8 还建议注释的行长都不超过 72 字符,因为有些工具为大型项目自动生成文档时,会在每行注释开头添加格式化字符。
PEP 8 中有关行长的指南并非不可逾越的红线,有些小组将最大行长设置为 99 字符。在学习期间,你不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8 指南。在大多数编辑器中,都可设置一个视觉标志,通常是一条竖线,让你知道不能越过的界线在什么地方。
3.7.3空行
要将程序的不同部分分开,可使用空行。你应该使用空行来组织程序文件,但也不能滥用。例如,如果你有 5 行创建列表的代码,还有 3 行处理该列表的代码,那么用一个空行将这两部分隔开是合适的。然而,你不应使用三四个空行将它们隔开。
空行不会影响代码的运行,但会影响代码的可读性。 Python 解释器根据水平缩进情况来解读代码,但不关心垂直间距。
3.7.4同一行显示多条语句
Python可以在某些时候同一行中可以使用多条语句,语句之间使用分号(;)分割,
但并不是所有情况都可以,所以不推荐这种写法。以下是一个简单的实例:
importsys;print(sys.path) #没有问题
'''
import sys
for i in sys.path:
print(i) #没有问题
'''
importsys;for i in sys.path:;print(i) # 报错
3.7.5分号
建议不要在行尾加分号,也不要使用分号将多条命令放在同一行。
3.7.6源文件编码
Python源码请使用 UTF-8 编码(Python2 中可以使用 ASCII 编码)。
文件采用 ASCII(Python2) 或者 UTF-8(Python 3)
3.7.7不以空格结束一行代码
在任何地方都不要以空格结束本行代码, 因为行末的空格不可见, 这可能会闹出问题: 比如反斜杠(连字符) 如果后面接空白字符就不再能够当连字符使用。 很多编辑器不允许以空格作为行结束符。
下一篇预告
今天我们掌握了 Python 注释、变量、数据类型和运算符 —— 这些都是处理大模型数据和参数的基础。下一篇将讲解流程控制(条件判断 / 循环),这是编写大模型训练逻辑的核心:比如用循环实现多轮训练,用条件判断停止训练、筛选有效数据,一定要跟上!
如果练代码时遇到报错,评论区贴出你的代码和报错信息,觉得干货有用,点赞 + 在看 + 转发,让更多想入门大模型的朋友一起学!