Python学习笔记
一、输入与输出
1. 输出
多种输出方式:
1 | print('hello, python') |
2. 输入
输入使用input,返回值就是输入的内容,参数就是提示语:
1 | str1 = input('Please input:') |
二、数据类型与变量
1. 数据类型
整数
对于大数字可以用_分割,而且十六进制数也支持,例如0xdead_beef,0x100_999_000
整数的大小没有限制
浮点数
对于很大或者很小的浮点数,必须使用科学计数法,把10用e替代,1.23x109就是
1.23e9,或者12.3e8,0.000012可以写成1.2e-5浮点数没有大小限制,但是超过一定范围就直接表示为inf(无穷大)
为什么python中的除法也是精确的?
python中有两种除法:
- / : 这种除法运算结果是浮点数,即使结果刚好整除,
- // : 地板除,两个整数的除法任然是整数,这会只保留整数部分,其余部分抛弃
字符串
字符串以 ’ 或者 “ 括起来,有以下转义字符表示特殊符号
\n 换行 \t 制表符 \ 右斜线\
r’ ’表示不转义,也就是想要输入\就不用输入\
多行内容用
1
2
3
4print('''hello,
world
python
''')布尔值
布尔值与布尔代数完全一致,有True和False两种值
布尔值可以通过以下运算符运算
and 与运算 相当于 &&
or 或运算 相当于 ||
not 非运算 相当于 ~
空值
空值是python中的特殊值,用None表示,None与0不一样,0是有意义的,而None是一个特殊空值
在计算机内部,可以把任意数据类型看作对象,变量就是用来指向这些对象的,
2. 变量
python是动态语言,定义变量类型的时候不需要显式地指定变量类型
1 | a=1 |
3. 常量
常量就是不能改变的变量,通常python中用全部大写的变量名表示常量(只是约定俗成,但是实际并无限制)
三、字符串
总结字符串标志前缀:
1 | r'' # 不转义内容 |
大多数情况下,计算机在存储数据的时候使用UTF-8编码,显示的时候使用Unicode编码
使用记事本时,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件:
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器:

编码与解码
在python3中,字符串以Unicode编码,ord()可以将字符转为整数,chr()将编码转换为对于字符
1 | ord('A') |
以Unicode表示的str通过encode()方法可以编码为指定的bytes
1 | 'aaa'.encode('ascii') |
如果bytes中存在小部分无效字节,可以使用error=’ignore’参数忽略
1 | b'\xe4\xbd\xa0\x87'.decode('utf-8', errors='ignore') |
字符串长度
1 | len('aaa') |
一个中文字符在UTF-8编码之后通常占3字节,1个英文字母占一个字节
为了使Python解释器按UTF-8编码读取,可以在文件头加上:
1 | #!/usr/bin/env python3 # 为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释 |
格式化字符串
方法一
类似于C语言的格式化方式,用%实现
1 | 'hello %s' % ('World') |
如果不知道用什么,可以尝试使用%s,这回将任何类型转换为字符串,同时%%表示一个%字符
方法二 使用format()
1
2
3
4'Hello, {0}! Num is {1}, it\'s {2}'.format('vstral', 19, True)
"Hello, vstral! Num is 19, it's True"
'Hello, {}! Num is {}, it\'s {}'.format('vstral', 19, True)
"Hello, vstral! Num is 19, it's True"方法三 f-string
使用f开头的字符串
1 | print(f'Hello, {name}! Your age is {age}') |
四、list与tuple类型
list
list是python内置的一种数据类型,是一种有序的集合,可以随时添加或删除其中的数据
1 | cls = ['aaa', 'bbb', 'ccc'] |
len()可以获得list元素的个数
1 | len(cls) |
用索引访问对应位置元素,可以使用正负索引
1 | cls[1] |
追加元素到末尾:
1 | cls.append('ddd') |
插入到指定位置
1 | cls.insert(2, 'xxx') |
删除末尾元素/删除指定位置
1 | cls.pop() |
需要替换某个位置的元素可以直接赋值
1 | cls[1] = 'bbb' |
list也可以是一个元素(二维)
1 | cls[2] = ['1', '2', '3'] |
tuple
tuple是另外一种有序列表,叫做元组,与list相似,但是tuple一旦初始化就不能修改,
1 | cla=(1, 2, 3) |
注意,当定义一个元素的tuple时,需要一点添加
1 | a=(2) # ()为运算符 |
当一个tuple有一个list元素会怎么样?
内层的list元素的元素是可以改变的!
这就是指向不变的,tuple指向的是list这个对象,而不是内部的每一个元素
1 | a=(1,2, [3,4]) |
五、条件判断与循环控制
条件判断
与C语言类型,使用if-else进行判断,对于多个判断使用elif
这一块不再学习
语法结构
1 | if <条件判断1>: |
模式匹配
类似于swich case结构,python也有match-case结构
1 | score = 'B' |
复杂条件匹配
通过将一个值增加到一系列值的匹配
1 | age = 15 |
循环
- for-in循环
1 | a = ['aaa', 'bbb', 'ccc'] |
range()函数可以生成一个0-10的整数序列,注意range函数为左闭右开
1 | for i in range(1,10): |
- while循环
while可以一直循环运行,直到遇到退出的指令或者条件不满足
1 | while True: |
- break
break可以使得循环提前退出
1 | n = 1 |
- continue
循环中,可以使用continue语句跳过当前的循环,直接进入下一次循环
1 | n = 1 |
六、dict和set
dict
dict是python内置的字典,在其他语言中也被称为map,使用键值对(Key-Value)储存,有极快的查找速度
1 | d = {'aaa':111, 'bbb':222, 'ccc':333} |
为什么dict查找速度这么快?
在list中,查找原理就是从前往后地依次遍历,list越大,查找越慢
而在dict中,给定一个名字 ’aaa’ ,dict就会在内部计算出这个 ‘aaa’ 对应数据的内存地址,直接取出来
dict查找原理:
基于哈希表,这是一种效率极高的数据结构,平均情况下时间复杂度为O(1)
当执行num[key]的时候,python会调用内置hash(key)计算key得hash值,hash值是一个整数
计算索引:hash通常是一个很大的整数,所以需要通过取模运算来进行映射
假设数组大小为n:(index = hash(key) % n)
检查槽位index位置
- 槽位为空:不存在这个健:抛出KeyError异常
- 槽位不为空:
- 键匹配:存在键值对,而且与查找的key相同(使用
==比较),返回值,查找完成 - 键不匹配:发生hash冲突。即两个不同的健经过hash函数计算后得到相同的数组索引。就需要处理hash冲突(二次探查)
- 键匹配:存在键值对,而且与查找的key相同(使用
判断一个值是否在dict中
使用 in 判断
1
2
3
4
5d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
'Bob' in d
True
'aaa' in d
False使用get方法,如果key不存在,返回None(交互环境不显示结果),或者自定义返回值
1 | d.get('Bob') |
删除一个Key
使用pop方法,对应的Value也会被删除
1 | d.pop('Bob') |
dict的特性
与list相比,有以下特点:
- 查找和插入速度极快,不会随Key增加而变慢
- 需要暂用大量内存,内存浪费多
所以dict是一种空间换时间的方法,**切记dict的Key是不可变对象,**因为dict是根据Key来计算对应Value的存储位置
七、函数
常用函数
| 函数名 | 功能 | |
|---|---|---|
| abs | 返回绝对值 | |
| help | 查看函数作用 | |
| int | 将其他数据类型转换为整数 |
函数的定义
1 | def myFunction(a, b): |
空函数(用来做占位函数,待实现功能)
1 | def nop_func(): |
返回多个值(实际上是一个tuple元组)
1 | import math |
默认参数:当没有设置这个参数值的时候使用默认参数
1 | def power(x, n=2): |
注意点:默认参数必须指向不变对象!
可变参数
顾名思义,可变参数就是传入的参数是可变的,可以是1个,2个…还可以是0个
1 | def calc(*num): |
这里传入函数内部的num是一个tuple类型
当想要将一个list或者一个tuple传入到函数的时候,可以使用*
1 | num = {1, 2, 3, 4} |
关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
1 | def output(name, age, **say): |
注意:这里的say参数表示把函数外部的这个dict的所有传入到了函数内,并且是一份拷贝,所以函数内的改动并不会影响函数外部
八、高级特性
切片
如何只取出lsit或者tuple中的部分元素?
1 | L = ['Michael', 'Sarah', 'Tracy'] |
练习:利用切片和递归去除字符串首尾的空格
1 | def trim(s): |
迭代
如果给定一个list或者tuple,我们就可以通过for循环来遍历这个list或者tuple,这种遍历称为迭代(Iteration)
在python中,迭代通过for-in来完成,C语言的迭代通过遍历每一个下标值来完成,而python的for循环抽象程度高于C的for,因为python的for还可以用在其他可迭代对象上例如dict、字符串等
要想实现类似Java的下标循环,可以使用内置的enumerate将list转换为索引-元素对,这样就可以同时迭代索引和元素本身
1 | a = ['aaa', 'bbb', 'ccc'] |
列表生成式
列表生成式即LIst Comperhensions,是python内置用来创建list的生成式
例如:
- 生成1-9的序列
1 | l = list(range(10)) |
- 生成1^2,2^2,3^2 …
1 | l = [] |
或者
1 | l = [x * x for x in range(10)] |
进一步:
1 | l = [x * x for x in range(10) if x % 2 != 0] |
还可以两层循环,生成全排列
1 | l = [x+y for x in 'abc' for y in 'cde'] |
将list中所有字符转小写
1 | L = ['Hello', 'World', 'IBM', 'Apple'] |
列表生成式中的if-else应用
1 | L = [x if x % 2 == 0 else -x for x in range(10)] |
生成器 generator
通过列表生成式可以直接创建一个列表,但是当我们想要创建一个很大的列表的时候,而且只需要前面几个元素,就会造成很大的内存浪费
所以可以使用生成器,生成器相当于是保存了列表规律的算法,他会循环推演出后续的元素,这样一边循环一边计算
创建一个generator,有很多方法:
- 只需要将一个列表生成式的{ }改为( )
1 | L1 = [i for i in range(10)] |
1 | L2 = (i for i in range(10)) |
当需要创建一些复杂一点的生成器的时候,单单for就很难实现,但是使用函数就会很容易,比如斐波拉契数列
1 | def fb(max): |
这就是定义generator的另一种方法,如果一个函数定义中包含yield关键词,那么这个函数就不再是一个普通函数而是一个generator函数,调用一个generator函数将会返回一个generator
yield函数的执行流程与普通函数不同普通函数是按顺序执行,直到遇到return或者全部执行完毕返回,而yield函数在每次调用next的时候执行,直到遇到yield返回,再次执行时从上一次yield的地方开始
1 | def fb(max): |
注意:调用generator会创建一个generator对象,多次调用generator会创建多个相互独立的generator
在实际使用中一般不会用next来获得下一个返回值,而是使用for循环迭代
但是用for循环调用generator时,发现拿不到return的返回值因为return的返回值在StopIteration错误中
杨辉三角实现:
1 | def triangles(): |
注意一个易错点:返回yield的时候要返回L[:]这是为什么呢?
L[:}指的是对L做一次切片拷贝,拷贝和原来的占用不同的内存,为什么不能直接yield L,因为后面使用的是append,实际上是对同一个list对象的引用,下一次修改的时候会导致前面也被修改