python基础及标准库

python基础部分备忘录。

python 基础

python 是一门解释型语言,无需编译。

数据类型

不可变对象:数值(Numbers),字符串 (String) , 元组 (Tuple) ,逻辑值 (Bool)

可变对象:列表(List),字典(Dictionary),集合(Set)

None

None是Python的空值类型。如果一个函数没有明确的返回值,就会默认返回None。

判断是否为空值,要用 is(内存地址是否相同)

1
2
3
4
In [37]: a = None

In [38]: a is None
Out[38]: True

None也常常作为函数的默认参数:

1
2
3
4
5
6
7
8
9
In [39]: def test(a,b,c=None):
...: result = a + b

...: if c is not None:
...: result = result * c

...: return result
...:

另外,None 不仅是一个保留字,还是唯一的 NoneType 的实例:

1
2
3
In [40]: type(None)
Out[40]: NoneType

变量赋值

在 python 中,变量名称和变量本身的值是一种引用(指针)的关系,我个人就是理解为标签和人的关系,每个人均至少需要贴一个标签,一个人身上可以有多个标签,赋值的过程就是将左侧的标签对应上右侧的值。

因此对于不可变对象,如果修改某个变量的值(因为这个过程是新建了一个值),不会影响其它变量,以字符串举例如下:

1
2
3
4
5
6
7
8
a='ABC'
b=a
a='XYZ'
# 问此时b是什么?
# 咋一看,b=a,此时a='XYZ',b也应该是'XYZ'
# 实际上不是,变量的名称和值是映射的关系,
# 这里的逻辑是首先内存中创建了一个值’ABC',变量a 映射到了ABC, 之后变量b也映射到了ABC
# 最后将a又映射到XYZ,过程见下图

1

但是,对于可变对象,则相反。举个例子,下面这种形式b也会改变(因为列表是可变对象,这里是修改了原列表

1
2
3
a=[1,2]
b=a
a.append(3) #b一样会改变

如果是 a=[1,2] , b=[1,2],这个时候修改a,对b就没有任何影响了,因为这时候是创建了两个列表对象。

函数中修改全局变量(变量作用域)

可变对象:当函数内修改同名变量时,函数外的同名变量也会随之改变,所以使用修改可变对象没有作用域的概念

不可变对象:当函数内修改同名变量时,会先复制过来再修改,函数外部的变量不变。(如果一定要修改,可以使用 global x,x为全局变量名)

1
2
3
4
5
6
7
8
9
10
11
12
13
def test(a,b):
a=a+1
b.append(13)
print('inner a: {}'.format(a))
print('inner b: {}'.format(b))

a=5
b=[10,11]

test(a,b)

print('outer a: {}'.format(a))
print('outer b: {}'.format(b))

运行结果如下:

1
2
3
4
inner a: 6
inner b: [10, 11, 13]
outer a: 5
outer b: [10, 11, 13]

注意如果再次运行 test(a,b),那么列表 b 中还会新增一个元素 13 ,为了避免出现问题,避免使用可变对象作为函数参数。我们可以在函数内部中定义新的局部可变对象,也可以直接读取或修改全局变量中的可变对象。

变量查找顺序

函数内部 – 父函数(如果有)-- 全局 – python 内置变量

UnboundLocalError : 函数先调用,后修改同名全局变量。

函数调用和修改同名全局变量(针对不可变变量)

  1. 光调用 : python 认为是全局变量,没有问题

  2. 光修改: python 认为是局部变量(只是和全局变量同名),也没有问题

  3. 调用+修改 ,分为两种情况

    3.1 先改,后调用:python 认为是局部变量,python 认为是局部变量,没有问题

    3.2 先调用,后改:python 认为是修改全局变量,报错

其实不用那么麻烦,命名的时候注意一点,避免函数内的变量名和全局变量同名就好了。

函数返回值

  • 无 return : 返回值均为 None。 例如 a = function() , a 均为 None
  • 有 return : return 一旦执行,函数就会终止。

字符串操作

字符串查找

  • str.find() : 找到目标时返回该字符的索引位置;没找到返回-1
  • str.index() : 找到目标时返回该字符的索引位置;没找到报错

字符串分割

  • str.patition() : 将字符串按找到的第一个关键字分割为三段(只分割一次),形成一个元组,内容包括关键字前、关键字本身、关键字后
  • str.split() : 以关键字为分割点进行分割(多次分割,且结果中不包含关键字),生成一个列表。
  • str.strip() : 移除字符串头尾指定的字符(默认是空格)

字符串运算符

  • + : 连接字符串
  • * : 重复,比如 a=“hello” , a*2 为 “hellohello"
  • [startnum:endnum] : 获取子字符串
  • in : 判断子字符串是否在大字符串中
  • not in
  • “”" “”" : 允许跨行
  • str.lower() : 全部转为小写
  • str.upper() : 全部转为大写
  • str.replace(old, new) : 替换字符串

break

break 与 continue

  • break 是直接跳出循环,包括该循环的 else 。如果break 在内层循环,则会跳出内层循环,但是不影响外层循环和外层循环的 else 部分
  • continue : 准确地说,continue 是指不执行循环体中continue 语句之后的代码,重新回到循环开始部分,直接进入下一次循环。

break 与 else

for else 语句 与 while else 语句 中如果存在 if break 语句,else 语句只有在满足下面两个条件才会运行

  • for/while 执行完
  • 整个循环过程中没有触发 break

所有逻辑值

python 进行逻辑判断的时候,认为:

  • True : 所有非空的量(非空字符串,非空列表);非0的数字
  • False : 0,None, False, 任意为空的量

递归函数

递归函数有两点:

  1. 自己引用自己
  2. 有一个明确的递归结束条件(不然就成死循环了)

例子一,目录遍历(或得一个目录所有文件/文件夹的路径,包括子目录,子子目录……)

1
2
3
4
5
6
7
8
9
import os
m = []
def dirlist(path):
file_list = os.listdir(path)
for i in file_list:
file_path = os.path.join(path,i)
m.append(file_path)
if os.path.isdir(file_path):
dirlist(file_path) #引用自身

例子二,求阶乘 n!

1
2
3
4
5
def f(n):
if n == 1:
return 1
return n*f(n-1)
#这里不用写else,因为python 只要运行了一个return,程序自动退出。但是我觉得还是写上 else,逻辑更严密,提高可读性

切片

格式如下

1
sequence[start_index:end_index:step]
  • start_index : 默认为0
  • end_index : 默认为 len(sequence)
  • step : 步长,默认为1(正索引),-1 表示负索引

注意:这里的正索引指的是方向从左到右,而不是单纯的索引号的增加。

所以 [:-1] 表示从第一个位置,一直向右,读到倒数第二个位置(即不要最后一个)。[-2:] 表示提取最后两个位置

列表排序

简单列表

1
2
3
a=[3,1,2]
b=sorted(a,reverse=True/False)
a.sort(reverse=True/False)

复杂列表(例如列表的每个元素又是一个长度为2的列表)

下面这两种方式的区别在于:如果列表的元素是字符类型,第一种按照 ASCII 码顺序,先比第一个字符,如果相同再比第二个字符,依次类推;第二种才是按照数字大小。

1
2
m2 = sorted(m1, key =lambda x:x[1], reverse=True/False)
m2 = sorted(m1, key =lambda x:float(x[1]), reverse=True/False)

多个条件

1
dup_sort_list = sorted(dup_list, key = lambda s:(float(s[5]),s[0])) #不一致率从小到大

删除对象

  • del a : 只是删除对象的一个引用

python 标准库

https://docs.python.org/zh-cn/3/library/index.html

内置函数

enumerate(iterable, start=0)

返回一个枚举对象。

1
2
3
4
5
6
7
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> enumerate(seasons)
<enumerate object at 0x2ba732af1c40>
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]

等价于:

1
2
3
4
5
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1

zip(*iterables)

创建一个聚合了来自每个可迭代对象中的元素的元组的迭代器。

**当所输入可迭代对象中最短的一个被耗尽时,迭代器将停止迭代。 **

相当于:(没看懂)

1
2
3
4
5
6
7
8
9
10
11
12
def zip(*iterables):
# zip('ABCD', 'xy') --> Ax By
sentinel = object()
iterators = [iter(it) for it in iterables]
while iterators:
result = []
for it in iterators:
elem = next(it, sentinel)
if elem is sentinel:
return
result.append(elem)
yield tuple(result)
1
2
3
4
5
6
7
8
9
10
11
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> list(zipped)
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(*zip(x, y))) #返回原来的两个列表
[(1, 2, 3), (4, 5, 6)]
>>> x2, y2 = zip(*zip(x, y))
>>> x == list(x2) and y == list(y2)
True

zip 也可以用于使用两个列表构建字典

1
2
3
4
5
In [73]: mapping = dict(zip(range(5),reversed(range(5))))

In [74]: mapping
Out[74]: {0: 4, 1: 3, 2: 2, 3: 1, 4: 0}

内置类型

数字类型 — int, float, complex

运算 结果 注释 完整文档
x // y xy 的商数(整除) 整除
x % y x / y 的余数 (2)
abs(x) x 的绝对值或大小 abs()
divmod(x, y) (x // y, x % y) (2) divmod()
pow(x, y) xy 次幂 (5) pow()
x ** y xy 次幂 (5)

注释:

  1. 也称为整数除法。 结果值是一个整数,但结果的类型不一定是 int。 运算结果总是向负无穷的方向舍入: 1//20, (-1)//2-1, 1//(-2)-1(-1)//(-2)0

  2. 从浮点数转换为整数会被舍入;请参阅 math.floor()math.ceil() 函数查看转换的完整定义。

    1
    2
    >>> int(1.9)
    1
  3. float 也接受字符串 “nan” 和附带可选前缀 “+” 或 “-” 的 “inf” 分别表示非数字 (NaN) 以及正或负无穷。

  4. Python 将 pow(0, 0)0 ** 0 定义为 1,这是编程语言的普遍做法。

浮点型类型还包括以下运算。

运算 结果
math.trunc(x) x 截断为 Integral
round(x[, n]) x 舍入到 n 位小数,半数值会舍入到偶数。 如果省略 n,则默认为 0。
math.floor(x) <= x 的最大 Integral
math.ceil(x) >= x 的最小 Integral

序列类型 – list, tuple, range

通用序列操作

此表按优先级升序列出了序列操作。 在表格中,st 是具有相同类型的序列,n, i, jk 是整数而 x 是任何满足 s 所规定的类型和值限制的任意对象。

运算 结果 注释
x in s 如果 s 中的某项等于 x 则结果为 True,否则为 False (1)
x not in s 如果 s 中的某项等于 x 则结果为 False,否则为 True (1)
s + t st 相拼接 (6)(7)
s * nn * s 相当于 s 与自身进行 n 次拼接 (2)(7)
s[i] s 的第 i 项,起始为 0 (3)
s[i:j] sij 的切片 (3)(4)
s[i:j:k] sij 步长为 k 的切片 (3)(5)
len(s) s 的长度
min(s) s 的最小项
max(s) s 的最大项
s.index(x[, i[, j]]) xs 中首次出现项的索引号(索引号在 i 或其后且在 j 之前) (8)
s.count(x) xs 中出现的总次数
  1. 注意:这里的* 号并不是拷贝,而是多次引用。例如下式,由于是引用,修改任一元素都是对这一个空列表的修改。

    1
    2
    3
    4
    5
    6
    >>> lists = [[]] * 3
    >>> lists
    [[], [], []]
    >>> lists[0].append(3)
    >>> lists
    [[3], [3], [3]]

    你可以用以下方式创建以不同列表为元素的列表:

    1
    2
    3
    4
    5
    6
    >>> lists = [[] for i in range(3)]
    >>> lists[0].append(3)
    >>> lists[1].append(5)
    >>> lists[2].append(7)
    >>> lists
    [[3], [5], [7]]

    但是如果是可变对象,则没有影响

    1
    2
    3
    4
    5
    6
    In [16]: a = [0] * 3

    In [17]: a[0] = 1

    In [18]: a
    Out[18]: [1, 0, 0]
  2. 切片中的 i 或 j 如果为负值, 索引号会被替换为 len(s) + ilen(s) + j

    例如 a[-2:] 中的 -2 会被替换为 len(a)-2

    1
    2
    3
    4
    5
    6
    >>> a=list(range(1,11))
    >>> a
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> a[-2:]
    >>> a[len(a)-2:]
    [9, 10]
  3. s 从i 到 j 的切片需要满足i <j。如果 i 或 j 大于 len(s) ,则使用 len(s)。 如果 i 被省略或为 None,则使用 0。 如果 j 被省略或为 None,则使用 len(s)。 如果 i 大于等于 j,则切片为空。

  4. 拼接不可变序列总是会生成新的对象。 这意味着通过重复拼接来构建序列的运行时开销将会基于序列总长度的乘方。 想要获得线性的运行时开销,你必须改用下列替代方案之一

    这里主要讨论拼接字符串。当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的, 因为加号连接会引起内存复制以及垃圾回收操作。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2024 Vincere Zhou
  • 访问人数: | 浏览次数:

请我喝杯茶吧~

支付宝
微信