Python入门 —— 从零基础到调包侠

文章目录

  • hello world
  • 常量和表达式
  • 变量
    • 使用
    • 类型
      • int整型
      • float浮点型
      • str字符串
      • bool布尔型
    • 动态类型特性
  • 注释
    • 行注释
    • 文档字符串
  • 输入输出
    • print() 格式控制
    • input()
  • 运算符
    • 算术运算符
    • 比较运算符
    • 逻辑运算符
    • 赋值运算符
    • 其他
  • 条件语句
    • if else缩进与代码块
    • 练习
    • 空语句
  • 循环
    • while 循环
    • for 循环
  • 函数
    • 定义函数的格式
    • 调用
    • 返回值
    • 作用域
    • 关键字传参
  • 列表和元祖
    • 创建列表
    • 下标访问
    • 切片操作
    • 列表的遍历
    • 列表的插入
    • 列表的查找
    • 列表的删除
    • 列表的拼接
    • 元祖操作
  • 字典
    • 创建字典
    • 查找 key
    • 字典的新增修改删除
    • 字典的遍历
    • 合法的 key 类型
  • 文件操作
    • 打开文件
    • 关闭文件
    • 写文件
    • 读文件
    • 上下文管理器
    • 标准库
    • 使用案例
      • 日期计算
      • LeetCode 翻转单词顺序
      • LeetCode 旋转字符串
      • LeetCode 统计是给定字符串前缀的字符串数目
      • 文件搜索工具
    • 第三方库
      • 使用 pip
    • 使用案例
      • 生成二维码
      • Excel 操作
      • 学生管理系统
  • 结语

hello world

使用 print() 这个内建函数可以直接打印内容,不需要像C/C++那样包含头文件,写 main 函数,也不需要在语句的末尾加 ;

print('hello world')

# 结果:
# hello world

如果你在末尾加了 ;,那也不算错。如果把多个语句写在同一行,语句之间必须加 ;(不推荐)

常量和表达式

print(1 + 5 - 3)
print(1 - 2 / 3)
print(2 // 3)

# 结果:
# 3
# 0.33333333333333337
# 0

在 Python 中,2 / 3 是 0.66666,而不是0,它不像 C++ / Java 整数除以整数还是整数,舍弃小数部分。

在 Python 中,舍弃小数可以用地板除法(取整除法) //2 // 3 结果就为 0 。

  • 形如 1 + 5 - 3 这样的称为表达式,这个表达式的运算结果,称为表达式的返回值
  • 1 2 3 这样的数字,称为 字面值常量
  • + - * / 称为运算符(操作符)

变量

使用

Python 定义变量时,不需要显式声明类型。而只是依靠初始化语句,根据初始化的值的类型来确定。

如我们要计算方差

计算方差的公式:
σ 2 = ∑ ( X − μ ) 2 N \sigma^2=\frac{\sum(X-\mu)^2}{N} σ2=N(Xμ)2
σ 2 \sigma^2 σ2 为总体方差, X X X 为变量, μ \mu μ 为总体均值, N N N 为总体例数。

因为要用每个数据都去减平均值,所以平均值是需要多次使用的,可以定义一个变量保存起来:

avg = (12.6 + 65.9 + 45 + 47.1) / 4
total = (12.6 - avg) ** 2 + (65.9 - avg) ** 2 + (45 - avg) ** 2 + (47.1 - avg) ** 2
result = total / 4
print(result)

** 表示乘方,** 2 就表示平方。


小技巧

有时候我们要改一个变量的变量名,但是该变量已经在很多地方都使用到了,手动一个一个改很不方便

在 PyCharm 中,我们可以将光标定位到要修改的变量名上面,按 Shift+F6 ,在弹出的窗口中输入新的变量名,点击重构即可。

类型

我们可以使用 type() 来查看变量的类型

a = 10
b = 0.5
c = 'hello'
print(type(a))
print(type(b))
print(type(c))

# 结果:
# 
# 
# 

int整型

在 Python 中,int 能够表示的数据范围是无穷大的(只要内存足够大),它可以根据要表示的数据的大小自动扩容,所以 Python 是天然支持高精度运算的。Python 也没有 short、long 这样的类型。

float浮点型

Python 中的 float 就是双精度浮点数,没有 double 类型。

str字符串

Python 中使用引号包含的一系列字符就是字符串,单引号和双引号都可以。

这里两种双引号的作用和 C/C++ 可不一样。

如果字符串本身包含引号,比如要把 my name is "cero" 再用一层引号引起来,表示成一串字符串:

a = "my name is "cero""

直接使用 "" 会导致 Python 解释器将 my name is 认为是一段字符串,而cero就不认识。

要把引号本身也当做字符串,一种方式是使用转义字符 \

a = "my name is \"cero\""

另一种方式,外围使用另一种引号:

a = 'my name is "cero"'

如果字符串内既有双引号,也有单引号,那么外围可以使用三引号''''''

b = '''zhangsan say: "hello 'lisi'"'''

使用 len() 函数可以求字符串长度

b = '''zhangsan say: "hello 'lisi'"'''
print(len(b))

# 结果:
# 28

Python 中的字符串也支持使用 + 来进行拼接:

a1 = 'hello'
a2 = ' world'
print(a1 + a2)

# 结果:
# hello world

注意:Python 中只有字符串类型,没有字符类型。如'a' 表示长度为1的字符串。也正因如此,Python 中''"" 都能表示字符串,没有作区分。

bool布尔型

Python 中的真用 True 表示,假用 False 表示,注意首字母是大写的。

动态类型特性

Python 中一个变量的类型是可以在程序运行中发生变化的,这个特性叫做动态类型

a = 10
print(type(a))
a = 'hello'
print(type(a))
a = True
print(type(a))

# 结果:
# 
# 
# 

像C/C++ Java就是静态类型的语言,程序运行过程中,一个变量的类型始终是不变的。

一个语言是否具有动态类型特性,与它是否需要在变量定义时什么类型无关,Python 其实也可以在定义时声明类型:

a:int = 10
print(type(a))
a:str = 'hello'
print(type(a))

Python的类型声明只起到增加可读性的作用,实际的类型还是要看给它赋的值。

注释

行注释

使用 # 开头

# 这是一行注释

文档字符串

使用三引号引起来的称为文档字符串,也是一种注释,

使用单引号或双引号均可。

'''
这是文档字符串
这是文档字符串
'''

"""
这是文档字符串
这是文档字符串
"""

PyCharm 中批量注释与取消注释的快捷键是 Ctrl + /

输入输出

print() 格式控制

a = 10
print(f'a = {a}')

# 结果:
# a = 10

这就类似于C语言中的 printf("a = %d\n", a);

Python 中这个语法,叫做格式化字符串(f-string)

在字符串前面加 f,就可以在后面的字符串中使用 {} 来嵌入变量或表达式。


print 也可以同时打印多个变量,中间用 , 分隔:

a = 10
b = 20
print(a, b)
# 结果:10 20

打印出的结果会被空格分隔。


print 打印默认会自动换行,如果你不想换行,可以增加一个关键字参数,将末尾设为 '' 空字符串,关键字参数会在下面的函数传参讲到。

a = 10
print(f'a = {a}', end='')
print(f'a = {a}', end='')
#结果:
# a = 10a = 10

input()

输入需要借助一个内建函数

input 函数执行会先打印传入的字符串,然后等待用户输入,最后将输入的值返回给变量,这个值是str类型

num = input('请输入一个整数:')
print(f'你输入的整数为 {num}')
print(type(num))

# 结果:
# 请输入一个整数:10
# 你输入的整数为 10
# 

如果你要拿它来加减乘除计算,那显然是不行的:

a = input('请输入第一个整数')
b = input('请输入第二个整数')
print(f'a + b = {a + b}')

# 结果:
# 请输入第一个整数10
# 请输入第二个整数20
# a + b = 1020

它会变成字符串拼接。

我们需要将 str 转换成 int 类型,可以用 int()

a = int(input('请输入第一个整数'))
b = int(input('请输入第二个整数'))
print(f'a + b = {a + b}')

# 结果:
# 请输入第一个整数10
# 请输入第二个整数20
# a + b = 30

以此类推,

如果想把整数转成字符串,使用 str()

如果想把字符串转成浮点数,使用 float()

运算符

算术运算符

+ - * / % ** //

这些在上述代码中已有体现。需要注意的点如下:

乘方运算符 **,右操作数表示指数,它即可是正整数,也可以是小数(如0.5开平方),负数(如-1求倒数)。


地板除法 // 只保留整数部分,采用向下取整的方式:

print(7 // 2)
print(-7 // 2)

# 结果:
# 3
# -4

因为是向下取整,所以不是简单的抹去小数部分,在数字相同,符号不同的情况下最后的算出的结果的绝对值可能是不同的。


+ 可以是字符串之间相加,也可以是整数和浮点数之间相加,也可以是整数和布尔值相加,布尔值在做算术运算时,True被看做1,False被看做0。

比较运算符

> < >= <= == !=

这些的用法和 C++ 是一样的,包括字符串 str 也可以使用比较运算符。

而C语言中对字符串使用比较运算符只是对指针的比较,要进行字符串比较需要借助 strcmp()


注意:

针对浮点数来说,使用 == 比较相等,存在一定风险。这一点对于所有语言都是一样的。

因为浮点数在内存中的存储和表示是可能存在误差的,这样的误差在进行算术运算的时候就可能被放大,导致 == 的误判。

print(0.1 + 0.2 == 0.3)
# 结果:False

如果单独打印 0.1 + 0.2

print(0.1 + 0.2)
# 结果:0.30000000000000004

可以发现,最后结果出现了误差。

正确的比较浮点数相等:

通过计算二者的差值判断是否在合理的误差范围内

a = 0.1 + 0.2
b = 0.3
print(-0.000001 < (a - b) < 0.000001)
# 结果:True

另外,Python 支持连续比较,这里就可以不用逻辑与运算符了。

逻辑运算符

and 逻辑与,or 逻辑或,not 逻辑取反

用法和 C/C++ 中的 && || ! 一样

Python 中也同样支持短路求值

对于 and 来说,如果左侧表达式为 False,那么右侧的表达式就不再求值了。对于 or 来说,如果左侧表达式为 True,那么右侧的表达式就不再求值了。

赋值运算符

=

Python 中的赋值运算符也支持链式赋值

a = b = 20

还支持多元赋值

a, b = 10, 20

相当于把 10 赋值给 a,把 20 赋值给 b。中间用 , 隔开

多元赋值有个很方便的运用场景:

变量交换

a, b = 10, 20
a, b = b, a
print(a, b)
# 结果:20 10

由于这两个值是同时赋过去的,所以不需要中间变量 tmp 了。

复合赋值运算符

例如+= -= *= /= &=,使用和C/C++是一样的。

注意左值的变量必须是事先定义过的。

另外,Python 不支持 +±- 这样的自增操作。我们使用 a += 1 这样的操作已经很简便了。

其他

身份运算符:is is not

成员运算符:in not in

位运算符:按位与& 按位或| 按位取反~ 按位异或^ 左移<< 右移>>

这些在后面介绍,此处不再赘述。

条件语句

if else缩进与代码块

使用 if else 关键字表示条件语句

if expression:
    do_something1
    do_something2
next_something

注意格式:if 后跟条件+: 下面的缩进部分表示在该语句的控制范围内。

多分支语句:

if - else

if expression:
    do_something1
else:
    do_something2

if - elif - else

注意 Python 中 else if 采用缩写 elif

if expression1:
    do_something1
elif expression2:
    do_something2
else:
    do_something3

注意:Python 中,缩进表示代码块,在 if else elif while for等 需要跟上代码块的部分,都是需要使用缩进来表示的。

Python 的这种风格是比较独特的,C/C++ Java 都是采用 {} 来表示代码块,对缩进没有硬性要求。Python 的这种方式一方面确实使代码更简洁了,另一方面也带了一点困扰:

if a == 1:
    if b == 2:
        if c == 3:
            if d == 4:
                if e == 5:
                    if f == 6:
                        if g == 7:
                            print('hello')
                    print('1')
        print('2')

像上面这样,如果嵌套层数过多,语句对应哪一级代码块,并不容易观察。需要借助游标卡尺

还好我们的 PyCharm 会显示竖线来辅助我们阅读对应的缩进级数。

练习

判断奇偶数

a = int(input('请输入一个整数'))
if a % 2 == 1:
    print('奇数')
else:
    print('偶数')

在 Python 中,负数 % 2 的结果仍然是正数,比如-9 % 2 => 1。所以这样写是可以判断负数的,而在C/C++ Java中是不行的。

空语句

像 if 这种语句后面必须跟一个代码块

如果我们要表示满足条件时啥都不做,C/C++ 中可以直接跟一个 {},大括号中间什么都不写。

Python 抛弃了大括号,所以这种方式显然是不行的

这里就需要使用空语句 pass 占位,用它缩进来表示一个代码块,而它本身是不执行的。

a = input('输入1啥都不做,输入其他数打印hello')
if a == '1':
    pass
else:
    print('hello')

另外 Python 中没有 switch 语句。

循环

while 循环

格式:

while 条件:
    循环体

for 循环

格式:

for 循环变量 in 可迭代对象:
    循环体

注意:

  • Python 的 for 和其他语言不同,没有初始化语句,循环条件判断语句,循环变量更新语句。它其实类似于C++11中的范围for
  • 可迭代对象指内部包含多个元素,能一个一个把元素取出来的对象。

打印1到10:

for i in range(1, 11):
    print(i)

range 是一个内建函数,效果是得到一个可迭代对象,这个可迭代对象包含 [参数1, 参数2) 之间的整数。

range 还提供了第三个参数,表示步长,默认步长是1。

打印 2 4 6 8 10:

for i in range(2, 11, 2):
    print(i)

打印 从10到1

for i in range(10, 0, -1):
    print(i)

continue 立即结束当前循环进入下次循环

break 跳出循环

这些在Python中也是一样的。

Python 没有 do while 和 goto 语句,对于循环来说,只需要有上面两种就够了。

函数

定义函数的格式

def 函数名(形参列表):
    函数体
  • 在C/C++中,def关键字的位置应该是返回类型,而 Python不需要显式去写,它返回的类型,由最后 return 的值决定。如果你不想return一个值,那也可以不写return语句。
  • Python 的形参列表,当然也是可以给缺省值的,方法和C++一样,从右往左给
  • Python 是弱类型的语言,不支持函数重载,如果定义多个名称相同的函数,下一个函数总会覆盖上一个函数。

如要写一个函数计算给定范围内的整数的和:

def calcSum(beg, end):
    sum = 0
    for i in range(beg, end + 1):
        sum += i
    print(sum)

调用

calcSum(1, 100)
calcSum(1, 1000)
calcSum(300, 400)
# 结果:
# 5050
# 500500
# 35350

注意

Python 规定,函数定义必须在函数调用之前

C/C++ Java 里的函数,要求形参和实参的类型匹配,而 Python 不要求,因为 Python 是动态类型的语言。可以传入任意的类型,这其实就是一种泛型编程,在 C++ 中只能通过模板来实现,而 Python 定义的函数是天然支持的

返回值

Python 一个重要的特性:

一个函数可以返回多个返回值,这一点还是非常香的

def getPoint():
    x = 10
    y = 20
    return x, y

采用多元赋值接收返回值:

a, b = getPoint() # x赋值给a,y赋值给b

如果你只需要其中部分返回值,可以用 _ 来占位:

_, b = getPoint() # 忽略x,把y赋值给b

作用域

定义在函数内部的是局部变量,定义在函数外部的全局变量。遵守局部优先原则。

需要注意的是,Python只有函数和类的代码块对变量的作用域有影响,其他像if,else,while,for这些关键字的代码块不会有影响。这一点和 C/C++ Java 是不一样的

x = 10	# 全局变量

def test():
    print(f'x = {x}')	# 访问全局变量

test()	# 函数调用
#结果:x = 10

由于 Python 创建变量和修改变量的语法是一样的,所以在函数内部修改全局变量会被解释器当成是创建一个新的局部变量。

要想在函数内部修改全局变量,必须使用 global,以声明这是个全局变量,下面的赋值操作起修改作用。

x = 10

def test():
    global x	# 声明x为全局变量
    x = 20

test()
print(f'x = {x}')
# 结果:x = 20

关于函数栈帧,递归调用,和C/C++的思想是一样的,这里不多赘述。

关键字传参

实参按照形参的先后顺序来传参,这种传参风格,称为位置参数,这是各大编程语言中最普遍的传参方式。

而 Python 还支持关键字传参:按照形参的名字来进行传参。

def test(x, y):
    print(f'x = {x}')
    print(f'y = {y}')

test(y = 20, x = 10)

# 结果:
# x = 10
# y = 20

优点:可以非常明显的告诉程序员,你的参数要传给谁,另外可以无视形参和实参的顺序。

注意:位置参数和关键字参数可以混用,混用时,要求位置参数在前,关键字参数在后。

列表和元祖

这部分就类似于其他编程语言中的数组。

列表和元祖,大部分功能都是差不多的,但是有一个功能具有非常明显的区别:

列表是可变的,创建好之后,随时能改

元祖是不可变的,创建好了之后,改不了,要想改只能抛弃旧的,搞个新的。

创建列表

两种方式:

  1. 直接使用字面值来创建

    [] 就表示一个空的列表

  2. 使用内建函数 list() 来创建

a = []
b = list()
print(type(a))
print(type(b))

# 结果:
# 
# 

可以在创建列表时,在 [] 中指定列表的初始值。

a = [1, 2, 3, 4]
print(a)
# 结果:
# [1, 2, 3, 4]

注意:

  • C/C++ Java 一个数组只能存放一个类型的变量,而 Python 里的列表存放的变量的类型无限制。
a = [1, 'hello', True, [4, 5, 6]]
print(a)
# 结果:
# [1, 'hello', True, [4, 5, 6]]

下标访问

下标访问依然是用 [],使用方法和 C/C++ 一样

a = [1, 2, 3, 4]
print(a[2])
# 结果:
# 3

使用下标来修改列表元素:

a = [1, 2, 3, 4]
a[2] = 10
print(a)
# 结果:
# [1, 2, 10, 4]

和字符串类似,使用内建函数 len() 可以获得列表的元素个数:

a = [1, 2, 3, 4]
print(len(a))
# 结果:
# 4

len 函数支持传入字符串,列表,元祖,字典,自定义的类…

Python 中的下标还支持写成负数,比如 -1,其实就等价于 len(a) - 1,也可以理解成倒数第一个元素。

a = [1, 2, 3, 4]
print(a[len(a) - 1])
print(a[-1])
# 结果:
# 4
# 4

切片操作

通过下标访问是一次取出里面的一个元素

通过切片,则是一次取出一组连续的元素,相当于得到一个 子列表

a = [1, 2, 3, 4]
print(a[1:3])
# 结果:[2, 3]

切片操作中,[] 内有两个数字,由 : 分隔。第一个数字表示开始区间的下标,第二个数字表示结束区间的下标,区间为左闭右开。此处的下标也可以写成负数形式

这两个边界是可以省略的:

a = [1, 2, 3, 4]
print(a[1:])
# 结果:[2, 3, 4]
print(a[:3])
# 结果:[1, 2, 3]
print(a[:])
# 结果:[1, 2, 3, 4]
  • 省略后边界,则取出的是从开始区间直到列表最后。
  • 同理,省略前边界,则取出列表开头到结束区间
  • 前后边界都省略,则取出整个列表

切片操作,可以指定步长

增加一个 : 第三个数字表示的就是步长

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[::2])
# 结果:[1, 3, 5, 7, 9]

步长也可以是负数,表示从后往前取

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a[::-2])
# 结果:[10, 8, 6, 4, 2]

注意:

  • 切片操作是一个比较高效的操作,进行切片的时候,只是取出了原有列表中的一个部分,不涉及数据的拷贝

  • 如果给的边界值超出范围,最后的效果和省略边界是一样的

列表的遍历

  1. 列表是可迭代对象,使用 for 循环可以完成基本的遍历
a = [1, 2, 3, 4, 5]
for e in a:
    print(e)
  1. 通过下标,使用 for 循环完成遍历
a = [1, 2, 3, 4, 5]
for i in range(0, len(a)):
    print(a[i])

使用第二种方式,可以对列表内的元素进行修改,而使用第一种方式就不行了:

a = [1, 2, 3, 4, 5]
for i in range(0, len(a)):
    a[i] += 10
print(a)

# 结果:[11, 12, 13, 14, 15]
  1. 通过下标,使用 while 循环完成遍历
a = [1, 2, 3, 4, 5]
i = 0
while i < len(a):
    print(a[i])
    i += 1

总结:如果不修改列表,则可以采用第一种方式,如果要修改列表,则要采用第二或第三种方式。

列表的插入

  1. 使用 append 方法在列表末尾插入元素
a = [1, 2, 3, 4, 5]
a.append(6)
a.append('hello')
print(a)
# 结果:[1, 2, 3, 4, 5, 6, 'hello']

注意 append 是需要搭配列表对象来一起使用的,而不是一个独立的函数。

这种要搭配对象来使用的函数,也叫作方法

  1. 使用 insert 方法在列表的任意位置插入元素

第一个参数表示要插入的位置的下标,第二个参数就是要插入的元素

a = [1, 2, 3, 4, 5]
a.insert(1, 'hello')
print(a)
# 结果:[1, 'hello', 2, 3, 4, 5]

注意:如果下标越界,则新的元素会被插入到列表的末尾。

列表的查找

  1. 使用 in 来判定某个元素是否在列表中
a = [1, 2, 3, 4, 5]
print(1 in a)
print(10 in a)
# 结果:
# True
# False

和它对应的还有 not in,用来判断一个元素是否不存在于列表中

a = [1, 2, 3, 4, 5]
print(1 not in a)
print(10 not in a)
# 结果:
# False
# True
  1. 使用 index 方法得到一个元素在列表中的位置的下标
a = [1, 2, 3, 4, 5]
print(a.index(3))
# 结果:2

注意:传入的参数必须是列表中存在的元素,否则会抛异常。这一点和 C++ Java 不同,它们都可以返回 -1 表示不存在,Python 的负数下标本身就有意义。

列表的删除

  1. 使用 pop 删除列表末尾的元素
a = [1, 2, 3, 4, 5]
a.pop()
print(a)
# 结果:[1, 2, 3, 4]
  1. 使用 pop 删除任意位置的元素,传一个下标过去。
a = [1, 2, 3, 4, 5]
a.pop(1)
print(a)
# 结果:[1, 3, 4, 5]

如果下标越界,则会报错。

  1. 使用 remove 方法,按照值来进行删除
a = [1, 2, 3, 4, 5]
a.remove(3)
print(a)
# 结果:[1, 2, 4, 5]

如果是不存在的元素,则会报错。

列表的拼接

  1. 类似于字符串,列表也可以使用 + 进行拼接
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
c = a + b
print(c)
# 结果:[1, 2, 3, 4, 5, 6, 7, 8]

使用 + 拼接,只是针对当前列表的内容生成了一个更大的新的列表,原有列表的内容是不变的。

  1. 使用 extend 进行拼接

这个操作是把后一个列表的内容拼接到前一个列表的里面,会修改原来的列表

a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
a.extend(b)
print(a)
print(b)
# 结果:
# [1, 2, 3, 4, 5, 6, 7, 8]
# [5, 6, 7, 8]

注意:extend 是没有返回值的。如果你拿一个变量接收,最后打印这个变量的结果是 None 表示什么也没有。

  1. 使用 += 进行拼接
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
a += b
print(a)
print(b)
# 结果:
# [1, 2, 3, 4, 5, 6, 7, 8]
# [5, 6, 7, 8]

它的结果和 extend 是一样的,但是这两者的底层实现差异是很大的。

Python 中 a += b 等价于 a = a + ba + b 会产生创建一个新的更大的列表,然后将这个列表赋值给 a,最后还要把 a 的旧值释放。而 extend 就是直接把 b 的内容拼接到了 a 的后面。所以用 extend 效率更高。

元祖操作

元祖的操作基本是和列表一致的,只是不能进行修改操作。

创建元祖同样有两种方法,使用字面值创建,符号是(),或者使用内建函数 tuple()

a = ()
b = tuple()
print(type(a))
print(type(b))
# 结果:
# 
# 

创建元祖的时候指定初始值:

a = (1, 2, 3, 4)
print(a)
# 结果:(1, 2, 3, 4)

其他只读性质的操作皆和列表一致:

  • 元祖中的元素也可以是任意类型的。

  • 也可以通过 [] 下标来访问元祖中的元素,下标也可以是负数

  • 切片操作也和列表一样。

  • 也可以使用 for 循环等方式来遍历元素

  • 也可以使用 in 来判断元素是否存在,使用 index 查找元素的下标。

  • 可以使用 + 来拼接两个元祖

不可通过下标修改元素

其他插入删除操作均不可以。


当进行多元赋值的时候,其实本质上就是按照元祖的方式来进行的,

def getPoint():
    x = 10
    y = 20
    return x, y

x, y = getPoint()
print(type(getPoint()))
# 结果:

可以看到,函数的返回类型是元祖

字典

这部分内容类似 C++STL 中的 unordered_map 容器,都是用来存键值对的

创建字典

有两种方法,用{} 创建一个字典,或者使用内建函数 dict() 来创建字典。

a = {}
b = dict()
print(type(a))
print(type(b))
# 结果:
# 
# 

创建时初始化:

a = {
    'apple' : 1,
    'banana' : 2
}
print(a)
# 结果:{'apple': 1, 'banana': 2}

键值对之间使用 , 分隔,一个键值对用 : 分隔键和值,: 左边是键,: 右边是值。

  • 书写格式建议换行书写,增加代码美观性。

  • 一个字典中的 key 和 value 的类型都不必一样。但是 key 的类型是有限制的。

  • 字典中的 key 不能重复。

查找 key

  1. 使用 in 判断 key 是否在字典中。
a = {
    'apple' : 1,
    'banana' : 2
}
print('apple' in a)
print('orange' in a)
# 结果:
# True
# False

注意此处的 in 只能判断 key 是否存在,与 value 无关。

not in 效果和 in 相反。

  1. 使用 [] 来根据 key 获取 value
a = {
    'apple' : 1,
    'banana' : 2
}
print(a['apple'])
# 结果:1

如果在字典中没有相应的 key,程序会抛异常。

对于字典来说,使用 in 或 [] 来获取 value 都是非常高效的操作,因为底层实现是哈希表。

与列表不同,列表使用 in 是比较低效的,使用 [] 是比较高效的。因为底层实现是顺序表。

字典的新增修改删除

  1. 使用 [] 可以进行新增和修改,这一点和 C++ 是一样的。
a = {
    'apple' : 1,
    'banana' : 2
}
a['apple'] = 3
a['orange'] = 0
print(a)
# 结果:{'apple': 3, 'banana': 2, 'orange': 0}
  1. 使用 pop 方法,根据 key 删除键值对
a = {
    'apple' : 1,
    'banana' : 2
}
a.pop('apple')
print(a)
# 结果:{'banana': 2}

字典的遍历

  1. 字典是可迭代对象,可以直接使用 for 循环来遍历字典

这里的循环变量只能拿到字典中的 key

a = {
    'apple' : 1,
    'banana' : 2,
    'orange' : 3
}
for key in a:
    print(key, a[key])
# 结果:
# apple 1
# banana 2
# orange 3

Python 和 C++ Java 不一样,Python 做了特殊处理,能够保证遍历出来的顺序和插入的顺序是一致的。

  1. keys() 获取字典中所有 key
  2. values() 获取字典中所有 value
  3. items() 获取字典中所有键值对
a = {
    'apple' : 1,
    'banana' : 2,
    'orange' : 3
}

print(a.keys())
print(a.values())
print(a.items())
# 结果:
# dict_keys(['apple', 'banana', 'orange'])
# dict_values([1, 2, 3])
# dict_items([('apple', 1), ('banana', 2), ('orange', 3)])

返回的结果看起来像是列表,又不完全是。其实它是一个自定义类型,使用的时候可以把它当做列表。

  1. items() 配合 for 循环使用

items 返回的列表里面是一个一个的元祖,可以利用多元赋值进行遍历

a = {
    'apple' : 1,
    'banana' : 2,
    'orange' : 3
}

for key, value in a.items():
    print(key, value)
# 结果:
# apple 1
# banana 2
# orange 3

2 和 3 两种方法当然也可以搭配 for 循环使用,这里不多举例。

合法的 key 类型

使用 hash() 函数可以计算出一个对象的哈希值。

像整型,浮点数,字符串,布尔值,元祖都是可哈希的

print(hash(0))
print(hash(1.414))
print(hash('hello'))
print(hash(True))
print(hash((1, 2, 3, 4)))
# 结果:
# 0
# 954619005814469121
# 4737232595826697948
# 1
# 590899387183067792

像列表,字典都是不可哈希的

print(hash([1, 2, 3, 4]))	# 此处报错:TypeError: unhashable type: 'list'
print(hash({}))	# 此处报错:TypeError: unhashable type: 'dict'

不可变的对象,一般就是可哈希的,可变的对象,一般就是不可哈希的。

文件操作

打开文件

Python中打开文件的函数是 open()

open('d:/Python环境/test.txt', 'r')

第一个参数为文件路径,第二个参数为打开方式:

  • r 表示 read,按照只读方式打开
  • w 表示 write,按照只写方式打开
  • a 表示 append,也是只写方式打开,把内容追加到文件内容末尾

Python还有更多选项,具体不多赘述,可以自行查看Python官方文档。


使用 f 接受返回值,f 就是文件对象:

f = open('d:/Python环境/test.txt', 'r')
print(f)
print(type(f))
# 结果:
# <_io.TextIOWrapper name='d:/Python环境/test.txt' mode='r' encoding='cp936'>
# 

可以直接打印文件对象的一些信息,文件对象的类型。

如果文件不存在,那么按照只读方式打开会抛异常:文件未找到。

关闭文件

文件在使用完一定要关闭

使用 close 方法关闭文件

f.close()

写文件

使用 write 方法写文件

f = open('d:/Python环境/test.txt', 'w')
f.write('hello')
f.close()

如果是以只读方式打开,写文件的时候会抛异常

直接使用 w 方式打开,会把文件原有内容清空。使用 a 方式则不会。

读文件

  1. 使用 read 方法读文件,参数表示读取的字符数量

事先在文件中写下这两句话

人生苦短
我用Python
f = open('d:/Python环境/test.txt', 'r')
result = f.read(2)
print(result)
f.close()
#结果:浜虹

很明显,结果有误

这里要注意,读中文应该要保证文件内容的编码方式和代码中文件操作的编码方式相同。

我们的记事本是采用 utf-8,这也是使用最广泛的编码格式,而代码中是按照 gbk 编码格式来解析,显然不匹配。

在 open 后面加一个关键字参数 encoding,可以设置编码格式,改为 utf8 结果就正常了:

f = open('d:/Python环境/test.txt', 'r', encoding='utf8')
result = f.read(2)
print(result)
f.close()
#结果:人生
  1. for 循环 按行读取
f = open('d:/Python环境/test.txt', 'r', encoding='utf8')
for line in f:
    print(line, end='')
f.close()
#结果:
# 人生苦短
# 我用Python
  1. 使用 readlines 方法直接把整个文件所有内容都读出来,按照行组织到一个列表里。
f = open('d:/Python环境/test.txt', 'r', encoding='utf8')
lines = f.readlines()
print(lines)
f.close()
# 结果:
# ['人生苦短\n', '我用Python']

上下文管理器

在一个大型工程中,由于代码量比较大,各种语句的跳转等等,很容易让我们遗漏一些本该关闭的文件,导致资源泄露。

Python 中的上下文管理器可以有效地帮我们缓解这个问题:

def func():
    with open('d:/Python环境/test.txt', 'r', encoding='utf8') as f:
        # 文件处理的逻辑
        # 其他各种各样代码
        return

像这样,通过with as将open的返回值赋给f,后跟一个代码块,代码块内不管写什么东西,只要最后 with 对应的代码块执行结束,就会自动关闭 f 文件,从而避免资源泄露。

C++ 智能指针,Java try with Resources 也可以实现类似的操作。

是别人已经写好的代码,可以让我们直接拿来用。

按照库的来源,可以大致分为两类:

  • 标准库:Python 自带,只要安装了 Python 可以使用
  • 第三方库:其他人实现的库,需要额外安装使用

我们自己也可以实现第三方库,发布给别人使用。

标准库

可以使用官方文档查阅:Python 标准库 — Python 3.10.6 文档

安装 Python 的时候,文档也会附带安装,如果网络慢,可以查看本地文档。

使用案例

日期计算

datetime — 基本日期和时间类型 — Python 3.10.6 文档

import datetime
date1 = datetime.datetime(2019, 12, 8)
date2 = datetime.datetime(2022, 9, 4)
print(date2 - date1)
# 结果:1001 days, 0:00:00

这可比我们 C++ 自己写日期类要简单多了。

  1. 如果你觉得 datetime.datetime() 比较别扭,也可以这样:
from datetime import datetime
date1 = datetime(2019, 12, 8)
date2 = datetime(2022, 9, 4)
print(date2 - date1)
# 结果:1001 days, 0:00:00

from 模块 import 类型,这样后面就不需要用 模块名. 的方式来引出类型。

  1. 使用 import as 给模块取别名
import datetime as dt
date1 = dt.datetime(2019, 12, 8)
date2 = dt.datetime(2022, 9, 4)
print(date2 - date1)

LeetCode 翻转单词顺序

原题链接:剑指 Offer 58 - I. 翻转单词顺序 - 力扣(LeetCode)

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。

示例 1:

输入: "the sky is blue"
输出: "blue is sky the"

示例 2

输入: "  hello world!  "
输出: "world! hello"
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。

示例 3

输入: "a good   example"
输出: "example good a"
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

说明

  • 无空格字符构成一个单词。
  • 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
  • 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。

做这道题完全可以通过 Python 标准库里的函数 相关文档:内置类型 — Python 3.10.6 文档

str.split(sep=None, maxsplit=- 1) 切割字符串,返回一个列表,不传参默认以空格分隔,且连续的空格会被视为单个分隔符

reverse 方法将获得的列表逆序

str.join(iterable) 将列表转换为字符串,调用该方法的字符串 str 将作为元素之间的分隔符

class Solution:
    def reverseWords(self, s: str) -> str:
        tokens = s.split()
        tokens.reverse()
        return ' '.join(tokens)

LeetCode 旋转字符串

原题链接:796. 旋转字符串 - 力扣(LeetCode)

给定两个字符串, sgoal。如果在若干次旋转操作之后,s 能变成 goal ,那么返回 true

s旋转操作 就是将 s 最左边的字符移动到最右边。

  • 例如, 若 s = 'abcde',在旋转一次之后结果就是'bcdea'

示例 1:

输入: s = "abcde", goal = "cdeab"
输出: true

示例 2:

输入: s = "abcde", goal = "abced"
输出: false

提示:

  • 1 <= s.length, goal.length <= 100
  • sgoal 由小写英文字母组成

思路:将两个 s 字符串拼接,看 goal 是否是拼接后的大字符串的子串。

class Solution:
    def rotateString(self, s: str, goal: str) -> bool:
        if len(s) != len(goal):
            return False
        return goal in (s + s)

LeetCode 统计是给定字符串前缀的字符串数目

原题链接:2255. 统计是给定字符串前缀的字符串数目 - 力扣(LeetCode)

给你一个字符串数组 words 和一个字符串 s ,其中 words[i]s 只包含 小写英文字母

请你返回 words 中是字符串 s 前缀字符串数目

一个字符串的 前缀 是出现在字符串开头的子字符串。子字符串 是一个字符串中的连续一段字符序列。

示例 1

输入:words = ["a","b","c","ab","bc","abc"], s = "abc"
输出:3
解释:
words 中是 s = "abc" 前缀的字符串为:
"a" ,"ab" 和 "abc" 。
所以 words 中是字符串 s 前缀的字符串数目为 3 。

示例 2

输入:words = ["a","a"], s = "aa"
输出:2
解释:
两个字符串都是 s 的前缀。
注意,相同的字符串可能在 words 中出现多次,它们应该被计数多次。

提示

  • 1 <= words.length <= 1000
  • 1 <= words[i].length, s.length <= 10
  • words[i]s 包含小写英文字母。

python 中有现成的方法 startswith

class Solution:
    def countPrefixes(self, words: List[str], s: str) -> int:
        count = 0
        for word in words:
            if s.startswith(word):
                count += 1
        return count

文件搜索工具

使用 for 循环,通过 os.walk(top, topdown=True, onerror=None, followlinks=False) 遍历文件。

相关文档:os — 多种操作系统接口 — Python 3.10.6 文档

生成目录树中的文件名,方式是按上->下或下->上顺序浏览目录树。对于以 top 为根的目录树中的每个目录(包括 top 本身),它都会生成一个三元组 (dirpath, dirnames, filenames)

dirpath 表示遍历到当前位置对应的路径

dirnames 表示当前目录下,都有哪些目录,这是一个包含了多个目录名的列表。

filenames 当前目录下,都有哪些文件名,这是一个包含了多个文件名的列表。

它能帮我们递归遍历一个路径下的所有文件,我们只需要用简单的 for 循环就可以使用了

具体代码

遍历所有文件名,找到有包含关键词的文件,将路径和文件名打印出来

import os

inputPath = input('请输入要搜索的路径:')
pattern = input('请输入要搜索的关键词:')

for dirpath, _, filenames in os.walk(inputPath):
    for f in filenames:
        if pattern in f:
            print(f'{dirpath}/{f}')

结果

请输入要搜索的路径:d:/Python环境
请输入要搜索的关键词:test
d:/Python环境/test.txt
d:/Python环境\abc\def/test.txt

第三方库

通过查阅官方文档我们可以发现,Python 的标准库已经相当丰富了,但它终究是有限的。而程序员的智慧是无穷无尽的,更加庞大的第三方库,可以说是一个新的世界。

使用 pip

类似于手机的应用商店,Linux 的 yum,

Python 官方也有这样一个网站 pypi,收集了各种第三方库,网站链接:PyPI · The Python Package Index

pip 工具是 Python 内置的一个包管理器,可以直接从 pypi 上下载你想要的第三方库


pip 在安装 Python 时是一起安装好的

具体使用步骤:

点击 PyCharm 下方的终端(Terminal)

Python入门 —— 从零基础到调包侠_第1张图片

在其中输入 pip 会列出一堆帮助信息

如果你输入 pip 提示找不到这个命令,那么可能你在安装 Python 时没有勾选 Add Python 3.10 to PATH 选项,需要手动把 pip 所在路径放到 PATH 环境变量中,或者卸载重装 Python,勾选上述选项。


使用以下命令,安装第三方库

pip install [库名]

安装成功后,便可使用 import 导入使用了。

注意:如果使用 pip 安装完后,在 PyCharm 中仍然提示找不到对应的模块,则检查 Setting -> Project -> Python Interpreter,看当前 Python 解释器设置是否正确(安装了多个版本的 Python,容易出现这种问题)

Python入门 —— 从零基础到调包侠_第2张图片

如图,设置正确后,可以在下面看到已经安装的软件包。

使用案例

生成二维码

使用搜索引擎可以发现,Python 有一个库叫 qrcode,可以帮助我们实现生成二维码

在 pypi 上搜索 qrcode,了解详情:qrcode · PyPI

从这个官方文档中找到安装指令:

pip install qrcode[pil]

粘贴到 PyCharm 终端。

安装完成后即可进行使用,使用方式在官方文档中也有详细介绍。


这里用字符串简单写生成一个二维码。

import qrcode	# 导入模块

img = qrcode.make('我真帅')	# 传入一串字符串,img接受文件对象
img.save('qrcode.png')		  # 将文件保存在当前目录,名为 qrcode.png

运行,然后就可以找到生成的二维码:

Python入门 —— 从零基础到调包侠_第3张图片

Excel 操作

读取 Excel 可以使用 xlrd 模块 相关文档:xlrd — xlrd 2.0.1 documentation

修改 Excel 可以使用 xlwt 模块 相关文档:xlwt documentation — xlwt 1.3.0 documentation

我们推荐安装旧版本的,因为新版本不支持 xlsx 后缀的 Excel文件

pip install xlrd==1.2.0

如有以下 Excel 文件,我们要求 211 班的平均分

Python入门 —— 从零基础到调包侠_第4张图片

代码如下:

import xlrd	#导入模块
# 打开文件
xlsx = xlrd.open_workbook('C:/Users/cero/Desktop/test.xlsx')
# 打开第一个工作表,也就是 0,或者传入工作表名称 sheet1
table = xlsx.sheet_by_index(0)
# 获取表格行数
nrows = table.nrows
total = 0
count = 0
for i in range(1, nrows):	# 第一行是表头,我们从第二行开始遍历
    classId = table.cell_value(i, 1)	# 获取i行1列的数值,也就是班级号
    if classId == 211:					# 如果是211班,那么将i行2列的分数加入total,并计数
        total += table.cell_value(i, 2)
        count += 1
print(f'平均分:{total / count}')	# 计算平均分

结果:

平均分:72.0

学生管理系统

import os.path
import sys


students = []


def save():
    with open('record.txt', 'w', encoding='utf8') as f:
        for s in students:
            f.write(f'{s["studentId"]}\t{s["name"]}\t{s["gender"]}\t{s["className"]}\n')
        print(f'存储成功,共保存{len(students)}条记录')


def load():
    # 如果文件不存在,则直接 return
    if not os.path.exists('record.txt'):
        return

    global students
    with open('record.txt', 'r', encoding='utf8') as f:
        for line in f:
            # 去除末尾的换行符
            line = line.strip()
            # 按制表符进行切分
            tokens = line.split('\t')
            if len(tokens) != 4:
                print(f'当前行格式存在问题,line={line}')
                continue
            # 使用字典聚合学生信息
            student = {
                'studentId': tokens[0],
                'name': tokens[1],
                'gender': tokens[2],
                'className': tokens[3]
            }
            students.append(student)
    print(f'载入成功,共加载{len(students)}条信息')


def menu():
    print('1.新增学生')
    print('2.显示学生')
    print('3.查找学生')
    print('4.删除学生')
    print('0.退出')
    choice = int(input('请选择:'))
    return choice


def insert():
    studentId = input('请输入学生学号:')
    name = input('请输入学生姓名:')
    gender = input('请输入学生性别:')
    if gender not in ('男', '女'):
        print('性别输入有误,新增失败')
        return
    className = input('请输入学生班级:')
    # 用字典将学生信息聚合起来
    student = {
        'studentId': studentId,
        'name': name,
        'gender': gender,
        'className': className
    }
    # 放到全局的列表中
    global students
    students.append(student)
    print('增加成功!')


def show():
    for s in students:
        print(f'{s["studentId"]}\t{s["name"]}\t{s["gender"]}\t{s["className"]}')
    print(f'共显示{len(students)}条数据')


def find():
    name = input('请输入要查找的学生姓名:')
    count = 0
    for s in students:
        if name == s['name']:
            print(f'{s["studentId"]}\t{s["name"]}\t{s["gender"]}\t{s["className"]}')
            count += 1
    print(f'共显示{count}条数据')


def delete():
    studentId = input('请输入要删除的学生学号:')
    for s in students:
        if studentId == s['studentId']:
            print(f'删除 {s["name"]} 同学的信息')
            students.remove(s)
    print('删除成功')


def main():
    print('-----------------------------')
    print('     欢迎来到学生管理系统      ')
    print('-----------------------------')
    load()
    while True:
        choice = menu()
        if choice == 1:
            insert()
        elif choice == 2:
            show()
        elif choice == 3:
            find()
        elif choice == 4:
            delete()
        elif choice == 0:
            save()
            print('再见')
            sys.exit(0)
        else:
            print('输入有误,请重新输入')


main()

结语

以上就是 Python 入门的基础了,后续进阶内容,推荐书籍《Python Cookbook》。

这本书介绍了各种Python经典应用场景以及解决方案。

一些实用的程序库:

awesome-python: awesome-python 的中文版 (gitee.com)

使用简短的 Python 代码来实现一些有趣的程序:

GitHub - aosabook/500lines: 500 Lines or Less

你可能感兴趣的:(Python小课,python,开发语言,后端,pip)