小甲鱼零基础Py学习记录

精简记录视频的内容,详细文字内容在论坛

视频地址:https://www.bilibili.com/video/BV1c4411e77t

Py官网:https://www.python.org/

PyPI:https://pypi.org/

小甲鱼的FishC论坛:https://fishc.com.cn/ (需要注册)

P2

IDLE分交互模式和编辑器模式

IDLE交互模式输入

import this

会输出 “The Zen of Python”

P3

File -> New File 打开编辑器模式

祖传猜数字老游戏:

""" 祖传猜数字老游戏 """

temp = input()
guess = int(temp)

if guess == 8:
    print('√')
else:
    print('×')

print('游戏结束')

保存后F5直接运行

注意检查英文标点、tab缩进、函数拼写

PEP8编码风格指南:原文 FishC汉化版

BIF (Built-in Functions,内置函数)

IDLE交互模式输入

dir(__builtins__)

可以查看Python所有内置函数

P4 & P5

变量 (variable)

x = 3

= 进行赋值操作,x为变量名,直接用变量名进行访问,如

print(x) # 3

变量的值取决于最后一次赋值。

(1)变量名不能以数字开头 (2)变量名区分大小写 (3)变量名可以用汉字

不同变量的值可以传递

x = 3
y = 5
y = x
print(y) # 3
x = y = 3
print(x, y) # 3 3

交换两个变量的值

# 传统
x = 5
y = 3
z = x # 中间变量
x = y
y = z
print(x, y) # 3 5

# Py
x = 5
y = 3
x, y = y, x
print(x, y) # 3 5

字符串 (string)

用单引号(‘‘)和双引号(““)括起,三个引号对长字符串 (single/double/triple quoted)

IDLE交互模式按 Alt + P 上一句

反斜杠 (\) 转义

原始字符串 (raw strings)

x = r'D:\111\222' # r -> raw

一对引号打印多行字符串

print('1111\n\
1111\n\
1111') # 换行符后再加一个\

长字符串打印

print('''1111
1111
1111''')

字符串加法乘法

+ 拼接字符串,***** 重复字符串

'520' + '1314' # 5201314
'520\n' * 3000 # 520 x3000行

P6

条件分支语句

if x == 1:
    pass
elif x == 2:
    pass
else:
    pass

比较运算符:

> 大于
>= 大于等于
< 小于
<= 小于等于
== 等于
!= 不等于

返回 True/False

P7 & P8

改进祖传老游戏

""" 改进祖传猜数字老游戏 """
import random

counts = 3 # 次数
answer = random.randint(1, 10)

while counts > 0:
    temp = input()
    guess = int(temp)

    if guess == answer:
        print('√')
        break
    elif guess > answer:
        print('大了')
    else:
        print('小了')
    
    counts -= 1

print('游戏结束')

IDLE按F1可以打开英文文档

重现伪随机数

import random

c = 5
x = random.getstate() # 获取生成器状态
while c > 0:
    print(random.randint(1, 10))
    c -= 1

c = 5
random.setstate(x)
while c > 0:
    print(random.randint(1, 10))
    c -= 1

P9 & P10

数字类型:整数 (integers)、浮点数 (floating point numbers)、复数 (complex numbers)

由于采用IEEE754标准存储浮点数,浮点数计算会存在误差。

0.3 == 0.1 + 0.2 # False
0.3 < 0.1 + 0.2 # True 0.300000....0004
import decimal
a = decimal.Decimal('0.1')
b = decimal.Decimal('0.2')
a + b # 0.3
c = decimal.Decimal('0.3')
c == a + b # True

E计法 (科学计数法)

0.00005 # 5e-05 5*10^-5
# 复数
x = 1 + 2j # 实部虚部通过浮点数存储
x.real # 1.0
x.imag # 2.0

x // y:地板除,除法的结果向下取整,取比结果小的整数

3 // 2 # 1
-3 // 2 # -2

x % y:求余数

x == (x // y) * y + (x % y)

abs(x) x的绝对值,复数返回模
int(x) 将x转换为整数,截去小数部分
float(x) 将x转换为浮点数
complex(re, im) 返回一个复数
c.conjugate() 返回c的共轭复数
divmod(x, y) 返回(x // y, x % y)
pow(x, y) 计算x的y次方
x ** y 计算x的y次方

pow(x, y, z):求x的y次方除z的余数

pow(2, 3, 5) # 3
2 ** 3 % 5 # 3

P11 & P12

布尔类型

bool()

结果为False的情况:

1 == True
0 == False
True + False # 1
True - False # 1
True * False # 0
True / False # 报错,除数不能为0

布尔类型就是特殊的整数类型

逻辑运算符

逻辑运算也叫布尔运算

与或非 and, or, not

支持真值测试

3 and 4 # 4, 都非0时返回后一个非0值
4 or 5 # 4, 都非0时返回第一个非0值

短路逻辑 (short-circuit logic)

(not 1) or (0 and 1) or (3 and 4) or (5 and 6) or (7 and 8 and 9) # 4
0 or 0 or 4 or 6 or 9 # 0 or 4 -> 4, 4 or 6 or 9不运算

从左往右,第一个操作数的值无法确定逻辑运算的结果才对第二个操作数进行求值

运算符优先级

not 1 or 0 and 1 or 3 and 4 or 5 and 6 or 7 and 8 and 9 # 4
# 0 or 0 or 4 or 6 or 9

not > and > or

算术运算 > 比较运算 > 逻辑运算

P15~P19

分支语句

if condition:
    pass
elif condition:
    pass
else:
    pass
# 条件表达式
条件成立执行 if condition else 条件不成立执行

a = 3
b = 5
small = a if a < b else b # 3
score = 66
level = ('D' if 0 <= score < 60 else
		'C' if 60 <= score < 80 else
        'B' if 80 <= score < 90 else
        'A' if 90 <= socre < 100 else
        'S' if score == 100 else
        '范围0~100') # 小括号表示多行为一句代码
print(level) # C

分支嵌套

循环语句

py有 whilefor 两种循环语句

while condition:
    statement()

跳出循环

break

break 语句退出循环,退出时不会执行break后面的语句

continue

跳过本轮循环,条件满足开始下一轮循环

i = 0
while i < 10:
    i += 1
    if i % 2 == 0:
        continue
    print(i) # 1 3 5 7 9

break 和 continue 均只作用于一层循环体

else

循环条件不为真时执行(循环结束时执行)

day = 1
while day <= 7:
    answer = input('今天有好好学习吗?')
    if answer != '有':
        break
    day += 1
else:
    print('Bravo!')

循环嵌套

# 九九乘法表参考
a = 1
while a <= 9:
    b = 1
    while b <= a:
        if b == a:
            print(str(b) + '×' + str(a) + '=' + str(b * a))
        else:
            print(str(b) + '×' + str(a) + '=' + str(b * a), end = '  ')
        b += 1
    a += 1

for 变量 in 可迭代对象:
	statement()
sum = 0
for each in range(1, 1000000 + 1): # 左闭右开
    sum += each
print(sum)
# range用法
## range(stop)
for i in range(10):
    print(i) # 0 1 2 3 4 5 6 7 8 9
## range(start, stop)
for i in range(5, 10):
    print(i) # 5 6 7 8 9
## range(start, stop, step)
for i in range(1, 10, 2):
    print(i) # 1 3 5 7 9
for i in range(10, 5, -2):
    print(i) # 10 8 6

搭配break continue语句,找出10以内的素数

for n in range(2, 10):
    for m in range(2, n): # n == 2时循环会直接结束
        if n % m == 0:
            break
    else:
        print(n, '是一个素数')

P20~P26

[] 创建列表,可以包含不同类型的元素

序列 在py中是最常见的数据结构,字符串、列表都是序列

通过下标索引访问元素:列表[下标]

访问最后一个元素:列表[-1] (逆序访问-1, -2…)

列表切割

列表[:3]

列表[3:]

列表[start:stop:step] 对整个列表 start 和 stop 可省略,列表[::step]

倒序输出可以:列表[::-1]

增删改查

列表.append() 追加一个对象

列表.extend() 追加一个可迭代对象(必须)

# 切片添加
s = [1, 2, 3, 4, 5]
s[len(s):] = [6]
# s.extend([6])
print(s) # [1, 2, 3, 4, 5, 6]

列表插入元素

s = [1, 3, 4, 5]
s.insert(1, 2)
# 插入开头 s.insert(0, x)
# 插入末尾 s.insert(len(s), x)
print(s) # [1, 2, 3, 4, 5]

列表删除元素

# 删除已知元素 - remove方法
s = [1, 2, 3, 14, 4]
s.remove(14)
print(s) # [1, 2, 3, 4]
# 删除未知元素 - pop方法
s = [1, 2, 3, 14, 4]
s.pop(3)
print(s) # [1, 2, 3, 4]
# 清空
s.clear()

替换

# 下标索引赋值单个替换
s = [1, 2, 3, 44, 5]
s[3] = 4
print(s) # [1, 2, 3, 4, 5]
# 切片替换
s = [1, 2, 3542, 44, 554]
s[2:] = [3, 4, 5]
print(s) # [1, 2, 3, 4, 5]

替换分两步:

  1. 删除 = 左边的内容
  2. 在删除的位置插入 = 右边的内容

从小到大排序

s = [3, 1, 9, 6, 8, 3, 5, 3]
s.sort() # [1, 3, 3, 3, 5, 6, 8, 9]
s.reverse() # [9, 8, 6, 5, 3, 3, 3, 1]
s = [3, 1, 9, 6, 8, 3, 5, 3]
s.sort(reverse = True) # [9, 8, 6, 5, 3, 3, 3, 1]

查找元素数量

s.count(3) # 3

查找元素下标索引

s = [3, 1, 9, 6, 8, 3, 5, 3]
s.index(3) # 0,第一个的下标
s.index(3, 1, 7) # 5,(元素, 开始, 结束)

列表复制

s_cp1 = s.copy()
s_cp2 = s[:] # [3, 1, 9, 6, 8, 3, 5, 3]
# 这两种方法都是浅拷贝(shallow copy)

列表的加乘

s = [1, 2, 3]
t = [4, 5, 6]
s + t # [1, 2, 3, 4, 5, 6]
s * 3 # [1, 2, 3, 1, 2, 3, 1, 2, 3]

嵌套列表 (nested list)

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 等价
matrix = [[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]
# 访问嵌套列表
for i in matrix:
    for each in i:
        print(each)
for i in matrix:
    for each in i:
        print(each, end = ' ')
    print()
# 下标索引访问
matrix[0] # [1, 2, 3]
matrix[0][0] # 1

循环创建嵌套列表

A = [0] * 3
for i in range(3):
    A[i] = [0] * 3
# 错误写法
B = [[0] * 3] * 3
# B[1][1] = 1 -> B == [[0, 1, 0], [0, 1, 0], [0, 1, 0]]

is运算符

x = 'String'
y = 'String'
x is y # True
x = [1, 2, 3]
y = [1, 2, 3]
x is y # False

与py的存储机制有关

A[0] is A[1] # False
B[0] is B[1] # True

B列表写法只是对单个列表引用,而非物理上拷贝

x = [1, 2, 3]
y = x # 一个变量的赋值传递给另一个变量,称为引用
x[1] = 1
y # [1, 1, 3]

需要两个独立的列表就要用拷贝来实现

x = [1, 2, 3]
y = x.copy() # or y = x[:]
x[1] = 1
y # [1, 2, 3]
x = [[1, 2, 3], [4, 5, 6]]
y = x.copy()
x[1][1] = 0
y # [[1, 2, 3], [4, 0, 6]]

浅拷贝只拷贝表层的列表引用,一样引用的内层的列表

深拷贝

import copy
x = [[1, 2, 3], [4, 5, 6]]
y = copy.copy(x) # 浅拷贝
y = copy.deepcopy(x) # 深拷贝
x[1][1] = 0
y # [[1, 2, 3], [4, 5, 6]]

深拷贝将引用的子对象一并进行了拷贝

列表推导式 (list comprehension expression)

例:将列表元素x2

oho = [1, 2, 3, 4, 5]
for i in range(len(oho)):
    oho[i] = oho[i] * 2
print(oho) # [2, 4, 6, 8, 10]

列表推导式

oho = [1, 2, 3, 4, 5]
oho = [i * 2 for i in oho] # [2, 4, 6, 8, 10]

C语言的列表推导式比Py虚拟机的for循环快

[expression for target in iterable]

x = [i for i in range(10)] # 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
x = [c * 2 for c in 'String'] # ['SS', 'tt', 'rr', 'ii', 'nn', 'gg']
# 将字符转换为unicode
x = [ord(c) for c in 'String'] # [83, 116, 114, 105, 110, 103]
matrix = [[1, 2, 3],
          [4, 5, 6],
          [7, 8, 9]]
col2 = [row[1] for row in matrix] # [2, 5, 8]
diag = [matrix[i][i] for i in range(len(matrix))] # [1, 5, 9]
diag2 = [matrix[i][len(matrix) - 1 - i] for i in range(len(matrix))] # [3, 5, 7]

循环通过迭代来逐个修改列表元素,列表推导式是直接创建新列表,再赋值给变量名。

创建嵌套列表

s = [[0] * 3 for i in range(3)] # [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

[expression for target in iterable if condition]

even = [i for i in range(10) if i % 2 == 0] # [0, 2, 4, 6, 8]
[i for i in range(10) if i % 2 == 0] # [1, 3, 5, 7, 9]
# 顺序:for => if => expression
# 筛选单词
words = ['Pretty', 'Fantastic', 'Excellent', 'Great', 'Fish', 'Brillant']
fword = [word for word in words if word[0] == 'F'] # ['Fantastic', 'Fish']
# fword = [word for word in words if word.startswith('F')]

[expression for target1 in iterable1

for target2 in iterable2

…]

# 展开嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flatten = [col for row in matrix for col in row] # [1, 2, 3, 4, 5, 6, 7, 8, 9]

外层循环放前,嵌套循环放后

# 笛卡尔乘积
_ = [x + y for x in 'abcd' for y in 'ABCD']

_ = [] # 临时或无关紧要的变量

[[x, y] for x in range(10) if x % 2 == 0 for y in range(10) if y % 3 == 0]

列表推导式版九九乘法表

[(str(y) + '×' + str(x) + '=' + str(x * y)) for x in range(1, 10) for y in range(1, x + 1)]

程序设计原则:KISS (Keep it Simple & Stupid)

P27

除了字符串和列表,元组也是一个序列

元组像列表可以容纳多种类型对象,也有字符串不可变的特性

列表 - []

元组 = ()

rhyme = (1, 2, 3, 4, 5, '上山打老虎')
rhyme = 1, 2, 3, 4, 5, '上山打老虎'

元组也可以通过下标索引获取元素,也支持切片操作

count() index()可用

+ * 拼接、重复可用

元组嵌套

s = 1, 2, 3
t = 4, 5, 6
w = s, t # ((1, 2, 3), (4, 5, 6))
# 循环迭代
for i in w:
    for each in i:
        print(each)
# 列表推导式
[each * 2 for i in w for each in i]
# 没有元组推导式

生成单元素元组

x = (520,)

元组的打包和解包

元组的生成也叫打包

t = (123, 'Fish', 3.14)
x, y, z = t
print(x, y, z) # 123 Fish 3.14,解包
# 解包也适用于其他序列
t = [123, 'Fish', 3.14]
x, y, z = t # 123 Fish 3.14

x, y, z = '一二三' # 一 二 三

a, b, *c = '1234567' # 1 2 ['3', '4', '5', '6', '7']

py多重赋值

x, y = 10, 20
# 实现:元组打包解包
_ = (10, 20)
x, y = _

元组内的元素不可变,但是元素指向了可变的列表就可变

s = [1, 2, 3]
t = [4, 5, 6]
w = (s, t) # ([1, 2, 3], [4, 5, 6])
w[1][2] = 0 #  ([1, 2, 3], [4, 5, 0])

P28~P33

# 判断回文数
x = '12321'
'是回文数' if x == x[::-1] else '不是回文数' # 是回文数

大小写切换

由于字符串不可变,都是按规则生成一个新字符串

左中右对齐

width小于源字符串长度则输出源字符串,fillchar默认空格填充

查找

替换

判断 (返回布尔类型):

判断一个字符串是否为py的保留标识符:

import keyword
keyword.iskeyword('if') # True

截取字符串

拆分&拼接

格式化字符串

P34~P36

序列可分为可变序列和不可变序列

s = [1, 2, 3]
id(s)
s *= 2 # 增量赋值,[1, 2, 3, 1, 2, 3]
id(s) # 两次id(s)相同

Py中每个对象都有三个基本属性:唯一标识、类型、值

不可以被修改,也不会重复

id()返回指定对象唯一标识的整数值

t = (1, 2, 3)
id(t)
t *= 2
id(t) # 两次id(s)不同

is 和 is not

用于检测对象的id值是否相等,也被称作同一性运算符

x = [1, 2, 3]
y = [1, 2, 3]
x is y # False

in 和 not in

判断包含

'AB' in 'ABCDE' # True

del

删除指定对象

x = [1, 2, 3, 4, 5]
del x[1:4] # [1, 5]
y = [1, 2, 3, 4, 5]
y[1:4] = [] # [1, 5]
# clear方法
x.clear() # []
del x[:]

列表、元组、字符串相互转换

list()

tuple()

str()

list('string') # ['s', 't', 'r', 'i', 'n', 'g']
tuple('string') # ('s', 't', 'r', 'i', 'n', 'g')
str([1, 2, 3]) # '[1, 2, 3]'
str((1, 2, 3) # '(1, 2, 3)'

min() & max()

(iterable, *[, key, default])

(arg1, arg2, *args[, key])

比较的是编码值的大小

min([1, 2, 3]) # 1
max('AgL') # 'g',字母顺序,大写在小写前
min('', default='default') # 'default',为空输出default的内容
min(1, 0, 6, 7, 2, 4) # 0

len() & sum()

len()的位数有限,n位的平台就是 2^(n-1)-1

s = [1, 2, 3, 4]
sum(s) # 10
sum(s, start=100) # sum(s, 100),110

sorted() & reversed()

s = [1, 2, 3, 0, 6]
sorted(s) # [0, 1, 2, 3, 6],与列表的sort方法类似,但是返回的是一个全新列表

默认按编码值升序排列

sorted()也支持key和reverse参数

相对于列表的sort方法,sorted()函数范围更广

sorted('String') # ['S', 'g', 'i', 'n', 'r', 't']
sorted((1, 0, 2, 4, 6, 8, 0)) # [0, 0, 1, 2, 4, 6, 8]

reversed()类似列表的reverse方法,但是返回的是一个反向迭代器

list(reversed([1, 2, 3, 4, 5])) # [5, 4, 3, 2, 1]

all() & any()

x = [1, 1, 0]
y = [1, 2, 1]
all(x) # False,非全为真
all(y) # True
any(x) # True,有为真
any(y) # True

enumerate()

返回一个枚举对象,将可迭代对象的每个元素和从0开始的序号构成一个二元组的列表

list(enumerate([1, 2, 3])) # [(0, 1), (1, 2), (2, 3)]

有start参数

list(enumerate([1, 2, 3], 10)) # [(10, 1), (11, 2), (12, 3)]

zip()

创建一个聚合多个可迭代对象的迭代器

将每个可迭代对象的每个元素合成一个元组

x = [1, 2, 3]
y = [4, 5, 6]
z = 'abcd'
list(zip(x, y)) # [(1, 4), (2, 5), (3, 6)]
list(zip(x, y, z)) # [(1, 4, 'a'), (2, 5, 'b'), (3, 6, 'c')],以最短的为准
import itertools
list(itertools.zip_longest(x, y, z)) # [(1, 4, 'a'), (2, 5, 'b'), (3, 6, 'c'), (None, None, 'd')]

map()

根据提供函数对指定可迭代对象的每个元素进行计算,返回运算结果的迭代器

list(map(ord, 'abc')) # [97, 98, 99]
list(map(pow, [2, 3, 5], [2, 3, 1])) # [4, 27, 5],指定函数为2参数的

filter()

根据提供函数对指定可迭代对象的每个元素进行计算,返回运算结果为真的迭代器

list(filter(str.islower, 'AbCdEfG')) # ['b', 'd', 'f']

迭代器、可迭代对象

一个迭代器肯定是一个可迭代对象

可迭代对象可以重复操作,而迭代器是一次性的

m = map(ord, 'abc')
list(m) # [97, 98, 99]
list(m) # []

iter()

将可迭代对象变为迭代器

x = [1, 2, 3, 4, 5]
y = iter(x)
type(x) # <class 'list'>
type(y) # <class 'list_iterator'>

next()

逐个提取迭代器的元素

next(y) # 1
next(y) # 2
next(y) # 3
next(y) # 4
next(y) # 5
next(y) # 迭代器没元素,抛出异常

next(y, '没了') # 迭代器没元素时打印 '没了'

P37~P39

字典是py中唯一实现映射关系的内置类型

映射类型数据的获取上,字典会远远快于列表

x = {'1', '2'}
type(x) # <class 'set'>,集合
y = {'a':1, 'b':2}
type(y) # <class 'dict'>,字典

{键 (key):值 (value)}

序列是通过位置偏移来存储数据,而字典是通过键来读写

读写值是通过键,而不是下标值

y['a'] # 1
y['c'] = 3
y # {'a': 1, 'b': 2, 'c': 3}

创建字典的六种方法

这六种写法等价

A == B == C == D == E == F # True

fromkeys(iterable[, values])方法,用可迭代对象创建新的字典,初始化为values的值

d = dict.fromkeys('fish', 250) # {'f': 250, 'i': 250, 's': 250, 'h': 250}
d['f'] = 0 # 改
d['o'] = 1 # 增

序列中元素可以重复,而字典中的键不会重复

pop(key[, default])方法

d.pop('s') # 250,返回pop的键队应的值,d中's'消失

pop的键不存在则会抛出异常,设置default参数在键不存在时返回

popitem()方法,py3.7之前是随机删除一个键值对,3.7之后删除最后一个加入的键值对

d.popitem() # ('o', 1)

del关键字

del d['i'] # {'f': 0, 'h': 250}
del d # 删除字典

clear()方法

d = dict.fromkeys('fish', 250)
d.clear() # {}

通过键修改值

d = dict.fromkeys('fish') # {'f': None, 'i': None, 's': None, 'h': None}
d['s'] = 15 # {'f': None, 'i': None, 's': 15, 'h': None}

update([other])方法,可以传入多个键值对、另外一个字典、包含键值对的可迭代对象

d.update(i=10, h=11) # {'f': None, 'i': 10, 's': 15, 'h': 11}
d.update({'f':9}) # {'f': 9, 'i': 10, 's': 15, 'h': 11}

d['i'] # 10

get(key[, default])方法,default参数指定找不到键时的返回

d.get('c', 'None') # 'None'

setdefault(),存在则返回值,不存在则设定值

d.setdefault('f', 'code') # 9
d.setdefault('o', 'code') # 'code'
d # {'f': 9, 'i': 10, 's': 15, 'h': 11, 'o': 'code'}

items()、keys()、values()方法

分别用于获取字典的键值对、键、值三者的视图对象

视图对象:字典的动态视图,字典内容改变时,视图对象的内容也会改变

k = d.keys() # dict_keys(['f', 'i', 's', 'h', 'o'])
v = d.values() # dict_values([9, 10, 15, 11, 'code'])
i = d.items() # dict_items([('f', 9), ('i', 10), ('s', 15), ('h', 11), ('o', 'code')])
d.pop('o')
k # dict_keys(['f', 'i', 's', 'h'])
v # dict_values([9, 10, 15, 11])
i # dict_items([('f', 9), ('i', 10), ('s', 15), ('h', 11)])

浅拷贝

e = d.copy()

键值对的数量

len(d) # 4

in/not in 判断键是否存在

'f' in d # True

list()得到列表

list(d) # ['f', 'i', 's', 'h'],由键构成
# 同
list(d.keys())
list(d.values()) # [9, 10, 15, 11]
iter(d) # 创建一个键的迭代器

py3.8往后字典有了顺序,可以用reversed()函数逆序

list(reversed(d.values())) # [11, 15, 10, 9]

嵌套

dict = {'A': {'a':1, 'b':2, 'c':3}, 'B': [1, 2, 3]}
dict['A']['b'] # 2
dict['B'][2] # 3

字典推导式

d = {'a':1, 'b':2, 'c':3}
b = {v:k for k,v in d.items()} # {1: 'a', 2: 'b', 3: 'c'}
c = {v:k for k,v in d.items() if v > 1} # {2: 'b', 3: 'c'}
{x:ord(x) for x in 'fish'} # {'f': 102, 'i': 105, 's': 115, 'h': 104}
{x:y for x in [1, 3, 5] for y in [2, 4, 6]} # {1: 6, 3: 6, 5: 6}
# 键的值会被覆盖,只会保留后覆盖的

P40~P41

type({}) # <class 'dict'>
type({'a'}) # <class 'set'>
type({'a':1}) # <class 'dict'>

集合中所有元素都应该是独一无二的,并且无序

创建集合三种方法:

无序性

由于集合无序,不能使用下标索引的方式访问

in/not in 可用

'g' in set('string') # True

访问元素可用迭代的方式

for each in set('string'):
    print(each) # r s g i t n

唯一性

去重

set([1, 1, 2, 3, 5]) # {1, 2, 3, 5}
s = [1, 1, 2, 3, 5]
len(s) == len(set(s)) # False,判断列表元素是否有重复

集合的方法:

# 浅拷贝
s = {1, 2, 3}
t = s.copy() # {1, 2, 3}
# 检测两个集合是否不相关
set('fish').isdisjoint(set('python')) # False,有相关
set('fish').isdisjoint(set('java')) # True
set('fish').isdisjoint('java') # 传入可迭代对象也可以
# 检测是否为子集
set('fish').issubset('fishh') # True
# 检测是否为超集
set('fish').issuperset('fis') # True
# 并集
set('fish').union('dish') # {'s', 'd', 'i', 'h', 'f'}
set('fish').union('dish', {1, 2, 3}) # 多参数
# 交集
set('fish').intersection('dish') # {'s', 'h', 'i'}
set('fish').intersection('dish', 'php') # {'h'},多参数
# 差集,属于A集合但不属于B集合
set('fish').difference('dish') # {'f'}
# 对称差集,排除AB集合共有元素之后剩余的元素
set('fish').symmetric_difference('dish') # {'f', 'd'},只能单参数

py也有对应的运算符

# 子集
s = {1, 2, 3}
s <= {1, 2, 3, 4} # True
s < {1, 2, 3, 4} # 真子集
# 超集
s >= {1, 2} # True
s > {1, 2} # 真超集
# 并集
s | {4} | {5} # {1, 2, 3, 4, 5}
# 交集
s & {2, 3} & {1, 3} # {3}
# 差集
s - {2, 3} # {1}
# 对称差集
s ^ {2, 3, 4} # {1, 4}

使用运算符时,符号两边必须都是集合类型的数据,而方法的参数可用使用可迭代对象

py集合分为可变和不可变两种对象

set() / frozenset()

s = frozenset('123456') # frozenset({'1', '6', '2', '4', '3', '5'})

上面的方法不会影响集合的内容,对frozenset也适用

会对集合内容改动的方法:

update(*others) others表示支持多个参数

s = set([1])
s.update([2, 3], '445') # {1, 2, 3, '4', '5'},相当于union并集对应的方法

intersection_update(*others)

difference_update(*others)

symmetric_difference_update(*others)

子集、差集、对称差集的方式更新集合

s.intersection_update([1, 2, 3]) # {1, 2, 3}
s.difference_update([2, 3]) # {1}
s.symmetric_difference_update([2, 3]) # {1, 2, 3}

单纯往集合添加数据可以用add()方法

s.add('45') # {1, 2, 3, '45'},不同于update()方法迭代对象添加,add是直接添加

移除元素

remove(elem) / discard(elem)

如果元素不存在,remove()方法会抛出异常,而discard()方法会静默处理

pop() 随机从集合中弹出一个元素

s = set('123') # {'1', '3', '2'
s.pop() # '1'
s.pop() # '3'
s.pop() # '2'
s # set()
s = set('123')
s.clear() # set()

可哈希

为了能够正确创建,字典的键和集合的元素都得是可哈希的,如果可哈希,则要求在程序生命周期内的哈希值都是不变的

hash(obj) 函数可以获取对象的哈希值

hash(1) # 1
hash(1.0) # 1
hash(1.001) # 2305843009213441

值大小相同时哈希值也相同

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

字符串、元组都不可变,列表,集合都可变

嵌套集合

x = frozenset([1, 2, 3])
y = {x, 4, 5} # {frozenset({1, 2, 3}), 4, 5}

将列表变成集合,可以提高运行的效率:

集合有散列表的支持,而列表没有,代价是要牺牲存储空间

P42~P53

函数

def myfunc():
    pass
def myfunc(name):
    print(f'I love {name}.')
myfunc('Py') # I love Py.
def myfunc(name, times):
    for i in range(times):
    	print(f'I love {name}.')
myfunc('Py', 2) # I love Py. I love Py.

形参/实参

# 返回值
def div(x, y):
    if y == 0:
        return '除数不能为0'
    else:
    	return x / y
div(4, 2) # 2.0

函数没通过return显式返回内容,也会在执行完后返回一个None:

def myfunc():
    pass
print(myfunc()) # None