03 - 变量与数据类型
03 - 变量与数据类型
变量是编程里最基础的概念,相当于你往电脑里存东西的"容器"。这章我们把变量的命名规则、Python 的几种基本数据类型都过一遍。
变量是什么
说白了,变量就是一个有名字的盒子。你往里面放个东西,以后想用这个名字就能取出来。
name="小明"age=25print(name,"今年",age,"岁")这里name和age就是变量。=不是"等于"的意思,而是"把右边的东西放进左边的盒子里"。
跟数学里的等号不一样,别搞混了。
x=10x=20# 重新赋值,原来的 10 就没了print(x)# 20变量可以随时重新赋值,新值会覆盖旧值。
命名规则
变量名不是随便起的,有几条硬性规则:
- 只能包含字母、数字、下划线
- 不能以数字开头
- 不能用 Python 的保留字(比如
if、for、class这些)
# 合法的user_name="小明"age2=30_private=True# 不合法的2nd_place="银牌"# 不能数字开头user-name="小明"# 不能用横杠for=10# for 是保留字规则之外还有习惯。Python 社区约定变量名用小写字母加下划线:
# 推荐first_name="小明"total_price=99.9# 不推荐(虽然不会报错)firstName="小明"# 驼峰命名是 Java/JS 的习惯FirstName="小明"# 大写字母开头一般留给类名起名字的时候尽量起有意义的。a = 10; b = 20这种写完了过两天你自己都不知道是什么。
Python 的基本数据类型
Python 里有几种基本的数据类型,我们一个个来。
整数(int)
就是没有小数点的数字,正数负数都行:
age=25temperature=-10population=1_400_000_000# 可以用下划线分隔,提高可读性1_400_000_000这个写法可能你没见过——Python 允许在数字中间加下划线当分隔符,纯粹是为了好读,跟1400000000完全等价。
浮点数(float)
就是带小数点的数字:
price=19.99pi=3.14159weight=0.5注意一个坑:浮点数运算可能不精确。
print(0.1+0.2)# 0.30000000000000004不是 Python 的 bug,几乎所有编程语言都有这个问题。因为电脑用二进制存小数,有些十进制小数没法精确用二进制表示。就像 1/3 用十进制只能写成 0.333… 一样。
如果真要做精确的小数运算(比如算钱),用Decimal:
fromdecimalimportDecimal price1=Decimal("0.1")price2=Decimal("0.2")print(price1+price2)# 0.3,精确的字符串(str)
用引号包起来的文字,单引号双引号都行:
name="小明"city='北京'两种引号没什么区别,只是方便你在字符串里面用另一种引号:
# 字符串里有双引号,外面就用单引号sentence='他说:"你好"'# 反过来也行sentence2="It's a good day"如果两种引号都不够用,可以用反斜杠转义:
sentence3="他说:\"你好\""不过说实话这种写法看着别扭,能避免就避免。
布尔值(bool)
只有两个值:True(真)和False(假)。注意首字母大写。
is_student=Trueis_adult=False布尔值经常用在条件判断里(后面会详细讲):
age=20is_adult=age>=18# 20 >= 18 是 Trueprint(is_adult)# True有意思的是,True和False在 Python 里本质上就是1和0:
print(True+True)# 2print(False*10)# 0虽然一般不会这么用,但知道这个特性有时候能帮你理解一些代码。
空值(NoneType)
None表示"什么都没有",“空”,“不存在”。
result=Noneprint(result)# None什么时候用呢?比如一个函数暂时没有结果,或者一个变量还没确定值,可以先给它赋None。
注意None不是0,不是空字符串"",不是False。它就是None,独一无二的"无"。
类型转换
有时候你需要把一种类型变成另一种类型。Python 提供了几个内置函数来干这事:
# 字符串转整数num=int("42")print(num+8)# 50# 字符串转浮点数price=float("19.99")print(price*2)# 39.98# 数字转字符串age=25message="我今年"+str(age)+"岁"print(message)# 转布尔值print(bool(1))# Trueprint(bool(0))# Falseprint(bool(""))# False(空字符串)print(bool("hello"))# True(非空字符串)关于bool()有个规律:0、""(空字符串)、None、[](空列表)、{}(空字典)这些"空"的东西转成布尔值都是False,其他的基本都是True。
这个规律以后写条件判断的时候特别有用。
类型检查
不确定一个变量是什么类型?用type():
print(type(42))# <class 'int'>print(type(3.14))# <class 'float'>print(type("hello"))# <class 'str'>print(type(True))# <class 'bool'>print(type(None))# <class 'NoneType'>还有一个更实用的方法:isinstance(),用来判断某个变量是不是指定类型:
age=25print(isinstance(age,int))# Trueprint(isinstance(age,str))# Falseprint(isinstance(age,float))# False这个在做参数校验的时候会经常用到。
多重赋值
Python 有几个比较骚的赋值方式,其他语言里不一定有:
# 同时给多个变量赋不同的值name,age,city="小明",25,"北京"# 同时给多个变量赋相同的值x=y=z=0# 交换两个变量的值(不用临时变量!)a=10b=20a,b=b,aprint(a,b)# 20 10最后那个交换操作,我第一次看到的时候觉得挺神奇的。在其他语言里你得用一个临时变量才能交换,Python 一行搞定。
一个综合例子
写个小程序把今天的知识串起来。新建profile.py:
# 用户信息卡片name="小明"age=25height=1.75is_student=Truehobbies=None# 打印信息print("=== 个人信息 ===")print("姓名:"+name)print("年龄:"+str(age))print("身高:"+str(height)+"米")print("是否学生:"+str(is_student))print("爱好:"+str(hobbies))# 算一下出生年份current_year=2024birth_year=current_year-ageprint("大约出生于:"+str(birth_year)+"年")跑一下看看效果。注意里面用了好几次str()来把数字转成字符串,因为字符串和数字不能直接用+拼接。
解包操作符(* 和 **)
解包就是把一个容器"拆开",把里面的元素一个个取出来。这个特性在 Python 里用得非常频繁。
* 解包列表/元组
# 把列表拆成单独的变量first,*rest=[1,2,3,4,5]print(first)# 1print(rest)# [2, 3, 4, 5]# 取头尾first,*middle,last=[1,2,3,4,5]print(first)# 1print(middle)# [2, 3, 4]print(last)# 5# 只取最后几个*init,last_two,last_one=[1,2,3,4,5]print(init)# [1, 2, 3]print(last_two)# 4print(last_one)# 5带*的变量会"吃掉"剩余的所有元素,组成一个列表。
* 解包用于合并
a=[1,2,3]b=[4,5,6]# 合并列表merged=[*a,*b]print(merged)# [1, 2, 3, 4, 5, 6]# 在中间插入result=[0,*a,99,*b]print(result)# [0, 1, 2, 3, 99, 4, 5, 6]** 解包字典
config1={"host":"localhost","port":8080}config2={"debug":True,"port":9090}# 合并字典(后面的覆盖前面的)merged={**config1,**config2}print(merged)# {'host': 'localhost', 'port': 9090, 'debug': True}解包用于函数调用
defadd(a,b,c):returna+b+c nums=[1,2,3]print(add(*nums))# 6,把列表拆成三个参数传入kwargs={"a":1,"b":2,"c":3}print(add(**kwargs))# 6,把字典拆成关键字参数传入第 10 章讲函数的时候会更详细地讲*args和**kwargs,到时候你就明白它们和解包的关系了。
本章小结
- 变量是存数据的容器,命名用小写字母加下划线
- Python 基本数据类型:
int(整数)、float(浮点数)、str(字符串)、bool(布尔值)、None(空值) - 浮点数运算可能不精确,这是通用问题不是 Python 的锅
int()、float()、str()、bool()可以做类型转换type()查看类型,isinstance()判断类型- Python 支持多重赋值和一行交换变量
*和**可以解包列表和字典,在赋值、合并、函数调用中都很常用
面试题
Q1:is和==有什么区别?
==比较的是值是否相等,is比较的是身份(是不是同一个对象)。
a=[1,2,3]b=[1,2,3]print(a==b)# True,值一样print(aisb)# False,不是同一个对象简单说:==问的是"你俩长一样吗",is问的是"你俩是同一个人吗"。
实际开发中,判断是否为 None 的时候推荐用is:if x is None。
Q2:为什么0.1 + 0.2不等于0.3?
这不是 Python 的 bug,是几乎所有编程语言的通用问题。
电脑内部用二进制表示数字,而0.1和0.2在二进制下是无限循环小数,存储时会有微小的精度损失。类似十进制里1/3 = 0.333...没法精确表示。
如果需要精确的小数运算(比如金融场景),应该用decimal模块的Decimal类型。
Q3:Python 的变量是"值传递"还是"引用传递"?
点击查看答案严格来说 Python 是"对象引用传递"(也有人叫"传对象")。
变量本身存的是对象的引用(类似指针),而不是值本身。但对于不可变类型(int、float、str、bool、tuple),你修改时实际上是创建了新对象,所以表现得像值传递:
x=10y=x x=20print(y)# 还是 10,不受影响对于可变类型(list、dict、set),修改会影响所有引用它的变量:
a=[1,2,3]b=a a.append(4)print(b)# [1, 2, 3, 4],b 也变了Q4:bool("")的结果是什么?为什么?
bool("")返回False。
Python 有一个"truthiness"规则:空字符串、0、None、空列表、空字典、空集合等"空"的值都被视为False。非空的值被视为True。
这个设计很实用,比如判断字符串是否为空时,不用写if s == "",直接写if s或if not s就行。
上一章 | 下一章:运算符与表达式 →
