使用 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
这样的称为表达式,这个表达式的运算结果,称为表达式的返回值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))
# 结果:
#
#
#
在 Python 中,int 能够表示的数据范围是无穷大的(只要内存足够大),它可以根据要表示的数据的大小自动扩容,所以 Python 是天然支持高精度运算的。Python 也没有 short、long 这样的类型。
Python 中的 float 就是双精度浮点数,没有 double 类型。
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 中''
和 ""
都能表示字符串,没有作区分。
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 + /
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 函数执行会先打印传入的字符串,然后等待用户输入,最后将输入的值返回给变量,这个值是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 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 条件:
循环体
格式:
for 循环变量 in 可迭代对象:
循环体
注意:
打印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 函数名(形参列表):
函数体
return
的值决定。如果你不想return一个值,那也可以不写return语句。如要写一个函数计算给定范围内的整数的和:
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
优点:可以非常明显的告诉程序员,你的参数要传给谁,另外可以无视形参和实参的顺序。
注意:位置参数和关键字参数可以混用,混用时,要求位置参数在前,关键字参数在后。
这部分就类似于其他编程语言中的数组。
列表和元祖,大部分功能都是差不多的,但是有一个功能具有非常明显的区别:
列表是可变的,创建好之后,随时能改
元祖是不可变的,创建好了之后,改不了,要想改只能抛弃旧的,搞个新的。
两种方式:
直接使用字面值来创建
[]
就表示一个空的列表
使用内建函数 list()
来创建
a = []
b = list()
print(type(a))
print(type(b))
# 结果:
#
#
可以在创建列表时,在 []
中指定列表的初始值。
a = [1, 2, 3, 4]
print(a)
# 结果:
# [1, 2, 3, 4]
注意:
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]
注意:
切片操作是一个比较高效的操作,进行切片的时候,只是取出了原有列表中的一个部分,不涉及数据的拷贝
如果给的边界值超出范围,最后的效果和省略边界是一样的
a = [1, 2, 3, 4, 5]
for e in a:
print(e)
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]
a = [1, 2, 3, 4, 5]
i = 0
while i < len(a):
print(a[i])
i += 1
总结:如果不修改列表,则可以采用第一种方式,如果要修改列表,则要采用第二或第三种方式。
append
方法在列表末尾插入元素a = [1, 2, 3, 4, 5]
a.append(6)
a.append('hello')
print(a)
# 结果:[1, 2, 3, 4, 5, 6, 'hello']
注意 append
是需要搭配列表对象来一起使用的,而不是一个独立的函数。
这种要搭配对象来使用的函数,也叫作方法
insert
方法在列表的任意位置插入元素第一个参数表示要插入的位置的下标,第二个参数就是要插入的元素
a = [1, 2, 3, 4, 5]
a.insert(1, 'hello')
print(a)
# 结果:[1, 'hello', 2, 3, 4, 5]
注意:如果下标越界,则新的元素会被插入到列表的末尾。
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
index
方法得到一个元素在列表中的位置的下标a = [1, 2, 3, 4, 5]
print(a.index(3))
# 结果:2
注意:传入的参数必须是列表中存在的元素,否则会抛异常。这一点和 C++ Java 不同,它们都可以返回 -1 表示不存在,Python 的负数下标本身就有意义。
pop
删除列表末尾的元素a = [1, 2, 3, 4, 5]
a.pop()
print(a)
# 结果:[1, 2, 3, 4]
pop
删除任意位置的元素,传一个下标过去。a = [1, 2, 3, 4, 5]
a.pop(1)
print(a)
# 结果:[1, 3, 4, 5]
如果下标越界,则会报错。
remove
方法,按照值来进行删除a = [1, 2, 3, 4, 5]
a.remove(3)
print(a)
# 结果:[1, 2, 4, 5]
如果是不存在的元素,则会报错。
+
进行拼接a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
c = a + b
print(c)
# 结果:[1, 2, 3, 4, 5, 6, 7, 8]
使用 +
拼接,只是针对当前列表的内容生成了一个更大的新的列表,原有列表的内容是不变的。
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
表示什么也没有。
+=
进行拼接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 + b
,a + 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 不能重复。
in
判断 key 是否在字典中。a = {
'apple' : 1,
'banana' : 2
}
print('apple' in a)
print('orange' in a)
# 结果:
# True
# False
注意此处的 in
只能判断 key 是否存在,与 value 无关。
not in
效果和 in
相反。
[]
来根据 key 获取 valuea = {
'apple' : 1,
'banana' : 2
}
print(a['apple'])
# 结果:1
如果在字典中没有相应的 key,程序会抛异常。
对于字典来说,使用 in 或 [] 来获取 value 都是非常高效的操作,因为底层实现是哈希表。
与列表不同,列表使用 in 是比较低效的,使用 [] 是比较高效的。因为底层实现是顺序表。
[]
可以进行新增和修改,这一点和 C++ 是一样的。a = {
'apple' : 1,
'banana' : 2
}
a['apple'] = 3
a['orange'] = 0
print(a)
# 结果:{'apple': 3, 'banana': 2, 'orange': 0}
pop
方法,根据 key 删除键值对a = {
'apple' : 1,
'banana' : 2
}
a.pop('apple')
print(a)
# 结果:{'banana': 2}
这里的循环变量只能拿到字典中的 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 做了特殊处理,能够保证遍历出来的顺序和插入的顺序是一致的。
keys()
获取字典中所有 keyvalues()
获取字典中所有 valueitems()
获取字典中所有键值对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)])
返回的结果看起来像是列表,又不完全是。其实它是一个自定义类型,使用的时候可以把它当做列表。
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 循环使用,这里不多举例。
使用 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')
第一个参数为文件路径,第二个参数为打开方式:
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 方式则不会。
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()
#结果:人生
f = open('d:/Python环境/test.txt', 'r', encoding='utf8')
for line in f:
print(line, end='')
f.close()
#结果:
# 人生苦短
# 我用Python
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 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++ 自己写日期类要简单多了。
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 类型
,这样后面就不需要用 模块名.
的方式来引出类型。
import as
给模块取别名import datetime as dt
date1 = dt.datetime(2019, 12, 8)
date2 = dt.datetime(2022, 9, 4)
print(date2 - date1)
原题链接:剑指 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)
原题链接:796. 旋转字符串 - 力扣(LeetCode)
给定两个字符串,
s
和goal
。如果在若干次旋转操作之后,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
s
和goal
由小写英文字母组成
思路:将两个 s
字符串拼接,看 goal
是否是拼接后的大字符串的子串。
class Solution:
def rotateString(self, s: str, goal: str) -> bool:
if len(s) != len(goal):
return False
return goal in (s + s)
原题链接: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 的标准库已经相当丰富了,但它终究是有限的。而程序员的智慧是无穷无尽的,更加庞大的第三方库,可以说是一个新的世界。
类似于手机的应用商店,Linux 的 yum,
Python 官方也有这样一个网站 pypi,收集了各种第三方库,网站链接:PyPI · The Python Package Index
pip 工具是 Python 内置的一个包管理器,可以直接从 pypi 上下载你想要的第三方库
pip 在安装 Python 时是一起安装好的
具体使用步骤:
点击 PyCharm 下方的终端(Terminal)
在其中输入 pip
会列出一堆帮助信息
如果你输入 pip
提示找不到这个命令,那么可能你在安装 Python 时没有勾选 Add Python 3.10 to PATH 选项,需要手动把 pip 所在路径放到 PATH 环境变量中,或者卸载重装 Python,勾选上述选项。
使用以下命令,安装第三方库
pip install [库名]
安装成功后,便可使用 import
导入使用了。
注意:如果使用 pip 安装完后,在 PyCharm 中仍然提示找不到对应的模块,则检查 Setting -> Project -> Python Interpreter,看当前 Python 解释器设置是否正确(安装了多个版本的 Python,容易出现这种问题)
如图,设置正确后,可以在下面看到已经安装的软件包。
使用搜索引擎可以发现,Python 有一个库叫 qrcode,可以帮助我们实现生成二维码
在 pypi 上搜索 qrcode,了解详情:qrcode · PyPI
从这个官方文档中找到安装指令:
pip install qrcode[pil]
粘贴到 PyCharm 终端。
安装完成后即可进行使用,使用方式在官方文档中也有详细介绍。
这里用字符串简单写生成一个二维码。
import qrcode # 导入模块
img = qrcode.make('我真帅') # 传入一串字符串,img接受文件对象
img.save('qrcode.png') # 将文件保存在当前目录,名为 qrcode.png
运行,然后就可以找到生成的二维码:
读取 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 班的平均分
代码如下:
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