尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python 入门必知:变量、数据类型与动态类型机制详解

Python 入门必知:变量、数据类型与动态类型机制详解 引言很多初学者在接触 Python 时第一感觉是简单——不用声明类型不用管内存写几行代码就能跑起来。但正是这种简单往往隐藏着理解上的盲区为什么a 1之后b a修改b有时影响a、有时又不影响为什么0.1 0.2 ! 0.3为什么列表可以随便加元素整数却不可变这些问题的答案都指向同一个核心Python 的变量模型与动态类型机制。本文将从底层原理出发系统讲解 Python 中的变量、基本数据类型以及动态类型的运作方式帮你建立扎实的基础认知。一、变量的本质不是盒子是标签在 C、Java 等静态类型语言中变量通常被理解为一个盒子——你声明一个int a系统就分配一块内存把值放进去变量名指向这块固定的内存。但 Python 完全不同。在 Python 中变量不是存储数据的容器而是绑定到对象上的一个名字标签。对象才是真正存储数据的实体变量只是引用了这个对象。a100这行代码实际上做了两件事在内存中创建一个整数对象100将名字a绑定到这个对象上。我们可以用id()函数查看对象的内存地址a100print(id(a))# 例如输出 140712345678912每次运行可能不同baprint(id(b))# 和 id(a) 相同b 和 a 指向同一个对象当执行b a时并没有创建新的整数对象只是让b这个标签也贴到了100这个对象上。此时a和b指向同一个对象。那如果修改b呢a100ba b200print(a)# 100print(b)# 200print(id(a)id(b))# False因为整数是不可变对象后面会详细讲执行b 200时并不是修改原来的100对象而是创建了一个新的整数对象200然后把b这个标签重新贴到新对象上。a仍然指向原来的100。理解变量是标签这一点是理解 Python 一切行为的基础。二、基本数据类型全览Python 是一门一切皆对象的语言连最基础的数值、布尔值都是对象。Python 的标准数据类型可以分为以下几类分类类型示例可变/不可变数值int42不可变数值float3.14不可变数值complex1 2j不可变序列strhello不可变序列list[1, 2, 3]可变序列tuple(1, 2, 3)不可变映射dict{a: 1}可变集合set{1, 2, 3}可变集合frozensetfrozenset({1, 2})不可变布尔boolTrue不可变空值NoneTypeNone不可变本文重点讲解最基础的数值、字符串、布尔值和 None列表、字典等容器类型将在后续文章中深入。2.1 整数类型 intPython 的整数没有大小限制只受可用内存约束这和很多语言不同big_num2**1000print(big_num)# 一个 302 位的超大整数Python 轻松处理整数支持常见的算术运算a10b3print(ab)# 13 加法print(a-b)# 7 减法print(a*b)# 30 乘法print(a/b)# 3.3333333333333335 真除法结果总是 floatprint(a//b)# 3 地板除法向下取整print(a%b)# 1 取余print(a**b)# 1000 幂运算注意/和//的区别/总是返回浮点数//返回整数向下取整。负数的地板除法容易踩坑print(7//2)# 3print(-7//2)# -4不是 -3因为向下取整-3.5 向下是 -42.2 浮点数类型 float浮点数用于表示小数底层遵循 IEEE 754 双精度标准。这里有一个经典问题print(0.10.2)# 0.30000000000000004print(0.10.20.3)# False这不是 Python 的 bug而是浮点数的通用特性——十进制小数0.1在二进制中是无限循环小数存储时会有精度损失。需要精确十进制计算时使用decimal模块fromdecimalimportDecimal aDecimal(0.1)bDecimal(0.2)print(ab)# 0.3print(abDecimal(0.3))# True浮点数比较时推荐使用math.isclose()容忍微小误差importmathprint(math.isclose(0.10.2,0.3))# True2.3 字符串类型 str字符串是 Unicode 字符的有序序列用单引号、双引号或三引号定义s1hellos2worlds3多行 字符串字符串是不可变的任何修改操作实际上都会创建新字符串shelloprint(id(s))# 原地址ss.upper()print(s)# HELLOprint(id(s))# 新地址原 hello 对象并未被修改常用字符串操作s Hello, Python! print(s.strip())# Hello, Python! 去除首尾空白print(s.lower())# hello, python! 转小写print(s.replace(Python,World))# 替换子串print(s.split(,))# [ Hello, Python! ] 分割print(-.join([a,b,c]))# a-b-c 拼接# f-stringPython 3.6最推荐的格式化方式name小明age18print(f{name}今年{age}岁)# 小明 今年 18 岁print(f{age*2})# 支持表达式输出 362.4 布尔类型 bool布尔值只有两个True和False。值得注意的是bool是int的子类print(isinstance(True,int))# Trueprint(True1)# Trueprint(True1)# 2Python 中各种类型都有对应的真假值在if、while等条件判断中会自动转换# 以下都为 Falsebool(False)bool(None)bool(0)# 整数 0bool(0.0)# 浮点数 0.0bool()# 空字符串bool([])# 空列表bool({})# 空字典# 其余基本都为 Truebool(hello)# Truebool([0])# True列表非空2.5 NoneTypeNone是 Python 中唯一的空值表示不存在或没有值。函数没有显式return时默认返回Nonedeffunc():print(hello)resultfunc()print(result)# None判断是否为None时应该用is而不是xNoneprint(xisNone)# True推荐写法print(xNone)# True但不推荐因为 可被类重写三、动态类型机制深度解析3.1 什么是动态类型Python 是动态类型语言意味着变量的类型在运行时才确定而且同一个变量可以随时指向不同类型的对象x10# x 指向 intprint(type(x))# class intxhello# x 重新指向 strprint(type(x))# class strx[1,2,3]# x 重新指向 listprint(type(x))# class list对比静态类型语言如 Java变量一旦声明类型就不能改变。Python 的动态类型带来了灵活性但也意味着类型错误只能在运行时发现。3.2 type() 与 isinstance()type()返回对象的确切类型isinstance()判断对象是否是某个类或其子类的实例print(type(True))# class boolprint(type(True)int)# Falsetype 不考虑继承关系print(isinstance(True,int))# Truebool 是 int 的子类print(isinstance(True,bool))# True最佳实践类型判断优先使用isinstance()因为它能正确处理继承关系更符合面向对象的里氏替换原则。3.3 类型转换Python 提供了内置函数进行显式类型转换# 字符串转整数print(int(123))# 123print(int(ff,16))# 255指定十六进制# 整数转字符串print(str(123))# 123# 数值互转print(float(3))# 3.0print(int(3.9))# 3截断小数部分不是四舍五入# 布尔转换print(bool(0))# Falseprint(bool(hello))# True转换失败会抛出ValueError或TypeErrortry:int(abc)exceptValueErrorase:print(f转换失败:{e})# 转换失败: invalid literal for int() with base 10: abc3.4 可变与不可变类型这是 Python 中极其重要的概念也是很多 bug 的根源。不可变类型int、float、str、tuple、bool、None。对象创建后值不能改变任何修改都会创建新对象。可变类型list、dict、set。对象创建后可以原地修改值。用代码直观对比# 不可变类型inta100ba b200print(a)# 100a 不受影响# 可变类型listlist_a[1,2,3]list_blist_a list_b.append(4)print(list_a)# [1, 2, 3, 4]a 被影响了因为两者指向同一个列表对象如果需要复制可变对象而不是共享引用使用拷贝list_a[1,2,3]list_blist_a.copy()# 或 list_a[:]浅拷贝list_b.append(4)print(list_a)# [1, 2, 3]不受影响对于嵌套结构需要copy.deepcopy()进行深拷贝这里不展开。四、常见坑点与避坑指南坑点 1整数缓存机制Python 对小整数通常是-5到256做了缓存这些整数对象在解释器启动时就创建好了重复使用同一个对象a256b256print(aisb)# Truea257b257print(aisb)# 可能为 False取决于实现和运行环境注意永远不要用is比较数值是否相等用。is只用于判断是否为同一个对象如x is None。坑点 2可变对象作为函数默认参数defadd_item(item,lst[]):lst.append(item)returnlstprint(add_item(1))# [1]print(add_item(2))# [1, 2]不是预期的 [2]默认参数在函数定义时只创建一次多次调用共享同一个列表对象。正确写法defadd_item(item,lstNone):iflstisNone:lst[]lst.append(item)returnlst坑点 3字符串拼接效率在循环中用拼接字符串会产生大量临时对象效率低下# 不推荐resultforiinrange(10000):resultstr(i)# 推荐result.join(str(i)foriinrange(10000))坑点 4浮点数相等判断前面已经提到不要直接用比较浮点数使用math.isclose()或decimal.Decimal。五、最佳实践总结理解变量是标签始终记住 Python 变量是对象的引用不是容器。赋值操作只是改变标签的绑定。优先使用isinstance()类型判断时考虑继承关系不要用type() 。用is None判断空值不要用 None。可变对象默认参数用 None避免函数默认参数的共享陷阱。浮点数比较用math.isclose()精确计算用decimal模块。善用类型注解Python 3.5 支持类型提示虽然不强制运行时检查但能显著提升代码可读性和 IDE 支持defgreet(name:str)-str:returnfHello,{name}字符串拼接用join()尤其是在循环中。结语变量、数据类型和动态类型机制是 Python 最基础也最核心的概念。很多初学者写了很久 Python却对变量是引用可变与不可变这些底层机制一知半解导致遇到奇怪的 bug 时无从排查。希望本文能帮你建立起清晰的心智模型变量是贴在对象上的标签对象分可变与不可变类型在运行时动态确定。掌握了这三点你在 Python 之路上的很多困惑都会迎刃而解。
返回列表