Python学习笔记-总
本文最后更新于:2024年8月11日 晚上
综述
本文用于记录平日学习Py中发现的奇奇怪怪的玩法和不知道的知识,以备查阅
Date:2022-04
使用函数组合对输入内容进行处理
1.核心是 map(Function,Data)函数,将F函数一 一映射到数据集Data中,本例中使用的函数是隐函数,处理数据为input并切片后的内容
2.lambda函数:第一个x为形参,:后为对x做类型转换处理
3.list,将结果转换成列表,否则似乎会返回容器代码
1 |
|
字符串切片、筛选、转列表快速方法
1.核心是列表解析,原方法为 x for x in list [if],此处进行改进,for前 x 为最终形成进入列表的参数,进行int()处理,for x in Str表示x在列表内,if 是对x的判断,对x进行一步筛选
1 |
|
使用隐函数对列表中字典按规定排序
有多个在一个列表中的字典,且存在可排序选项
1 |
|
希望对列表中的元素按照XP值的大小进行排序,代码如下:
1 |
|
解析:
1.sorted(Data,Key=,[reverse=False] )方法可对可迭代对象进行排序,Data为排序对象,key为排序规则,如果使用 abs 没有括号!
则对每个元素的绝对值大小进行排序,reverse为是否逆序,默认为升序排列
2.使用隐函数,对每个元素(本例中是字典)中的 ‘xp’ 项的值进行排序,相当于如下代码:
1 |
|
数学方法类:
1 |
|
判断回文:
1 |
|
二维列表
创建二维列表<列表推导创建法>
1.引入random,设置一个种子(这步不是必要的,为了确保结果能够复现)
- random.randint 每一行的元素都是0~9之间的随机整数
- 第一个range(1,6)表示有 5 列,或每行有 5 个元素
- 第二个range(1,5)表示有 4 行,或每列有 4 个元素
1 |
|
以矩阵形式输出二维列表
1 |
|
求取二维列表的最大值
1 |
|
求取一个二维方阵的主对角线或副对角线的和
1 |
|
简便方法求取两数之间的奇数和及偶数和
1 |
|
关于字典
小任务:词频统计等
给出一段文字,要求分别求出单词、标点的个数,然后将单词逆序,最后利用字典统计各个词频:
1 |
|
上述代码不是很复杂,重点讲解字典部分:
对于每一个在待处理列表里的元素
对于word键,定义值为 【查询该word键的值的结果,没有该键则赋值为0】
加上 【1】
聪明在于,对dict[Key]
赋值,不存在的键值将被自动创建,不需要再进行逻辑判断
更聪明在于,使用dict.get(Key,Default Value)
的方式尝试去访问这个键的值,如果存在,就直接调用先前统计的量,再加一,如果不存在,这个函数会自动创建键值并赋值为Default Value
,可以避免直接访问不存在的键导致报错的情况。也避免了再用逻辑判断其值是否存在,不存在就创建,存在就加一的复杂情况。
其他一些好玩的用法
只遍历Key或Value
1 |
|
遍历键值对 < ! >
1 |
|
基于元组列表的字典解析 < ! >[字典推导]
如果有一个元组组成的列表,可以像类似列表解析一样,解析成一个字典:
1 |
|
双列表转字典的Zip方法
可以用Zip方法把两个列表缝合成元组,键值一 一对应:
1 |
|
如果列表里有多个双元组,可以直接套入dic()
函数,但对三元组必须使用zip()
,注意是双元组内直接形成键值
1 |
|
作用域访问和可变参数传递问题
作用域访问
变量所在作用域类型
【1】B:内置作用域:储存一些Python自带的函数和方法
【2】G:全局作用域:在函数体外声明的方法、变量,因为Py没有main函数,因此没有放在def function里的变量都是全局变量
【3】L:局部作用域:在函数体内声明的变量,各个函数体内的变量相互隔离,互不干扰
【4】E:嵌套作用域:预先在函数体外声明,在函数体内调用、修改的nonlocal
变量,可以实现在某函数体内修改局域外的变量
作用域访问顺序
调用优先级:LEGB == 本域 -> 在本域的嵌套域 -> 父域 -> 内置作用域
global 强制声明一个全局变量,除了某些情况要用到,一般比较少用
local 声明一个在本域的局部变量
nonlocal 声明一个在本域的嵌套变量,这个变量必须在父域得到声明
示例
1 |
|
如果学过C++或指针概念会更好理解
函数参数可变对象的传递
导入
一切都源于HZH的题目
黄HZ需要实现,输入一个字符串,将字符串末尾提至首部,生成列表打印
1 |
|
结果显然是办不到的,列表生成了,但是没法把尾部元素放置到头部
起初,我认为是没有return的问题,只需要把修改好的列表lst
写入return
,并赋值给一个变量,然后赋值给一个变量,并打印即可。由于无法修打印代码,于是这个思路虽然实现了,但是还是改了,最终使用全局变量解决,实现的代码如下:
1 |
|
虽然成功解决了问题,但是在子作用域中声明全局变量是非常不合适的,本来,我以为,在子域的变量,必须使用return
来输出,不然就会困在子域中,无法被访问。但是下面这个例子显然驳斥了我的观点:
观察现象:
1 |
|
这是个菜鸟编程的样例,显然,样例中并没有使用return的方式来回传结果【箭头位置】,而直接在全局域中访问lst
并且打印出了子域的值,而不是全局域中的值,你可能觉得,子域和全局域都使用了同一个变量名lst
导致了巧合,实际上,将Mylst
函数的形参换成A
或者FCUK
或者别的什么东西,结果是一样的,提出两个猜想:
1.全局域中,可以访问子域变量,且优先访问子域变量
2.函数直接对全局的lst
进行了修改,并且从某种方式正确返回值
显然,学习了上一节,你可以知道,函数只能访问本域及各层父域的变量,不可能访问子域变量
因此,函数确实对传入的参数lst
本身进行了修改
合理的解释?
经过我的查找,发现了Python函数参数传入的 可变对象传递
和不可变对象传递
,感觉有点抽象和深奥,在此简单说明一下,其他可参考Blog
可变对象和不可变对象
可变对象就是可迭代对象,比如 字典、列表、集合
不可变对象就是不可迭代对象,如 字符串、数字、元组、函数本身
参数传入
可变对象作为参数传入时,实际上是这个变量指针对象本身传入,不对对象进行拷贝操作,因此在子函数内部对这个传入参数的修改,就是对这个变量指向的对象本身的修改。
我认为,在可变对象传入时,形参会把指针指向这个变量指针指向的对象本身。使用id( )
去检测子函数的形参和传入参数的ID,返回值是一样的,因此在子函数中对对象的修改不需要经过返回值即可直接影响到父域的可变对象本身,因为父域的可变变量指针指向的对象本身被修改了,因此它的值也修改了。
传入不可变对象时,刚刚传入时,形参和父域变量的ID值是一样的,一旦要对其进行操作,比如 赋值等,因为对象本身不可变(1就是1,100就是100嘛),因此会深度拷贝该父域变量,赋值给形参,再对形参所指向的对象进行操作,最终结果不会直接影响到父域变量本身,且此时形参的ID值和父域变量不再一样。因此我认为此时就必须使用return
将计算的结果传出。
使用以下两个小实验能有助于理解:
1 |
|
关于参数传递问题的续:
上面的论述都还没有完全解决HZH同志提出的问题,题目的意思肯定不是让我们用这么恶臭和不合规范的再子域中声明全局变量的写法。因此我们有必要进行进一步探索,实际上也不困难。
地址被偷换了
按照Dustella所述,使用list( )
函数相当于深拷贝这个对象然后转换成列表,地址的变换在调用list( )
时就不可避免了,我们的解决方案就是不调用list。
函数的写法
Dustella给出了多样的写法,开拓了大家的眼界。
1 |
|
其中,shift( ls : list )
的意思是,直接告诉函数,传入的ls
是个列表list
,这样就不必调用list( )
函数导致地址改变了
其中的 -> None
是祂的习惯性写法,没有实质性作用(对Python来说)
===========================
基于上述理论,能给出更多的写法。
1 |
|
使用pop()
方法删除元素,本身就会返回被删除的元素的性质,可以缩减代码
1 |
|
使用匿名函数的方法,这样shift
既可以接受参数,又不用写得特别庞大,真乃神来之笔
Data:2022-05
使用双重解析组合列表
可以使用二重解析,将两个列表以对应位置的元素形成元组再组合成列表
1 |
|
有点类似于字典推导,字典推导复习部分:
1 |
|
关于列表的随机元素抽取
提供两种方法随机访问列表中的元素
1 |
|
字典的一些用法
使得字典按照Key的大小降序排列
1 |
|
那么,按照类似的方法,我们也可以对值进行降序排列,尝试实现一下?
1 |
|
字典合并<2>
对于两个字典,合并方式:
1 |
|
奇奇怪怪
赋值与二元操作符
存在这样一种代码(魔法师说是一种语法糖),按位与并把结果赋值,如下:
1 |
|
也就是说,只有当a、b的位都是1时才能为1,否则均为0
同样的,还有按位或,并赋值 a |= b
,也有异或a ^= b
均等于他们的原来形式,比如a &= b
== a = a&b
enumerate()编制索引
enumerate函数将可迭代对象编辑索引,并且遍历时会同时返回索引
实现如下
1 |
|
迭代器检验
使用any( )
可以检验迭代对象内容的布尔值,当全为False
时返回False
,空迭代对象也返回False
使用all( )
可以检验迭代对象的元素布尔值,全为True
时返回True
,否则返回False
一些奇特的方法
去掉0x、0b等
输入一个数,将它转换成十六进制并输出,居中,以“
填充字符,限制为10字符长度,实现如下:
1 |
|
字符串操作
输入一个中文数字(〇一二三……)将其替换成数字(0123……),要求原地代码。
给出固定格式代码,只能在横线____处添加一行代码实现功能
1 |
|
因为是原地代码而且只能使用一行,因此只能使用str.replace(old,new)
的方式来替换字符
实现如下
1 |
|
关于函数奇妙写法(函数解释器)的再探讨
前文我们提到了,在写函数的时候,有人写了这个写法
1 |
|
之前的解释是,B:list
是告诉函数这个参数是列表,但是->None
是祂的一种习惯写法。
之后又遇到了更加离谱的写法,如下:
1 |
|
WTF,这么复杂的写法,肯定不仅仅是习惯问题了,一定是存在某个规则,因此我去查阅了一些资料,得到如下结论:
这些写法其实是函数解释器,用来告诉函数每个参数是什么东西,有哪些限制,返回值是什么类型,这种写法在静态语言里面是强制的,比如C和Java,但是对于动态语言Python来说,是不强制、不检查的,因为编译器会在遇到这个变量赋值自动判断它的类型,使得py没有那么多硬性的复杂语法,相比于C简洁很多,但不严格意味着错误概率提升,py的隐式转换有时候会导致整个程序的致命错误,难以调试,而C的严格限制变量的类型则会在编译的时候就发现错误。
虽然提供解释器,但是py也是不检查、不要求的,这么写是为了让读程序的人查看方便(或者更难理解?)
总之这么写是一种好的习惯。
现在来解释具体含义:
A:list=[]
:传入参数A是一个列表,默认是空列表
B:”int>10”=12
:传入参数B是一个大于10的整数,默认值为12
-> str
:整个函数的返回值应该是字符类型
文件操作
示例一
给出一个关于星座内容的.CSV
文件,文件固定格式为序号,星座,开始日月,结束日月,Unicode
,例如第二行内容为1,水瓶座,120,218,9810
。完成第一个任务
当用户输入星座名,如 双子座
时返回双子座的生日位于521-621之间
,给出格式化输出的代码,剩下的请自行完成。
1 |
|
思路:
CSV是多行文件,本来想读一行判断一行,但是实现起来有点困难,决定一次性把多行读取,存入一个列表中,再通过遍历访问来判断。
实现如下:
1 |
|
如果在 open()
内直接说明open(encoding=“utf-8”)
且使用r
模式,for
语句就不需要解码指令了。当然,指定解码模式只能使用r
打开,使用rb
打开会报错
复盘:
■使用r
方式打开会报解码错误,必须立即指明解码方式encoding="utf-8"
使用rb
模式再解码不会报错
■使用r
模式访问readline()
返回的是奇怪的一串东西(如果没有在open
设置解码的话)
■readlines()
返回以每一行字符串组成的列表,需要把字符串进一步转换成列表才能被访问,否则访问会存在一些困难
■如果使用列表解析式[list(x) for x in f.readlines()]
尝试把readlines
返回的列表内部的字符串转换成列表,最终会得到每个字符单独组成的字符串所组成的列表。如下形式:
[['序', '号', ',', '星', '座', ',', '开', '始', '月', '日', ',', '结', '束', '月', '日', ',', 'U', 'n', 'i', 'c', 'o', 'd', 'e', '\n'], ['1', ',', '水', '瓶', '座', ',',………………]
示例二
给一个文本vote.txt
,里面一行应有一个明星的名字,要求对里面的明星得票进行统计,多写或不写不计入结果,多写的均以单个空格隔开。
给出示例代码,在横线仅填写一行代码:
1 |
|
答案如下:
1 |
|
本题不难,现在解释一部分内容:
open
默认使用r
读取,因此必须加入encoding=“utf-8”
将文本多行读取后记得使用close()
将其关闭,释放空间
readlines()
返回的是每一行内容组成的字符串“XXXX”组成的列表,比如[“孙俪\n”,“周杰伦 孙俪\n”,“周杰伦\n”……]
for name in names
后,name
的值为字符串,统计时必须使用name[:-1]
来把明星的名称全部录入,使用name[0]
只会录入姓氏造成统计故障
将最终的字典以元组形式返回,再形成列表,然后用lambda
辅助进行排序,记得reverse=True
因为默认排序是从小到大的,然后再访问即可。
编码问题:
大多数时候使用utf-8
解码,等价于CHCP65001
编码
而GB2132
等价于cp936
编码
这些个数字只是中文系统里的编号而已
BGK
兼容GB2132