0.26 数据类型:数字、字符串、布尔、列表、字典
第〇篇【零基础预科】免费。变量里能放各种数据,这一篇认识它们的"种类"。
一、为什么要分类型
不同数据能做的事不同:数字能加减,文字能拼接查找,"是/否"用来判断。类型决定了数据的含义和可用操作。
你可能会问:为什么要分类型,不能让电脑自己判断吗? 分类型其实是在避免歧义。
123这个东西,它是数字"一百二十三"、还是字符串"一二三"?如果不区分,你写"123" + 1时电脑就懵了——是要把它们拼成"1231",还是算出124?分了类型,规则就明确:数字和数字才能加,字符串和字符串才能拼。你后面写脚本时遇到TypeError,基本都是"类型没对上"——比如从接口拿到的状态码是字符串"200",你却拿它和数字200去比。
二、基础类型
age = 20 # int 整数
price = 9.9 # float 小数
name = "eason" # str 字符串(文本,用引号)
is_admin = True # bool 布尔,只有 True / False
nothing = None # None 表示“空/没有值”| 类型 | 例子 | 说明 |
|---|---|---|
| int | 20、-3 | 整数 |
| float | 9.9 | 小数 |
| str | "hello"、'x' | 文本,必须引号 |
| bool | True / False | 真假 |
int 和 float 的区别也值得一提。20 是整数,20.0 是浮点数。为什么要分?因为在电脑里它们存的方式不同——整数精确、运算快,浮点数有小数位、会出现 0.1 + 0.2 != 0.3 这种精度问题。安全脚本里你大多数时候用 int 存端口、状态码、计数;float 用得少,知道有这回事、遇到不慌即可。
这里有两个新手必踩的坑。一是字符串必须用引号包起来:name = "eason" 是把文字存进变量;要是忘了引号写成 name = eason,Python 会以为 eason 是另一个变量名,跑去查它的值,查不到就报 NameError。二是布尔值只有 True 和 False,首字母必须大写、不能加引号;写成 true(小写)或 "True"(带引号)都是错的,Python 不认识。
None 值得单独说一句。它不是"0"、不是"空字符串"、不是"False"——它是一个独立的类型,表示"这里什么都没有/还没赋值"。函数没有显式 return 时默认返回 None;接口请求失败时你也可能拿到 None。判断"这个变量是不是还没设值"时,要写 if x is None,而不是 if x == 0。
三、容器类型
ports = [22, 80, 443] # list 列表:有序、可改
person = {"name": "eason", "age": 20} # dict 字典:键值对
coords = (1, 2) # tuple 元组:有序但不可改
uniq = {1, 1, 2, 3} # set 集合:自动去重列表 vs 字典(重点)
列表像一排有编号的格子,用下标(从 0 开始)访问:
pythonports[0] # 22 ports.append(8080) # 末尾添加字典用"键"查"值",适合存属性:
pythonperson["name"] # "eason"
举个安全场景帮你记住区别。你要存一批待扫的端口,顺序无所谓、还会往里加新端口——用列表 [22, 80, 443],因为它就是"一排格子、按编号取、能增能删"。你要存某个漏洞的特征,比如"这个漏洞的 URL 长什么样、利用参数叫什么、成功标志是什么"——这是一组有关联的属性,用字典 {"url": "/admin", "param": "id", "flag": "success"},因为你要靠"键"(url、param)去取对应的值,而不是记它在第几个位置。
你可能会问:元组和列表看着差不多,为什么要分开? 元组用小括号写、一旦创建就不能改(不能 append、不能改某个位置的值)。它的用途是:存一组"固定不变"的数据,比如一个坐标
(x, y)、一条不可改的配置。用元组而非列表,等于在代码里写明"这组数据不该被改",别人读代码时一眼就知道它是常量。新手前期用列表就够,元组知道有这东西、见过能认出来就行。
四、类型查看与转换
type(age) # <class 'int'>
int("10") # 把字符串 "10" 转成整数 10
str(20) # 把数字转成 "20"
len(ports) # 容器长度- 类型不匹配会报
TypeError; - 字符串转数字失败(如 int("abc"))会报
ValueError。
这两个报错在写脚本时天天见。TypeError 的意思是"你让我做一个这种类型做不到的操作",比如你拿字符串 "abc" 去和数字 5 相加——电脑不知道该把它们拼成 "abc5" 还是算算术。ValueError 则是"你想转,但这串内容根本不像数字",比如 int("12a")——int() 要求你给它一个能当数字读的字符串,给个 12a 它转不出来。
排查这类问题的第一招是 type()。怀疑哪个变量类型不对,就在它后面打印一句 print(type(x)),跑一遍看输出是 <class 'int'> 还是 <class 'str'>,马上就能定位。新手最常见的错就是:从命令行参数、从文件、从接口读进来的数据,默认都是字符串;你以为它是数字,拿它去算,结果报 TypeError。养成"拿进来先看一眼类型"的习惯,能省一半调试时间。
五、安全脚本中的用法
targets = ["http://a.com", "http://b.com"] # 列表:多个目标
vuln_signatures = ["rmi://", "ldap://"] # 列表:特征
result = {"url": targets[0], "vuln": True} # 字典:一条结果看这三行就能明白安全脚本的典型套路:待打的目标用列表装(因为是一堆同类型的东西、要挨个循环),漏洞特征也用列表装(同样是一堆待匹配的字符串),每打完一个目标、要记录结果时用字典——因为一条结果是"哪条 URL、是否存在漏洞、返回了什么"这组有关联的属性,用键去存比记第几个位置清楚得多。你后面写 PoC、写批量探测器,几乎都是这两套容器的排列组合:列表管"一批同类项",字典管"一组关联属性"。
你可能会问:那集合(set)什么时候用? 集合最大的特点是"自动去重、不讲顺序"。你扫了 100 个目标、发现了 200 个端口,但其中很多重复——丢进集合里,一秒钟帮你去重,剩下的就是"这个目标到底开了哪些不同端口"。前期你用列表和字典就够,集合知道有这东西、用到再查。
六、本篇小结
- 基础类型:int 整数、float 小数、str 文本、bool 真假、None 空。
- 容器:list 有序可改、dict 键值对、tuple 不可改、set 去重。
- 列表按下标(从 0),字典按键;用 type() 看类型、int()/str() 转换。
- 安全里用列表存目标/特征、字典存结果。
记住这套分工,以后读任何 Python 脚本都能先分清"这是一堆东西、还是一条记录"。
下一篇 0.27 讲条件判断,让程序学会"看情况办事"。