第三周笔记
封装和解构
-
封装
- 将多个值使用逗号分割,组合在一起
- 本质上,返回一个元组,只是省略掉了小括号
- python特有语法,被很多语言借鉴
-
交换
-
a = 4 b = 5 temp = a a = b b = temp 等价于 a, b = b, a # 右边封装,左边解构
-
-
解构
- 把线性结构的元素解开,并顺序的付给其他变量
- 左边接纳的变量数要和右边解开的元素个数一致
Python3的解构
-
使用*变量名接收,但不能单独使用
-
被*变量名收集后组成一个列表
-
举例
-
lst = list(range(1, 21, 2)) head, *mid, tail = lst *lst2 = lst *body, tail = lst head, *tail = lst head, *m1, *m2, tail = lst head, *mid, tail = "abcdefghijk" type(mid) --->
-
-
丢弃变量
-
这是一个惯例,是不成文的约定,不是标准
-
如果不关心一个变量,就可以定义该变量的名字为_
-
_是一个合法的标识符,也可以作为一个有效的变量使用,但是定义成下划线就是希望不要被使用,除非你明确知道整个数据需要使用
-
lst = [9, 8, 7, 20] first, *second = lst head, *_, tail = lst print(head) print(tail) --->9 20
-
总结:
- _这个变量本身无任何语义,没有任何可读性,所以不是用来给人使用的
- Python中很多库,都是用这个变量,使用十分广泛。请不要在不明确变量作用域的情况下使用,导致和库中的_冲突
-
-
总结:
- 解构,是Python中提供的很好的功能,可以方便提取复杂数据结构的值
- 配合_的使用,会更加的便利
set及操作
集set
-
约定
- set翻译为集合
- collection翻译为集合类型或容器,是一个大概念
-
set
- 可变的,无序的,不重复的元素的集合
-
set定义 初始化
- set()
- set(iterable)
-
set的元素
- set的元素要求必须可以hash
- 目前学过的不可hash的类型有list、set、bytearray
- 元素不可以索引
- set可以迭代
-
set增加
- add(elem)
- 增加一个元素到set中
- 如果元素存在,什么都不做
- update(*others)
- 合并其他元素到set集合中
- 参数others必须是可迭代对象
- 就地修改
- add(elem)
-
set删除
- remove(elem)
- 从set中移除一个元素
- 元素不存在,抛出KeyError异常
- discard(elem)
- 从set中移除一个元素
- 元素不存在,什么都不做
- pop()->item
- 移除并返回任意的元素
- 空集返回KeyError异常
- clear()
- 移除所有元素
- remove(elem)
-
set修改、查询
- 要么删除,要么加入新的元素,不可修改
- 非线性结构,无法索引
- 可以迭代所有元素
-
set和线性结构
- 线性结构的查询时间复杂度是O(n),即随数据规模的增大而耗时增加
- set、dict等结构,内部使用hash值作为key,时间复杂度可以做到O(1),查询时间和数据规模无关
- 可hash
- 数值型 int、float、complex
- 布尔型 True、False
- 字符串 string、bytes
- tuple
- None
- 以上都是不可变类型,称为可哈希类型,hashable
- set的元素必须是可hash的
-
集合
- 全集
- 子集subset和超集superset
- 真子集和真超集
-
集合运算
- 并集
- 将两个集合A和B的所有元素合并到一起,组成的集合称作A与B的并集
- | 运算符重载(等同union)
- |= 将多个集合合并,就地修改(等同update)
- 交集
- 集合A和B,由所有属于A且属于B的元素组成的集合
- intersection(*others)
- 返回和多个集合的交集
- &
- 等同intersection
- intersection_update(*others)
- 获取和多个集合的交集,并就地修改
- &=
- 等同intersecton_update
- 差集
- 集合A和B,由所有属于A切不属于B的元素组成的集合
- difference(*others)
- 返回和多个集合的差集
-
- 等同difference
- difference_update(*others)
- 获取和多个集合的差集并就地修改
- -=
- 等同difference_update
- 对称差集
- 集合A和B,由所有不属于A和B的交集元素组成的集合,记作(A-B)∪(B-A)
- symmetric_difference(other)
- 返回和另一个集合的对称差集
- ^
- 等同symmetric_difference
- symmetric_difference_update(other)
- 获取和另一个几个的对称差集并就地修改
- ^=
- 等同symmetric_difference_update
- issubset(other)、<=
- 判断当前集合是否是另一个集合的子集
- set1 < set2
- 判断set1是否是set2的真子集
- issuperset(other)、>=
- 判断当前集合是否是other的超集
- set1 > set2
- 判断set1是否是set2的真超集
- isdisjoint(other)
- 当前集合和另一个几个没有交集
- 没有交集,返回True
- 并集
-
幂等性
- 输入的参数不变,输出的值也对应相等
-
hash冲突
- 两个不同的值,经过hash,hash值一样(可能性极小)
字典dict
- key-value键值对的数据的集合
- 可变的、无序的、key不重复
字典dict定义 初始化
- d = dict()或者d = {}
- dict(**kwargs)使用name=value对初始化一个字典
- dict(iterable, **kwarg)使用可迭代对象和name=value对构造字典,不过可迭代对象的元素必须是一个二元结构
- d=dict(((1,‘a’), (2,‘b’)))或者d=dict(([1,‘a’],[2,‘b’]), c=300)
- dict(mapping, **kwarg)使用一个字典构建另一个字典
- d={‘a’:10, ‘b’:20,‘c’:None,‘d’:[1,2,3]}
- 类方法dict.fromkeys(iterabe, value)
- d=dict.fromkeys(range(5))
- d=dict.fromkeys(range(5), 0)
字典元素的访问
- d[key]
- 返回key对应的值value
- key不存在抛出KeyError异常
- get(key[,default])
- 返回key对应的值value
- key不存在返回缺省值,如果没有设置缺省值就返回None
- setdefault(key[,default])
- 返回key对应的值value
- key不存在,添加kv对,value设置为default,并返回default,如果default没有设置,缺省为None
字典增加和修改
- d[key] = value
- 将key对应的值修改为value
- key不存在添加新的kv对
- update([other]) -> None
- 使用另一个字典的kv对更新本字典
- key不存在,就添加
- key存在,覆盖已经存在的key对应的值
- 就地修改
字典删除
- pop(key[,default])
- key存在,移除它,斌返回它的value
- key不存在,返回给定的default
- default未设置,key不存在则抛出KeyError异常
- popitem()
- 移除并返回一个任意的键值对
- 字典为empty,抛出KeyError异常
- clear()
- 清空字典
- del语句
字典遍历
-
遍历key
for ... in dict # 遍历key for k in d: print(K) for k in d.keys(): print(k)
-
遍历value
-
for ... in dict # 遍历value for k in d: print(d[k]) for k in d.keys(): print(d.get(k)) for v in d.values(): print(v)
-
遍历item
-
for ... in dict: for item in d.items(): print(item) for item in d.items(): print(item[0], item[1]) for k,v in d.items(): print(k, v) for k,_ in d.items(): print(k) for _,v in d.items(): print(v)
-
总结:
- Python3中,keys、values、items方法返回一个类似一个生成器的可迭代对象,不会把函数的返回结果复制到内存中
- Dictionary view对象,可以使用len(),lter(),in操作
- 字典的entry的动态的视图,字典变化,视图将反映出这些变化
- keys返回一个类set对象,也就是可以看做一个set集合。如果values都可以hash,那么items也可以看做是类set对象
- Python2中,上面的方法会返回一个新的列表,占据新的内存空间。所以Python2建议使用iterkeys,itervalues,iteritems版本,为不是返回一个copy
- Python3中,keys、values、items方法返回一个类似一个生成器的可迭代对象,不会把函数的返回结果复制到内存中
-
如何在遍历的时候移除元素
-
d = dict(a=1, b=2, c='abc') keys = [] for k,v in d.items(): if isinstance(v,str): keys.append(k) for k in keys: d.pop(k) print(d)
-
字典的key
-
key的要求和set的元素要求一致
- set的元素可以就是看作key,set可以看作dict的简化版
- hashable可哈希才可以作为key,可以使用hahs()测试
- d={1:0,2.0:3,“abc”:None, (‘hello’, ‘world’, ‘pyrhon’):‘string’,b’abc’:‘153’
-
defaultdict
-
collections.default([default_factory[, …]])
-
第一个参数是default_factory,缺省是None,它提供一个初始化函数。当key不存在的时候,会调用这个工厂函数来生成key对应的value
-
import random d1 = {} for k in "abcdef": for i in range(random.randint(1, 5)): if k not in d1.keys(): d1[k] = [] d1[k].append(i) print(d1) --->{'a': [0, 1, 2], 'b': [0, 1], 'c': [0, 1, 2, 3, 4], 'd': [0, 1, 2, 3], 'e': [0, 1, 2, 3], 'f': [0]}
-
from collections import defaultdict import random d1 = defaultdict(list) for k in 'abcedf': for i in range(random.randint(1, 5)): d1[k].append(i) print(d1) --->defaultdict(<class 'list'>, {'a': [0, 1], 'b': [0, 1], 'c': [0, 1, 2], 'e': [0, 1], 'd': [0], 'f': [0]})
-
-
-
OrderedDict
-
collections.OrdedDict([items])
-
key并不是按照加入的顺序排列,可以使用OrderedDict记录顺序
-
from collections import OrderedDict import random d = {'banbana':3, 'apple':4, 'pear':2} print(d) keys = list(d.keys()) random.shuffle(keys) print(keys) od = OrderedDict() for key in keys: od[key] = d[key] print(od) print(od.keys) --->{'banbana': 3, 'apple': 4, 'pear': 2} ['banbana', 'pear', 'apple'] OrderedDict([('banbana', 3), ('pear', 2), ('apple', 4)]) <built-in method keys of collections.OrderedDict object at 0x000001BDE6531E18>
-
-
有序字典可以记录元素插入的顺序,打印的时候也是按照你这个顺序输出打印
-
3.6版本的python的字典就是记录key插入的顺序(ipython不一定有效果)
-
应用场景
- 假如使用字典记录了N个产品,这些产品使用ID由小到大加入到字典中
- 除了使用字典检索的遍历,有时候需要取出ID,但是希望是按照输入的顺序,因为输入顺序是有序的
- 否则还需要重新把遍历到的值排序
-
Python解析式、生成器
标准库datetime
-
datetime模块
-
对日期、时间、时间戳的处理
-
datetime类
-
类方法
- today()返回本地区当前时间的datetime对象
- now(tz=None)返回当前时间的datetime对象,时间到微秒,如果tz为None,返回和today()一样
- utcnow()没有时区的当前时间
- fromtimestamp(timestamp, tz=None)从一个时间戳返回一个datetime对象
-
datetime对象
-
timestamp()返回一个到微妙的时间戳
- 时间戳:格林威治时间1970年1月1日0点到现在的秒数
- 构造方法 datetime.datetime(2016, 12, 6, 16, 29, 43, 79043)
- year,month,day,hour,minute,second,microsecond,取datetime对象的年月日时分秒及微秒
- weekday()返回星期的天,周一0,周日6
- isoweekday()返回星期的天,周一1,周日7
- date()返回日期date对象
- time()返回时间time对象
- replace()修改并返回新的时间
- isocalendar()返回一个三元组(年,周数,周的天)
-
日期格式化
-
类方法 strptime(date_string, format), 返回datetime对象
-
对象方法strtfime(format),返回字符串
-
字符串format函数格式化
-
import datetime dt = datetime.datetime.strptime("21/11/06 16:30", "%d%m%y %H:%M") print(dt.strftime(""%Y-%m-%d %H:%M:%S")) print("{0:%Y}/{0:%m}/{0:%d} {0:%H}::{0:%M}::{0:%S}".format(dt))
-
-
-
timedelta对象
- 构造方法
- datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)
- year = datetime.timedelta(days=365)
- total_seconds()返回时间差的总秒数
- 构造方法
-
-
time模块
- time.sleep(secs)将调用线程挂起指定的秒数
列表解析式
-
生成一个列表,元素0~9,对每一个元素自增1后求平方返回新列表
-
l1 = list(range(10)) l2 = [] for i in l1: l2.append((i + 1) ** 2) print(l2) --->[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
-
# 列表解析式 l1 = list(range(10)) l2 = [(i + 1) ** 2 for i in l1] print(l2) print(type(l2)) --->[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] <class 'list'>
-
-
语法
- [返回值 for 元素 in 可迭代对象 if 条件]
- 使用中括号[], 内部是for循环, if条件语句可选
- 返回一个新的列表
-
列表解析式是一种语法糖
- 编译器会优化,不会因为简写而影响效率,反而因优化提高了效率
- 减少程序员工作量,减少出错
- 简化了代码,但可读性增强
生成器表达式
-
语法
- (返回值for元素in可迭代对象if条件)
- 列表解析式的中括号换成小括号就行了
- 返回一个生成器
-
和列表解析式的区别
- 生成器表达式时按需计算(或称惰性求值,延迟计算),需要的时候才计算值
- 列表解析式时立即返回值
-
生成器
- 可迭代对象
- 迭代器
-
举例
-
g = ("{:04}".format(i) for i in range(1, 11)) next(g) for x in g: print(x) print('--------------------------') for x in g: print(x) --->0002 0003 0004 0005 0006 0007 0008 0009 0010 --------------------------
-
总结
-
延迟计算
-返回迭代器,可以迭代
-
从前到后走完一遍,不能回头
-
-
-
和列表解析式的对比
- 计算方式
- 生成器表达式延迟计算,列表解析式立即计算
- 内存占用
- 单从返回值本身来说,生成器表达式省内存,列表解析式返回新的列表
- 生成器没有数据,内存占用极少,到那时使用的时候,虽然一个个返回数据,但是合起来占用的内存也差不多
- 列表解析式构造新的列表需要占用内训
- 计算速度
- 单看计算时间,生成器表达式耗时非常短,列表解析式耗时长
- 但是生成器本身并没有任何返回值,只返回了一个生成器对象
- 列表解析式构造并返回了一个新的列表
- 计算方式
集合解析式
-
语法
- {返回值 for 元素 in 可迭代对象 if 条件}
- 列表解析式的中括号换成大括号就行了
- 立即返回一个集合
-
用法
-
{(x, x+1) for x in range(10)} --->{(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10)}
-
字典解析式
-
语法
-
{返回值 for 元素 in 可迭代对象 if 条件}
-
列表解析式的中括号换成大括号就行了
-
使用key:value形式
-
立即返回一个字典
-
{x:(x, x+1) for x in range(10)} --->{0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5), 5: (5, 6), 6: (6, 7), 7: (7, 8), 8: (8, 9), 9: (9, 10)}
-
-
总结
- 一般来说,应该多应用解析式,简短高效
- 如果一个解析式非常复杂,难以读懂,要考虑拆成for循环
- 生成器和迭代器时不同的对象,但都是可迭代对象
Python内建函数
-
标识 id
- 返回对象的唯一标识,CPython返回内存地址
-
哈希 hash
- 返回一个对象的哈希值
-
类型 type()
- 返回对象的类型
-
类型转换
- float(), int(), bin(), henx(), oct(), bool(), list(), tuple(), dict(), set(), complex(), bytes(), bytearray()
-
输入 input
- 接收用户输入,返回一个字符串
-
打印 print
- 打印输出,默认使用空格分隔,换行结尾,输出到控制台
-
对象长度 len()
- 返回一个集合类型的元素个数
-
isinstance(obj, class_or_tuple)
-
判断对象obj是否是属于某种类型或元组中列出的某个子类
-
isinstance(True, int)
-
isinstance('234', (int, tuple)) # 布尔型是整型的子类 --->False
-
-
issubclass(cls, class_or_tuple)
- 判断类型cls是否是某种类型的子类或元组中列出的某个类型的子类
- issubclass(bool, int)
-
绝对值abs(x) x为数值
-
最大值max() 最小值min()
-
round(x) 四舍六入五取偶
-
**pow(x, y) **
-
range(stop) 从0开始到stop-1的可迭代对象
-
divmod(x, y) 等价于tuple(x // y, x % y)
-
sum(iterable[,start]) 对可迭代对象的所有数值元素求和
-
chr(i) 给一个一定范围的这个念书返回对应的字符
-
ord© 返回字符对应的整数
- ord('a) ord(‘中’)
-
str(), repr(), ascii() 后面说
-
sorted(iterable[, key][, reverse])排序
-
返回一个新的列表,默认升序
-
reverse是反转
-
sorted([1, 3, 5]) --->[1, 3, 5] sorted([1, 3, 5], reverse=True) --->[5, 3, 1] sorted({'c':1, 'b':2, 'a':1}) --->['a', 'b', 'c']
-
-
翻转 reversed(seq)
-
返回一个翻转元素的迭代器
-
list(reversed(“13579”))
-
{ reversed((2, 4))} --->{<reversed at 0x155cb206ba8>}
-
for x in reversed(['c', 'b', 'a']): print(x) reversed(sorted({1, 5, 9})) --->a b c <list_reverseiterator at 0x155cb0ece10>
-
-
枚举
-
迭代一个序列,返回索引数字和元素构成的二元组
-
start表示索引开始的数字,默认是0
-
for x in enumerate([2, 4, 6, 8]): print(x) --->(0, 2) (1, 4) (2, 6) (3, 8)
-
-
*拉链函数 zip(iterables)
-
像拉链一样,把多个可迭代对象合并在一起,返回一个迭代器
-
将每次从不同对象中取到的元素合并成一个元组
-
list(zip(range(10), range(10))) --->[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]
-
list(zip(range(10), range(10), range(5), range(10))) --->[(0, 0, 0, 0), (1, 1, 1, 1), (2, 2, 2, 2), (3, 3, 3, 3), (4, 4, 4, 4)]
-
-
迭代器和取元素 iter(iterable), next(iterator[, default])
-
iter将一个可迭代对象封装成一个迭代器
-
next对一个迭代器取下一个元素。如果元素全部都取过了,再次next会抛StopIleration异常
-
it = iter(range(5)) next(it) --->0 it = reversed([1, 3, 5]) next(it) --->5
-
-
可迭代对象
- 能够通过迭代一次次返回不同的元素的对象
- 所谓相同,不是指值是否相同,而是元素在容器中是否是同一个,例如列表中值可以重复的,[‘a’, ‘a’],虽然这个列表有两个元素,值一样,但是两个‘a’是不同的元素
- 可以迭代,但是未必有序,未必可索引
- 可迭代对象有:list, tuple, string, bytes, bytearray, range, set, dict, 生成器等
- 可以使用成员操作符in,not in, in本质上对线性数据结构就是在遍历对象
- 能够通过迭代一次次返回不同的元素的对象
迭代器
-
迭代器
-
特殊的对象,一定是可迭代对象,具备可迭代对象的特征
-
通过iter方法把一个可迭代对象封装成迭代器
-
通过next方法,迭代 迭代器
-
生成器对象,就是迭代器对象
-
for x in iter(range(10)): print(x) --->0 1 2 3 4 5 6 7 8 9
-