a = (1) # 这是整数 1
a = (1,) # 这才是元祖
也许这两行,你们当时疑惑过,并且现在也都知道了,当然重点并不在这里。。我无聊的时候想过,为什么单元素元祖要这样设计 -> (1,)?
不多废话,看下面代码,自己理解:a = (3,)
a = (3)
a = (1+2)
a = (1+2,)
a = (1+2) + (3+4)
a = (1+2,) + (3+4,)
注:这是我个人原创理解的一个微不足道的知识点,但是印象却特别深刻。因为我反向推测出 设计者为什么会设计出这种语法。(当然,也许我的推测和设计者当时的想法的并不一样~~~ 手动滑稽)
"""
最开始接触深浅拷贝的时候没太大感觉,只是普通的觉得避免数据污染就够了
后来有一次用 scrapy 写爬虫的时候,层次太多导致内存有些顶不住。后来用的 deepcopy() 来 优化 scrapy 的 meta,虽然效果不是特别明显,但是感觉深浅拷贝很有用
"""
1. = 号,不拷贝
= 号就意味着,引用指向同一个地址空间,‘敌动我动,敌不动我不懂’的感觉。LOL 一句话:"连体婴儿"~~
2. copy:也称浅拷贝
我用最简单的话解释一下:浅拷贝就是只能拷贝最外面的一层皮,来独立开辟空间使用,再深还是共用的
eg:
from copy import copy
from copy import deepcopy
a = [[1,2,3],[4,5,6]]
b = deepcopy(a)
b[0] = 0 # 这就是最外面的一层皮
print(b)
print(a)
3. deepcopy:顾名思义了,深拷贝
如果你听懂我上面的话,我感觉这个就更好理解了,浅拷贝是皮,深拷贝那就是肉了呗。没错,无论套了几层的序列结构,每一层都是独立开辟空间,独立指向。from copy import copy
from copy import deepcopy
a = [[1,2,3],[4,5,6]]
b = deepcopy(a)
b[0][1] = 0 # 看清楚,这回就是里面的肉了,深拷贝:你改哪里都行,哪里都与我无关
print(b)
print(a)
"""lambda 相当于匿名函数,可以使代码简介,但有时也会被人唾弃,但我仍然喜欢用 lambda"""
1. 试想:如果你想在 lambda 调用多个函数,该如何写?lambda: (print(1),print(2)) # 最外层加个括号即可
2. 如果你想让这个 lambda 函数直接自执行,而不是通过赋予一个函数引用再执行?1. 这个也是我自己瞎鼓捣出来的。2. 虽然我 JS 水平很垃圾,但是我知道 JS 匿名函数有一种执行方式叫做‘自执行’。3. 把上面类比一下。看吧,这就是 Python 版的匿名函数自执行方法。Python 版本:(lambda a:print(a))(1)
JS 版:(function(){})()
"""
据说这个模块可以替代 lambda,个人理解此模块并不那么太有实用价值,理解成本也偏高,建议:如果不喜欢 lambda 或者 lambda 用的很少的人,可以研究一下此模块。此模块的意图还是可以的。我还是喜欢使用 lambda
"""
直接上个例子:(字典基于 Value 来排序)传统 lambda 写法:In [27]: a = {'1':6, '2':5, '3':4}
In [28]: sorted(a.items(), key=lambda a:a[1]) # 看 key= 这里
Out[28]: [('3', 4), ('2', 5), ('1', 6)]
operator 写法:from operator import itemgetter
In [25]: a = {'1':6, '2':5, '3':4}
In [26]: sorted(a.items(), key=itemgetter(1)) # 就是 key= 这里有区别
Out[26]: [('3', 4), ('2', 5), ('1', 6)]
如果上面两种新旧方法都很模糊,那么我再解释一下:我认为上面能让人头疼的也就是 索引 1 了!!!!sorted, map 这种高阶函数,我之前也单独讲过,它会把 一个序列的每一个元素用管道函数进行映射。sorted 稍微特殊一点,它的管道函数方法变成了 key= 这里:(变相理解为 指定排序的基准 / 参考)
1. key=lambda a:a[1]
指定基准:序列 a 的 每子元素 的 第 1 号索引子元素 # eg:[[1,2],[3,4],[5,6]] 就是 2,4,6
2. key=itemgetter(1)
指定基准:同上一模一样,只不过写法不一样,逻辑步骤就是 原原本本从 lambda 那里演变过来的。总结与个人观点:1. operator 模块只是 lambda 使用思想 的 高一层的封装
2. 让使用者可以忽略 lambda 格式细节
3. 但是我认为 如果 lambda 都用不好,那么 这个 itemgetter(1) 这种子元素 索引的指定 也会很困难
4. 所以我还是建议用 lambda, 当你 lambda 思想练熟了之后,用 operator 看看官方文档就是很快的事情
"""再次说明一下:我写的所有的都是 Py3 的 / Py2 的解构赋值可能有些出入,此处我只说 Py3"""
封包:1)def f(a,*b):
print(a) # 1
print(b) # (2,3,4)
f(1,2,3,4)
2)def f(**kwargs):
print(kwargs) # {'a': 3, 'b': 4}
f(**dict(a=3,b=4))
拆包(解构赋值):"""
我说过太多次了,ES6 的语法和 Python 很像。解构赋值这个词也是从 ES6 听到的。不过 ES6 的解构,还可以解构 {} 和 解构空值 和 解构默认值, 而 Python 不可以
"""
1) 只要第一个
a, *_ = range(5)
print(a, _) # 0 [1, 2, 3, 4]
2) 只要第一个和最后一个
a, *_, c = range(5)
print(a, _, c) # 0 [1, 2, 3] 4
3) 只要最后一个
*_, b = range(5)
print(_, b) # [0, 1, 2, 3] 4
函数占位参数骚操作:"""
这是我在源码中看到的,当时觉得很惊讶,自己试了一下,下面说下自己的理解:
这个 * 的作用就是:(* 后面的参数是 调用时 必须命名 且 必须传递 的参数)a 你必须给我传过来,但是你不写 a=
b 你必须给我传过来,但是你必须写 b=
"""
def f(a,*,b):
print(a)
print(b)
f(1,b=3) # f(a=1,b=3) # 只能通过这两种方式调用
综合例子:
from importlib import import_module
random = import_module('random') # 动态反射导入模块
# 或 random = __import__('random')
if hasattr(random, 'randint'): # 检测模块中是否有函数
randint = getattr(random,'randint') # 动态反射导入函数
print(eval('randint(0,1)')) # 字符串转语句执行(类似反射)getattr & setattr & hasattr & delattr 讲解:hasattr & getattr
random = __import__('random')
if hasattr(random,'randint'): # 检测 random 模块中是否有 randint 函数
randint = getattr(random,'randint')
print(randint(0,1))
delattr & hasattr
delattr(random, 'randint') # 动态删除模块中的 randint 函数
if not hasattr(random,'randint'):
print('没有此函数了,让 delattr 删除了')
setattr & getattr # 动态重新设置模块的 randint 函数,并给个函数体
setattr(random, 'randint', lambda:print('设置这个方法凑合用把。'))
randint = getattr(random, 'randint')
randint()
from imp import reload
import time
reload(time)
print(time.time())
for x in tqdm(range(100)):
import time
time.sleep(1)
print(x)
tqdm 包装一个可迭代对象,只是装饰了一下,使用方法还是像原来一样使用。
In [2]: from collections import Counter
In [3]: Counter([1,2,3,4])
Out[3]: Counter({1: 1, 2: 1, 3: 1, 4: 1})
In [4]: Counter([1,1,1,2,2,3]) # 统计频次
Out[4]: Counter({1: 3, 2: 2, 3: 1})
In [5]: Counter([1,1,1,2,2,3]).most_common(1) # 频次最多的前 1 个
Out[5]: [(1, 3)]
import shutil
shutil.copy(源,目标) # 复制
shutil.move(源,目标) # 移动,改名
shutil.rmtree(r'目录名') # 删除目录(级联删除)# 参数只能是目录
"""
os.walk() 是一个深度遍历模式的文件遍历函数
返回值是一个迭代器,遍历这个迭代器后,每一次的返回值都是如下顺序三种构成
1. current_path: 当前路径
2. dir_list: 其下目录列表
3. file_list: 其下文件列表
"""
import os
file_generator = os.walk('D:/ 虚拟 E 盘 - 代码空间 /TF2')
for current_dir, dir_list, file_list in file_generator:
print(current_dir, dir_list, file_list)
"""主要代替 os.system"""
import subprocess
res = subprocess.run('dir', shell=True, stdout=subprocess.PIPE) # 结果输入到 res 管道中去
print(res.stdout.decode('gbk')) # res 管道中有输出日志,如果在 win 下,需要 decode
import itertools
list(itertools.product([1,2,3],repeat=3)) # 复制 3 份有序全排列,repeat=3
list(itertools.permutations([1,2,3], 3)) # 内部有序排列,3 表示最后排列为几位
list(itertools.permutations([1,2,3,4],3)) # 无序组合,3 表示 3 位
In [100]: list(enumerate(list('abcde'),start=1)) # 默认从 0,开始标号,start= 1 就从 1 开始
Out[100]: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]
In [108]: list(enumerate(((1,2),(3,4))))
Out[108]: [(0, (1, 2)), (1, (3, 4))]
In [106]: list(enumerate({"a":'c','b':'d'}))
Out[106]: [(0, 'a'), (1, 'b')]
global: 函数外的变量只能在函数内部取值,而不能修改,如果想要在函数内部修改外部变量,‘global 变量名’即可
a = 1
def f():
global a
a += 1
print(a)
f()
nonlocal: 原理同上一模一样,只不过应用场景是闭包了,代码如下:def f():
a = 1
def f1():
nonlocal a
a = a+1
print(a)
f1()
f()
import calendar
calendar.calendar(2019) # 返回 2019 年的日历
calendar.month(2919,5) # 返回 2019 年 5 月的日历
calendar.isleap(2000) # 判断 2000 年是否为闰年
import time
1. 时间戳:time.time()
2. 字符串转时间 (p-pass 方便记忆)
from datetime import datetime
fordate = datetime.strptime('2019-5-25 9:30:30', '%Y-%m-%d %H:%M:%S')
print(fordate)
3. 时间转字符串 (f-from 方便记忆)
from datetime import datetime
strdate = datetime.strftime(fordate, '%Y-%m-%d %H:%M:%S')
print(strdate)
4. 初始化时间
from datetime import datetime
dt1 = datetime(2019,5,25,9,37) # 初始化时间为 datetime 格式
dt1 = datetime.now() # 获取当前时间为 datetime 格式
print(dt1.year)
print(dt1.month)
print(dt1.day)
print(dt1.hour)
print(dt1.minute)
print(dt1.second)