变量以及类型

Python中的数据类型很多,而且也允许我们自定义新的数据类型,先介绍几种常用的数据类型

整型:Python中可以处理任意大小的整数(Python 2.x中有int和long两种类型的整数,但这种区分对Python来说意义不大,因此在Python 3.x中整数只有int这一种了),而且支持二进制(如0b100,换算成十进制是4)、八进制(如0o100,换算成十进制是64)、十进制(100)和十六进制(0x100,换算成十进制是256)的表示法。

浮点型:浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,浮点数除了数学写法(如123.456)之外还支持科学计数法(如1.23456e2)。

字符串型:字符串是以单引号或双引号括起来的任意文本,比如’hello’和"hello",字符串还有原始字符串表示法、字节字符串表示法、Unicode字符串表示法,而且可以书写成多行的形式(用三个单引号或三个双引号开头,三个单引号或三个双引号结尾)。

布尔型:布尔值只有True、False两种值,要么是True,要么是False,在Python中,可以直接用True、False表示布尔值(请注意大小写),也可以通过布尔运算计算出来(例如3 < 5会产生布尔值True,而2 == 1会产生布尔值False)。

复数型:形如3+5j,跟数学上的复数表示一样,唯一不同的是虚部的i换成了j。实际上,这个类型并不常用,了解一下就可以了。

变量命名

  • 硬性规则:
    • 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头。
    • 大小写敏感(大写的a和小写的A是两个不同的变量)。
    • 不要跟关键字(有特殊含义的单词,后面会讲到)和系统保留字(如函数、模块等的名字)冲突。
  • PEP 8要求:
    • 用小写字母拼写,多个单词用下划线连接。
    • 受保护的实例属性用单个下划线开头。
    • 私有的实例属性用两个下划线开头。

变量的使用

在Python中可以使用type()函数对变量的类型进行检查

1
2
3
4
5
6
7
8
9
10
a = 100
b = 12.3
c = 'hello'
d = False
e = 1+2j
print(type(a))#<class 'int'>
print(type(b))#<class 'float'>
print(type(c))#<class 'str'>
print(type(d))#<class 'bool'>
print(type(e))#<class 'complex'>

可以使用Python中内置的函数对变量类型进行转换。

  • int():将一个数值或字符串转换成整数,可以指定进制。
  • float():将一个字符串转换成浮点数。
  • str():将指定的对象转换成字符串形式,可以指定编码。
  • chr():将整数转换成该编码对应的字符串(一个字符)。
  • ord():将字符串(一个字符)转换成对应的编码(整数)。

使用input()函数获取键盘输入(字符串类型)

通过键盘输入两个整数来实现对两个整数的算术运算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
使用int()函数将输入的字符串转换成整数
使用print()函数输出带占位符的字符串
@author: zy
@data: 2022/9/1 13:20
"""
f = int(input('a = '))#a = 仅作显示不运算
g = int(input('b = '))#b = 仅作显示不运算
print('%d + %d = %d' % (f, g, f + g))
print('%d - %d = %d' % (f, g, f - g))
print('%d * %d = %d' % (f, g, f * g))
print('%d / %d = %f' % (f, g, f / g))
print('%d // %d = %d' % (f, g, f // g))
print('%d %% %d = %d' % (f, g, f % g))
print('%d ** %d = %d' % (f, g, f ** g))

上面的print函数中输出的字符串使用了占位符语法,其中%d是整数的占位符,%f是小数的占位符,%.1f表示保留一位小数,%%表示百分号(因为百分号代表了占位符,所以带占位符的字符串中要表示百分号必须写成%%),字符串之后的%后面跟的变量值会替换掉占位符然后输出到终端中,运行上面的程序,看看程序执行结果就明白啦。

运算符

Python支持多种运算符,下表大致按照优先级从高到低的顺序列出了所有的运算符,运算符的优先级指的是多个运算符同时出现时,先做什么运算然后再做什么运算。

运算符描述
[] [:]下标,切片
**指数
~ + -按位取反, 正负号
* / % //乘,除,模,整除
+ -加,减
>> <<右移,左移
&按位与
^ |按位异或,按位或
<= < > >=小于等于,小于,大于,大于等于
== !=等于,不等于
is is not身份运算符
in not in成员运算符
not or and逻辑运算符
= += -= *= /= %= //= **= &= | = ^= >>= <<=

在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。

赋值运算符=应该是最为常见的运算符,它的作用是将右边的值赋给左边的变量。

比较运算符有的地方也称为关系运算符,包括==、!=、<、>、<=、>=,我相信没有什么好解释的,大家一看就能懂,唯一需要提醒的是比较相等用的是==,请注意这个地方是两个等号,因为=是赋值运算符,我们在上面刚刚讲到过,==才是比较相等的比较运算符。比较运算符会产生布尔值,要么是True要么是False。

逻辑运算符有三个,分别是and、or和not。and字面意思是“而且”,所以and运算符会连接两个布尔值,如果两个布尔值都是True,那么运算的结果就是True;左右两边的布尔值有一个是False,最终的运算结果就是False。相信大家已经想到了,如果and左边的布尔值是False,不管右边的布尔值是什么,最终的结果都是False,所以在做运算的时候右边的值会被跳过(短路处理),这也就意味着在and运算符左边为False的情况下,右边的表达式根本不会执行。or字面意思是“或者”,所以or运算符也会连接两个布尔值,如果两个布尔值有任意一个是True,那么最终的结果就是True。当然,or运算符也是有短路功能的,在它左边的布尔值为True的情况下,右边的表达式根本不会执行。not运算符的后面会跟上一个布尔值,它的作用是得到与该布尔值相反的值,也就是说,后面的布尔值如果是True运算结果就是False,而后面的布尔值如果是False则运算结果就是True。

分支结构

if语句的使用

在Python中,要构造分支结构可以使用if、elif和else关键字。。所谓关键字就是有特殊含义的单词,像if和else就是专门用于构造分支结构的关键字,很显然你不能够使用它作为变量名(事实上,用作其他的标识符也是不可以)。

需要说明的是和C/C++、Java等语言不同,Python中没有用花括号来构造代码块而是使用了缩进的方式来表示代码的层次结构,如果if条件成立的情况下需要执行多条语句,只要保持多条语句具有相同的缩进就可以了。换句话说连续的代码如果又保持了相同的缩进那么它们属于同一个代码块,相当于是一个执行的整体。缩进可以使用任意数量的空格,但通常使用4个空格,建议大家不要使用制表键或者设置你的代码编辑工具自动将制表键变成4个空格。

当然如果要构造出更多的分支,可以使用if…elif…else…结构或者嵌套的if…else…结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
"""
分支
x+1,x>0
f(x){ x, x=0
x-1,x<0

@author: zy
@data: 2022/9/1 13:41
"""
a = float(input())
if a>0:
print(a+1)
else:
if a==0:
print(a)
else:
print(a-1)
#------------------------
if a>0:
print(a+1)
elif a==0:
print(a)
else:print(a-1)

循环结构

for-in循环

如果明确的知道循环执行的次数或者要对一个容器进行迭代(后面会讲到),那么我们推荐使用for-in循环

1
2
3
4
5
6
7
8
9
"""
使用for...in实现1-100求和
@author: zy
@data: 2022/9/1 14:32
"""
sum = 0
for i in range(101):
sum += i
print(sum)

需要说明的是上面代码中的range(1, 101)可以用来构造一个从1到100的范围,当我们把这样一个范围放到for-in循环中,就可以通过前面的循环变量x依次取出从1到100的整数。当然,range的用法非常灵活。

  • range(101):可以用来产生0到100范围的整数,需要注意的是取不到101。
  • range(1, 101):可以用来产生1到100范围的整数,相当于前面是闭区间后面是开区间。
  • range(1, 101, 2):可以用来产生1到100的奇数,其中2是步长,即每次数值递增的值。
  • range(100, 0, -2):可以用来产生100到1的偶数,其中-2是步长,即每次数字递减的值。

知道了这一点,我们可以用下面的代码来实现1~100之间的偶数求和。

1
2
3
4
5
6
7
8
9
"""
使用for...in实现1-100求和
@author: zy
@data: 2022/9/1 14:32
"""
sum = 0
for i in range(1,101,2):
sum += i
print(sum)

当然,也可以通过在循环中使用分支结构的方式来实现相同的功能,

1
2
3
4
5
6
7
8
9
10
"""
使用for...in实现1-100求和
@author: zy
@data: 2022/9/1 14:32
"""
sum = 0
for i in range(1,101):
if i % 2==0:
sum += i
print(sum)

说明:相较于上面直接跳过奇数的做法,下面这种做法很明显并不是很好的选择。

while循环

如果要构造不知道具体循环次数的循环结构,我们推荐使用while循环。while循环通过一个能够产生或转换出bool值的表达式来控制循环,表达式的值为True则继续循环;表达式的值为False则结束循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import random#导入产生随机数的包
"""

猜大小
@author: zy
@data: 2022/9/1 14:44
"""
ans = random.randint(1,100)
counter = 0
while True:
counter +=1
number = int(input())
if number < ans:
print("dayidian")
elif number > ans:
print("xiaoydiann")
else:
print("good")
break
print('一共猜了%d次'%counter)

上面的代码中使用了break关键字来提前终止循环,需要注意的是break只能终止它所在的那个循环,这一点在使用嵌套的循环结构(下面会讲到)需要引起注意。除了break之外,还有另一个关键字是continue,它可以用来放弃本次循环后续的代码直接让循环进入下一轮。

函数

要写出高质量的代码首先要解决的就是重复代码的问题对于重复的问题我们可以把代码封装在一个函数中当使用的时候调用这个函数

1
Python中可以在函数内部再定义函数

定义函数

在Python中可以使用def关键字来定义函数,命名规则跟变量的命名规则是一致的。

定义一个求阶乘的函数

1
2
3
4
5
6
7
8
#求阶乘
def jie(num):
res = 1
for i in range(1,num+1):
res *= i
return res
n = int(input("n="))
print(jie(n))

说明: Python的math模块中其实已经有一个名为factorial函数实现了阶乘运算,事实上求阶乘并不用自己定义函数。实际开发中并不建议做这种低级的重复劳动

1
2
3
4
5
6
7
8
9
10
import math
#求阶乘
def jie(num):
res = 1
for i in range(1,num+1):
res *= i
return res
n = int(input("n="))
print(jie(n))
print(math.factorial(n))

函数的参数

在Python中,函数的参数可以有默认值,也支持使用可变参数,所以Python并不需要像其他语言一样支持函数的重载,因为我们在定义一个函数的时候可以让它有多种不同的使用方式

1
2
3
4
5
6
7
8
9
10
11
'''
如果没有指定参数那么使用默认值
'''
def roll(x=2):
sum=0
for i in range(x+1):
sum = sum+i
return sum
print(roll())
print(roll(2))
print(roll(5))

我们给上面两个函数的参数都设定了默认值,这也就意味着如果在调用函数的时候如果没有传入对应参数的值时将使用该参数的默认值

1
2
3
4
5
6
7
8
9
10
def add(*s):#在参数名前面的*表示s是一个可变参数
sum = 0
for i in s:
sum+=i
return sum

# 在调用add函数时可以传入0个或多个参数
print(add())
print(add(1))
print(add(1,2,3))

用模块管理函数

同一个.py文件中定义了两个同名函数,由于Python没有函数重载的概念,那么后面的定义会覆盖之前的定义,也就意味着两个函数同名函数实际上只有一个是存在的。

1
2
3
4
5
6
7
8
9
def foo():
print('hello,')


def foo():
print('world!')


foo()#world!

Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过import关键字导入指定的模块就可以区分到底要使用的是哪个模块中的foo函数

1
2
3
4
5
6
7
8
9
10
11
demo1.py
def foo():
print("hello,")
demo2.py
def foo():
print("world!")
demo3.py
from demo1 import foo
foo()#hello,
from demo2 import foo
foo()#world!

也可以按照如下所示的方式来区分到底要使用哪一个foo函数

1
2
3
4
import demo1 as d1
import demo2 as d2
d1.foo()
d2.foo()

但如果是这样的话,下边导入的会覆盖上边

1
2
3
4
from demo1 import foo
from demo2 import foo

foo()#world!

需要说明的是,如果我们导入的模块除了定义函数之外还有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码,事实上我们可能并不希望如此,因此如果我们在模块中编写了执行代码,最好是将这些执行代码放入如下所示的条件中,这样的话除非直接运行该模块,if条件下的这些代码是不会执行的,因为只有直接执行的模块的名字才是"main"。可以参考下方连接

Python中if name == ‘main‘:的作用和原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
demo3.py
def foo():
print("1")


def bar():
print("2")


# __name__是Python中一个隐含的变量它代表了模块的名字
# 只有被Python解释器直接执行的模块的名字才是__main__
foo()
if __name__ == '__main__':
print('call bar()')
bar()

当直接运行时

img

当导入demo4中运行时

img

变量的作用域

函数内部的赋值会覆盖全局的赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def foo():
a = 200
print(a) # 200


if __name__ == '__main__':
a = 100
foo()
print(a) # 100
在调用foo函数后,我们发现a的值仍然是100,这是因为当我们在函数foo中写a = 200的时候,是重新定义了一个名字为a的局部变量,它跟全局作用域的a并不是同一个变量,因为局部作用域中有了自己的变量a,因此foo函数不再搜索全局作用域中的a。如果我们希望在foo函数中修改全局作用域中的a
def foo():
global a
a = 200
print(a) # 200


if __name__ == '__main__':
a = 100
foo()
print(a) # 200

我们可以使用global关键字来指示foo函数中的变量a来自于全局作用域,如果全局作用域中没有a,就会定义变量a并将其置于全局作用域。同理,如果我们希望函数内部的函数能够修改嵌套作用域中的变量,可以使用nonlocal关键字来指示变量来自于嵌套作用域

在实际开发中,我们应该尽量减少对全局变量的使用,因为全局变量的作用域和影响过于广泛,可能会发生意料之外的修改和使用,除此之外全局变量比局部变量拥有更长的生命周期,可能导致对象占用的内存长时间无法被垃圾回收。事实上,减少对全局变量的使用,也是降低代码之间耦合度的一个重要举措。

list

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
name=['1','2','3']
print(name)
#插入
name.append('4')#插入末尾
print(name)
name.append(4)
print(name)
name.insert(2,'0')#插入指定项
#将0插入到第2项
print(name)
#删除
del name[len(name)-1]
print(name)
name.append('4');
name.pop();#删除末尾元素
print(name)
del name[2]
del name[3]
print(name)
a = '2' in name
print(a)
a = '4' in name
print(a)
for i in [1,2,3]:print(i)
print(max(name))
print(min(name))
print("------------------")
for i in name:print(i)
name.append('4')
print('--------')
for i in name:print(i)
name.pop(2)#删除2处元素
print("--------------")
for i in name:print(i)
name[2]='3'
print("----------------")
for i in name:print(i)
print('-----------')
#list 里面的元素的数据类型是可以不同的,并且list里边还可以是list
newname= [['VIP用户',11111],['twowater',22222],['三点水',33333]]
print(newname)
newname=[['1a','1'],['2a','2'],['3a','3']]
print(newname[1][0])#第一个表示第一个括号第几个第二个参数表示里边的第几个
name.extend(newname)
print(name)
name.append('1')
name.remove('1')#移除列表中的某个元素第一个匹配结果
print(newname)
newname.clear()
print(newname)
print(name.count('2'))#查询字符出现次数
print(name)
name.reverse()
print(name)# 将列表中的元素倒叙,在原列表进行操作,不返回新的列表

# List (列表)函数&方法

# len(list) 列表元素个数
# max(list) 返回列表元素最大值
# min(list) 返回列表元素最小值
# list(seq) 将元组转换为列表
# list.append(obj) 在列表末尾添加新的对象
# list.count(obj) 统计某个元素在列表中出现的次数
# list.extend(seq) 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
# list.index(obj) 从列表中找出某个值第一个匹配项的索引位置
# list.insert(index, obj) 将对象插入列表
# list.pop(obj=list[-1]) 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
# list.remove(obj) 移除列表中的一个元素(参数是列表中元素),并且不返回任何值
# list.reverse() 反向列表中元素
# list.sort([func]) 对原列表进行排序
# List(列表)运算符
# 列表对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表。
#
# Python 表达式 结果 描述
# len([1, 2, 3]) 3 计算元素个数
# [1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] 组合
# ['Hi!'] * 4 ['Hi!', 'Hi!', 'Hi!', 'Hi!'] 复制
# 3 in [1, 2, 3] True 元素是否存在于列表中
# for x in [1, 2, 3]: print x, 1 2 3 迭代