关于python:那些用起来很爽但用不好可能会被人打的Python骚操作

38次阅读

共计 4099 个字符,预计需要花费 11 分钟才能阅读完成。

疾速将两个别离寄存有 key 和 value 的列表合并成一个字典

>>> a = ["key1", "key2", "key3"]
>>> b = ["value1", "value2", "value3"]
>>> dict(zip(a, b))
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}

这个操作的用处对于爬虫工程师而言挺常见的,比如说:

你须要采集一些键值对类型的信息,而后你可能会碰到一些平台的接口返回这些信息时是间接返回的一个只有 value 的列表,并且 key 都是写死在代码或申请参数里的,这时候你就能够通过这个操作来将它们疾速合并成一个字典,这样就能比拟不便地取值了,取值局部的可读性也会好很多。

还有一种状况就是,你可能会碰到一些网站上的这种键值对信息在 HTML 中 key 和 value 的元素是平级关系,并且 key 和 value 也没有可能辨别的标识,这些状况咱们只能通过把整个键值对局部的元素都提取进去转换成列表,而后再通过按列表下标距离切片的形式别离取出 key 和 value 的列表,而后再将它们合并成一个字典。比方这样:

>>> result = ["key1", "value1", "key2", "value2", "key3", "value3"]
>>> result[0::2]
['key1', 'key2', 'key3']
>>> result[1::2]
['value1', 'value2', 'value3']
>>> dict(zip(result[0::2], result[1::2]))
{'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}

须要留神的是,这个操作在碰到 key 和 value 数量不统一的时候,会主动疏忽掉多的那局部列表尾部的值,你须要确保 key 和 value 是对得上的才行。

简略来说就是,如果你的 key 列表比 value 列表多一个值,那么最终进去的字典就会缺失掉 key 列表中的最初那一个多进去的值。

疾速按头、尾、两头局部切割元素,并将它们别离赋值给三个变量

>>> a = "123456789"  # 也能够是 list 之类的
>>> a1, *a2, a3 = a
>>> a1
'1'
>>> a2
['2', '3', '4', '5', '6', '7', '8']
>>> a3
'9' 

这个操作的用处,对于爬虫工程师或者是一些会接触到公有协定的后端工程师应该都挺常见的,比如说:

你可能会碰到一些基于 TCP 或 UDP 搞的公有协定,而后它们可能会定义一个由内容类型头、通信内容、校验码之类的货色组成的构造,每次通信时都会给你返回这么一个货色,而后你须要将它们切开并赋值给不同的变量,这时候你就能够通过这个操作来疾速实现这个成果了。

当然,这个操作也不能乱用,你最好是可能确保它的内容不会变动,像公有协定这种状况,你能够判断一下协定版本号之类的,以确保它的内容肯定是这个构造。

疾速解压内含嵌套列表的列表,并同时将嵌套列表内的值也赋值给不同的变量

>>> result = [1, 2, [3, 4], 5]
>>> [a, b, [c, d], e] = result
>>> a
1
>>> b
2
>>> c
3
>>> d
4
>>> e
5

这个操作也是偶然会在解决一些公有协定时用到,你能够通过这个操作疾速地将列表中的值赋值给不同的变量再进行解决,十分不便。

如果你只须要嵌套列表中的某个结尾的值,其余的不须要怎么办呢?能够像这样:

>>> result = [1, 2, [3, 4, 5]]
>>> [a, b, [c, *_]] = result
>>> a
1
>>> b
2
>>> c
3

总之就是和后面的操作一样,应用星号来解决前面的多个值,并将它们赋值给下划线这种长期变量摈弃。

注:下划线变量的用处和含意能够自行通过搜索引擎搜寻一下,网上有很多文章提到,这里就不再赘述了。

遍历嵌套且长短不一的列表时,按头、尾切割,并将它们别离赋值给两个变量

>>> result = [["items", "item1", "item2", "item3"], ["status", 1]]
>>> for key, *values in result:
...     print(key)
...     print(values)
...
>>> items
['item1', 'item2', 'item3']
>>> status
[1]

这个操作偶然会在解决一些公有协定或者奇葩平台的接口时用到,就是对方给你返回的内容可能是这么一个嵌套列表,子列表的第一个值是 key、前面的局部是 value,而后有些奇葩点的平台可能连子列表的程序都不雷同。

这种时候如果用这个操作去取 key 和 value 的话,就会不便很多,你不须要管它的 value 到底有多少个,也不须要按下标 0 去取嵌套列表中的 key,你只须要间接这么 for 一下而后解决 key 和 value 就完事了。

>>> {key:values for key, *values in result}
{'items': ['item1', 'item2', 'item3'], 'status': [1]}

甚至你还能够间接把这个代码写成一行,间接将它们转成字典再做后续的解决。

疾速解压一个字典,并将它外面的 key 和 value 们别离赋值给不同的变量

>>> a = {"key1": "value1", "key2": "value2", "key3": "value3"}
>>> (key1, value1), (key2, value2), (key3, value3) = a.items()
>>> key1
'key1'
>>> value1
'value1'
>>> key2
'key2'
>>> value2
'value2'

这个操作的用处也是对于爬虫工程师和后端工程师而言会比拟常见,比如说:

你须要提取一个接口返回的带有状态码、状态信息和 data 的内容,并且你须要判断一下状态码是不是代表申请胜利的那个,这时候如果是一个一个通过 key 去取值、赋值的话就会很麻烦,但如果你用这个操作的话,就能够疾速解决。

可能光是这么说不太直观,看一段样例代码吧:

>>> result = {"code": 200, "data": {"balabala": 111}, "msg": None}
>>> (_, code), (_, data), (_, msg)  = result.items()
>>> code
200
>>> data
{'balabala': 111}
>>> msg
>>>

当然这个操作也不能乱用,在应用这个操作时,你须要确保字典中 key 的程序严格统一,否则就可能会呈现提取到谬误内容的状况,所以提取之前为了避免程序错乱,能够先按 key 做个排序,以确保程序是严格统一的。

而后字典中的内容是否会有变动也是须要思考的,如果你写的代码须要十分谨严,那就还是老老实实地按 key 一个一个取吧,毕竟如果这外面多了一个 key 在两头地位,取到的货色就会齐全不同。

动态创建函数
有时候你可能会碰到相似这样的非凡状况:你有一些不同的值须要通过解决形式雷同的函数进行解决,但因为条件限度你还不能将这个函数演绎为一个并通过传参的形式进行解决,只能是写出多个不同名称的函数来别离解决。

或者你可能就是单纯有个需要须要动态创建一个长期函数来应用。

这时候如果应用这个操作的话,就能够很轻松地解决这个问题,只须要像这样就能够动静地创立出一个函数了:

>>> from types import FunctionType
>>>
>>> func = FunctionType(compile(...     ("def func():\n"
...      "print(1)\n"
...      "return 2"),
...     "<string>",
...     "exec"
... ).co_consts[0], globals())
>>> print(func())
1
2

注:这外面用括号包起来的字符串会主动进行拼接,属于 Python 中多行字符串的写法之一,长处是不会因为像三个引号那样会因为缩进导致字符串内容受影响。如果想理解更多能够自行查看 Python 官网文档,外面的字符串局部有讲这个小技巧。

咱们还能够对外面那个函数代码字符串进行动静生成(比方用 format),以实现对函数名和内容的批改,甚至咱们还能够通过应用像 Jinja 这种模板渲染库来实现更不便的函数代码生成。

因为 Django Admin 的那个 action 函数的参数是固定的,并且如果须要传参给 action 函数的话就须要通过两头页来实现,而我既不想弄两头页、又有好几个不同的参数须要别离解决,于是就间接采纳动态创建函数的形式来解决了。

动静导入
有时候你可能会有一些扩大代码之类的须要在运行时动静地被导入,这时候你就能够用上这个操作了,比如说咱们须要导入 operator 这个库:

>>> import importlib
>>>
>>> module = importlib.import_module("operator")

而后这个 module 变量就是被导入后的模块名称了,咱们能够间接和失常导入时一样应用,比方咱们要调用它的 add 函数:

>>> module.add(1, 1)  # 加法运算符
2

动静调用
有时候你在动静导入之后,还会须要进行动静调用,这时候你就能够这样:

>>> import importlib
>>>
>>> module = importlib.import_module("operator")
>>> func = getattr(module, "add")
>>> func(1, 1) 
2 

当然,在应用动态创建、动静导入、动静调用这种比拟 Hack 的操作的时候,肯定要注意安全问题,就是如果你在应用时有局部参数是须要用户输出的的话,就肯定要对输出内容进行查看,免得被利用来间接执行危险代码。

比如说你提供了一个动态创建函数的性能,如果没有查看内容的话,可能有些比拟坏的人间接就通过 os 库之类的来调用命令行把你的机子给黑了,十分危险。

那么以上就是本次分享的全部内容了,对于这些骚操作其实还有很多,大家感兴趣的话平时能够多注意一下他人写的代码以及各种论坛之类的中央,有时候会有些意外播种。

以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈,发送“J”即可收费获取,每日干货分享

正文完
 0