# Python教程 - 2 基础语法

# 2.1 注释

在学习基础语法之前先介绍一下注释。

我们在学习任何语言,都会有注释,注释的作用就是向别人解释我们编写的代码的含义和逻辑,使代码有更好的可读性。

注释不是程序,是不会被执行的

注释一般分类两类,单行注释多行注释

# 1 单行注释

单行注释以 # 开头,井号右边为注释内容。

例如:

# 我是单行注释,打印Hello World
print("Hello World!")
1
2

注意:# 号和注释内容一般建议以一个空格隔开,这是代码规范,建议大家遵守。

单行注释一般用于对一行或一小部分代码进行解释。

# 2 多行注释

多行注释是以一对三个双引号括起来,中间的内容为注释内容,注释内容可以换行。

"""
我是多行注释,
我来哔哔两句
"""
print("哔~~")
1
2
3
4
5

多行注释一般对:Python文件、类、方法进行解释,类和方法后面我们再学习。

# 2.2 变量

在代码中,数据是保存在哪里的呢?

在代码中,数据需要保存在变量中,变量是在程序运行的时候存储数据用的,可以想象变量为一个盒子。

整数、浮点数(小数)、字符串(文本)都可以放在变量中。

# 1 变量的定义

定义变量的格式:变量名称 = 变量值

举个栗子:

# 定义变量
name = "逗比笔记"     # 定义一个字符串变量,存储姓名
age = 18             # 定义一个整数变量,存储年龄
height = 1.78        # 定义一个浮点数类型,存储身高
is_has_jj = True     # 定义一个bool类型,存储是否有jj

# 定义完变量就可以使用变量了
print(name)       	 # 逗比笔记
print(age)        	 # 18
print(height)     	 # 1.78
print(is_has_jj)     # True
1
2
3
4
5
6
7
8
9
10
11

上面定义了4个变量,并赋值,值分别是字符串(string)、整数(int)、浮点型(float)、布尔型(bool)。

字符串(string)需要使用双引号 " 包围起来,可以包含任意字符。

布尔型(bool) 的值只有2个,即 TrueFalse,用来表示真和假,注意大小写不能错。

和 C 和 Java 语言不同,Python不是强类型变量,不需要指定变量的类型。


前面已经使用了 print 函数,用来输出数据,输出完数据会进行换行,所以每次输出都是新的一行,如果不想换行,可以使用如下方式:

print("逗比笔记", end="")		# 输出完不换行
print(13)
1
2

最终输出的结果是:逗比笔记13

# 2 变量的特征

变量变量,从名字中可以看出,表示“量”是可变的。所以,变量被定义后,可以在后面的代码中使用了,而且还可以重新修改变量的值。

例如:

# 1.定义变量
name = "逗比笔记"
age = 18
height = 1.78
is_has_jj = True

# 2.修改变量的值
name = "逗比"       # 修改name的值为逗比
age = age + 2      # 将age加2,重新赋值给age
height = 1.85
is_has_jj = False

print(name)       # 逗比
print(age)        # 20
print(height)     # 1.85
print(is_has_jj)  # False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以看到变量的值可以被修改,而且可以参与运算。

为什么要使用变量?

变量就是在程序运行时,记录数据用的,使用变量是为了重复的使用这些数据。

# 3 变量的存储

如果对 java 不熟悉,可以忽略 java 的介绍。

Java变量的内存机制

熟悉Java的小伙伴可能知道,Java中的数据类型分基本数据类型与引用数据类型,对于基本数据类型,在栈内存中存储的是基本数据类型的值,而对于引用数据类型,栈内存存储的是引用数据类型数据的内存地址,引用数据的值存储在堆内存空间,这个内存地址的就是该引用数据的堆内存地址。(可以忽略)

Python变量的内存机制

Python万物皆对象,在栈内存永远存储的是数据的堆内存地址,堆内存存储的数据值。

# 变量内存示意

上面说的是什么意思呢?

举个栗子:

a = 10
b = 20
1
2

在内存中的存储,示意图如下:

首先在栈区开辟了为a开辟一块内存,但是10并不是存储在a中,而是在堆区开辟了另一块内存存储10,然后将10的内存地址存在a中,

b同理。

继续

a = 10
b = a
1
2

在内存中的存储,示意图如下:

将a赋值给b,是将a中存储的地址赋值给b。

此时a和b指向堆中的同一块内存区域,里面存储了10,那么此时修改a的值,b的值会变吗?

a = 10
b = a

a = 20
print(b);
1
2
3
4
5

执行结果:

10

b的值不会变,为什么?

此时内存中的存储,示意图如下:

此时将20赋值给a,是在堆区中重新开辟了一块内存存储20,然后将20的地址赋值给a,a存储了20的地址,b没有变。

# is 关键字

如何判断两个变量是否指向同一块内存区域呢?

可以使用 is 关键字,举个栗子:

a = 10
b = 20
print(a is b)				# False,a和b指向的是不同的地址

a = 10
b = a
print(a is b)				# True,a和b指向的是相同的地址
1
2
3
4
5
6
7

同样还可以使用 is not 来进行相反的判断:

print(a is not b)
1

# 小整数对象池

我们之前可以在命令行中编写Python代码进行执行,这种方式称为交互式编程,现在我们重新编写一段代码:

完全懵逼了!!!

为什么a = 10 和 b = 10 指向的是相同的对象? a = 1000 和 b = 1000 指向的是不同的对象。

这是因为编译器Cpython中存在小整数池[-5, 256],在解释器启动的时候就自动开辟了,在全局范围内重复使用,不会被垃圾回收。

所以a = 10 和 b = 10 指向的是相同的对象。

把同样的代码放在文件中执行或在PyCharm中执行:

a = 10
b = 10
print(a is b)

a = 1000
b = 1000
print(a is b)
1
2
3
4
5
6
7

执行结果:

True

True

又懵逼了!!!

为什么和交互式执行的结果又不一样?

这是因为出于对性能的考虑,编译器会扩大小整数池的范围,如果创建变量的值如果相同的话,创建的时间间隔又比较短,那么他们的内存空间的值是相同的。

其他的字符串等不可变类型也都包含在内一便采用相同的方式处理了,我们只需要记住这是一种优化机制,至于范围到底多大,无需细究。

# id 函数

上面 is 关键字的逻辑是比较两个变量指向的是否是相同的内存地址,我们可以使用 id 函数获取变量的内存地址:

a = 10
b = 10
print(a is b)
print(id(a))
print(id(b))
1
2
3
4
5

执行结果:

True
4400850656
4400850656
1
2
3

可以看到变量 a 和 b 的地址是相同的,所以 a is b 为 True。

# 4 del 关键字

del的作用是删除变量,解除变量和堆中对象的关联。

举个栗子:

a = 10
del a
print(a)		# 代码执行到这里会报错,因为del a已经将变量a删除了,这里a是没有声明的,所以会报错。
1
2
3

此时的内存示意如下:

此时的变量a内删除,没有变量指向10,10的内存空间随时可能被当做垃圾回收。

# 2.3 数据类型

刚才在定义变量的时候,我们使用了字符串(string)、整数(int)、浮点型(float)、布尔型(bool)4个类型。

在后面我们还会学习对象类型、列表(List)、元组(Tuple)、集合(Set)、字典(Dictionary)等类型,不着急,后面会慢慢学习。


下面先看一下如何获取数据的类型。

当我们将不同的类型的数据放到了变量中,那么如何验证一个数据的数据类型呢?

例如:

money = 50
name = "张三"
1
2

# 1 type()

使用 type() 函数,可以得到数据的类型。

举个栗子:

print(type(10))
print(type(3.14))
print(type("100"))
1
2
3

执行结果如下,可以看到三个数据的类型,分别是整形、浮点型、字符串:

<class 'int'>
<class 'float'>
<class 'str'>
1
2
3

我们还可以将 type() 的结果保存到变量中:

data_type = type("人生苦短,我选Python")
print(data_type)    # 执行结果: <class 'str'>
1
2

也可以查看变量中存储的数据的类型:

name = "张三"
data_type = type(name)
print(data_type)    # 执行结果: <class 'str'>
1
2
3

再来看一个问题,代码如下:

# 在value变量中放入字符串
value = "张三"
data_type = type(value)
print(data_type)

# 在value变量中,重新放入整形
value = 10
data_type = type(value)
print(data_type)
1
2
3
4
5
6
7
8
9

我们先后在同一个变量中,放入字符串和整形数据,执行的结果是:

<class 'str'>
<class 'int'>
1
2

可以得出,变量是没有类型的,有类型的只是其中的数据

# 2 None

Python中有一个特殊的值,就是None,None表示空,什么都没有。在其他语言中可能叫 null、nil等。

如果我们想创建一个变量,但是变量中存储什么类型的数据还不确定,可以在初始化的时候,赋值为None。

a = None
print(type(a))
1
2

打印结果:

<class 'NoneType'>
1

None 是 NoneType 数据类型的唯一值,可以将 None 赋值给任何变量。

# 3 变量的注解

在 Python 中定义变量是不需要指定类型的。但是在 Python 中,变量注解(Variable Annotations)是 Python 3.5 引入的一个新特性,它允许开发者为变量和函数参数提供预期的类型信息。

举个栗子:

name: str = "逗比"  # 定义姓名
age: int = 30  # 定义年龄
height: float = 1.78  # 定义升高
is_has_jj: bool = True  # 定义是否有jj
1
2
3
4

这个例子中,name 被注解为 str 类型,age 被注解为 int 类型,height 被注解为 float 类型,is_has_jj 被注解为 bool 类型。

但是需要注意:注解只是用来做类型提示的,不会做类型验证,不按照类型赋值也没有问题。

name: str = 13				# 定义姓名
age: int = "逗比"  		# 定义年龄
1
2

上面也是可以的,只是不建议这么做。

# 4 类型转换

数据类型转换就是不同的数据类型之间是可以进行转换的,例如在某些时候,我们需要将数字转换为字符串,或者字符串转换为数字。

为什么需要进行类型转换呢?

例如我们从文件读取的数字,默认是字符串类型的,我们读取以后需要转换为数字类型,例如将字符串"100"转换为数字100。

常用的转换函数有如下3个:

函数 说明
int(x) 将x转换为一个整数
float(x) 将x转换为一个浮点数
str(x) 将x转换为字符串

上面的函数会将转换完成的结果返回。

演示一下,将字符串转换为整数:

v_str = "10"          # 定义一个字符串类型的数据
print(type(v_str))    # 打印: <class 'str'>

v_int = int(v_str)    # 将字符串转换为整数
print(v_int)          # 打印: 10

print(type(v_str))    # 打印: <class 'str'>
print(type(v_int))    # 打印: <class 'int'>
1
2
3
4
5
6
7
8

有几点需要注意:

1. 任何类型都可以通过str()转换为字符串,但是如果将字符串转换为数字,字符串必须得是数字格式。

v_str = "123a"
v_int = int(v_str)    # 报错,不是整数,转化失败

v_str = "12.13"
v_int = int(v_str)    # 报错,不是整数,转化失败
1
2
3
4
5

2. 浮点数转换为整数会丢失精度

v_float = 12.13
v_int = int(v_float)  # 将浮点数转换为整数
print(v_int)          # 打印: 12, 小数部分丢失
1
2
3

# 2.4 标识符

什么是标识符?

标识符就是名字,例如变量的名字、方法的名字、类的名字。

起名字肯定会有限制,肯定不能 张Three 这样起名字,所以标识符也有限制。

# 1 标识符命名规则

标识符需要遵守一下规则:

  1. 只能是英文、数字、下划线_、中文(可以是中文,但是强烈建议不要使用),其他任何内容都不允许;
  2. 不能使用数字开头,可以英文或下划线开头;
a					# 可以
a_b				# 可以
_a				# 可以
a1				# 可以
a_b_a			# 可以

1					# 错误
1_				# 错误
1_a				# 错误
1
2
3
4
5
6
7
8
9
  1. 大小写敏感,大小写不同是不同的标识符;
name = "zhangsan"   
Name = "lisi"				# 和 name 是不同的标识符
1
2
  1. 不能使用关键字,关键字就是Python中保留的一些单词,有特殊的用途,不能被用作标识符;

Python 有如下关键字:

这么多怎么记?不用记!不用记!不用记!

后面每个关键字都会学到,自然知道每个关键字是做什么用的,不用记!

# 2 变量命名规范

使用上面说的规则,我们可以定义变量名了。

但是为了优雅、统一、规范,我们在定义变量名时,还应该遵守以下规范,虽然你不遵守,没人开枪打死你,但是建议你遵守。

  1. 见名知意

看见一个变量名,就知道这个变量名是干嘛的。

a = "zhangsan"								# 看到a,鬼知道a是干嘛的
name = "zhangsan"							# 看到name,就知道这是个名字,简单明了
a_person_name = "zhangsan"		# 在确保明了的前提下,尽量减少长度,这个有点不够简洁
1
2
3
  1. 多个单词使用下划线分隔
first_name = "Jim"
student_nickname = "胖墩"
1
2
  1. 变量中的英文应全部小写
Name = "zhangsan"			# 不推荐
name = "zhangsan"			# 推荐
1
2

# 2.5 字符串扩展

# 1 字符串定义方式

在上面我们使用双引号 " 来定义字符串,但其实字符串有3种不同的定义方式:

方式一:双引号定义法

text1 = "我是一个字符串"
1

方式二:单引号定义法

text2 = '我是一个字符串'
1

方式三:三引号定义法

三引号除了可以用来表示多行注释,如果将三个引号的内容赋值给一个变量,还可以用来定义字符串,还可以换行:

text3 = """我是一个字符串,
我还可以换行"""
1
2

# 2 转义字符

如果我们的字符串中包含引号,该怎么处理呢?

如果字符串中包含单引号,可以使用双引号定义法:

str = "Hello 'Python'"
1

如果字符串中包含双引号,可以使用单引号定义法:

str = 'Hello "Python"'
1

还有一个通用的方法,就是使用转义符 \ ,在引号前面加上 \ 表示后面的字符是普通字符串:

str = "Hello \"Python\""
str = "Hello \'Python\'"
1
2

同样,如果你想在字符串中输出 \t ,你可能会这样写:

str = "Hello \t \"Python\""
print(str)
1
2

但运行完成结果却没有 \t ,因为 \t 是制表符,同样 \n 是换行符,如果想在字符串中输出 \t\n 等特殊字符,也是需要对 斜杠 \ 进行转义:

str = "Hello \\t \"Python\""
print(str)
1
2

# 3 字符串拼接

# 使用加号拼接

两个字符串拼接,直接使用 加号+ 拼接即可,例如:

print("Hello " + "World")			# 输出:Hello World
1

但是上面的拼接纯属脱裤子放屁,直接写成 print("Hello World") 就完了,所以一般字符串拼接都是在字面量和变量、变量和变量之间拼接:

name = "张三"
print("Hello, 我是" + name + ", 法外狂徒就是我")		# 输出:Hello, 我是张三, 法外狂徒就是我
1
2

# 拼接其他类型

使用 加号+ 能否拼接 数字bool 类型呢?

age = 2023
print("Hello, 我是法外狂徒,我生于:" + age)
1
2

运行报错:

那该如何拼接非字符串类型呢?

需要将其他非字符串类型的数据转换为字符串,如下:

age = 2023
is_adult = True
print("Hello, 我是法外狂徒,我生于:" + str(age) + ", 是否成年:" + str(is_adult))
1
2
3

# 4 字符串格式化

# 占位符

在上面进行字符串拼接的时候,会发现如果要拼接的变量太多,会很麻烦,而且非字符串变量还需要手动转换为字符串,有没有更好的方式呢?

那就是字符串格式化

举个栗子:

name = "张三"
print("Hello, 我是%s, 法外狂徒就是我" % name)		# 输出:Hello, 我是张三, 法外狂徒就是我
1
2

上面的 %s 表示占位符,% 表示我要占位,s 表示将变量转换为字符串放到这里。

多个变量呢?

使用 括号() ,将多个变量括起来:

name = "张三"
age = 18
print("Hello, 我是%s, 年龄%s" % (name, age))
1
2
3

# 数据类型占位

上面的 %s 表示将数据转换为字符串拼接,数字也被转换为字符串后进行拼接。

我数字凭什么要转换为字符串后拼接,就不能直接拼接吗,这显得很不体面,既然不体面,我们就帮它体面。

除了 %s 占位符,还有两个常用的占位符:

格式符号 说明
%s 将内容转换成字符串,放入占位位置
%d 将内容转换成整数,放入占位位置
%f 将内容转换成浮点型,放入占位位置

举个栗子:

name = "张三"
age = 18
money = 3.14
print("Hello, 我是%s, 年龄%d, 我有%f块钱" % (name, age, money))
1
2
3
4

输出如下:

Hello, 我是张三, 年龄18, 我有3.140000块钱
1

这个小数点后面是什么鬼,如何控制数字精度呢

# 精度控制

我们可以在 占位符 % 后面 使用辅助符号"m.n"来控制数据的宽度和精度:

m:控制宽度(很少使用),要求是数字,设置的宽度小于数字自身,不生效

.n,控制小数点精度,要求是数字,会进行小数的四舍五入。

有点抽象,举个栗子:

name = "张三"
age = 18
money = 3.14
print("Hello, 我是%s, 年龄%5d, 我有%5.2f块钱" % (name, age, money))
1
2
3
4

输出如下:

Hello, 我是张三, 年龄 18, 我有 3.14块钱

%5d表示:age最少占用 5 个字符的位置,18已经占用了 2 个字符,那么需要再前面加 3 个空格,最后的d表示已整数的形式输出。

%5.2f表示:money最少占用 5 个字符的位置,.2 表示保留小数点 2 位,那么小数点前只能占用3位了,当然前面数字大于3位,那么小数点前的限制就不生效了。

一般常用的方式是只限制小数点后的位数:

%.2f:表示不限制宽度,只设置小数点精度为2。

例如:

money = 3.1415
print("我有%.2f块钱" % money)
1
2

输出:

我有3.14块钱
1

# 5 快速格式化

目前通过%符号占位已经很方便了,还能进行精度控制,但是Python还有更方便的写法。

语法格式:

f"内容{变量}"
1

通过在字符串前面添加一个 f ,可以在字符串中使用 {} 嵌入变量。

举个栗子:

name = "张三"
age = 18
money = 3.14
print(f"Hello, 我是{name}, 年龄{age}, 我有{money}块钱")
1
2
3
4

输出:

Hello, 我是张三, 年龄18, 我有3.14块钱
1

可以看到,这种写法没有精度控制,不理会数据类型,都是原样输出。

# 6 字符串比较

在有些语言中,比较两个字符串要麻烦一些,但在 python 中还是比较简单的。

比较连个字符串是否相等:

# 定义字符串  
str1 = "Hello"
str2 = "Hello"
str3 = "hello"

print(str1 == str2)  # 相等True
print(str1 == str3)  # 不等False
1
2
3
4
5
6
7

如果要忽略大小写进行比较,可以先转换为小写后,再进行比较:

# 定义字符串
str1 = "Hello"
str2 = "hello"

print(str1.lower() == str2.lower())  # str1.lower()是将字符串转换为小写
1
2
3
4
5

还可以按照字典顺序比较两个字符串的大小:

# 定义字符串
str1 = "abcde"
str2 = "doubibiji"

print(str1 > str2)  # False
print(str1 < str2)  # True
1
2
3
4
5
6

这些比较都是基于字符的 Unicode 码点进行的。例如,大写字母在字典序上小于小写字母,因为它们的 Unicode 码点较小。同样,数字在字典序上也小于字母。

# 2.6 数据输入

前面都时候使用print函数在控制台打印数据,Python还提供了一个函数input,用于读取键盘输入的数据。

# 1 input()

input函数使用也很简单,直接举栗子:

print("请输入姓名:")
name = input();
print("你的名字是:" + name)
1
2
3

上面的代码input()会读取键盘输入的内容,赋值给name变量。

运行代码后,代码执行到input函数时,会阻塞,等待你在控制台输入,当你输入完成后,回车。代码会继续执行,打印你输入的姓名。

例如我输入zhangsan,执行结果:

请输入姓名:
zhangsan
你的名字是:zhangsan
1
2
3

上面的代码,第一句是多余的,上面的代码还可以写成:

name = input("请输入姓名:");
print("你的名字是:" + name)
1
2

# 2 数据输入的类型

上面从键盘读取的数据的类型都是字符串类型的。

所以如果要获取整数或浮点数类型,需要在获取数据后,对数据进行转换。

age = input("请输入年龄:");
age = int(age)

money = input("请输入余额:")
money = float(money)

print(f"你的年龄是:{age},余额:{money}")
1
2
3
4
5
6
7