很多学Python的新手,第一天基本都卡在“变量”和“数据类型”这两个词上。不是它们有多难理解,而是教材常写“变量是存储数据的容器”、“数据类型是指数据的种类”,每个字都认识,连起来就不知道在说什么。尤其当你看到a = 10这种代码,脑子里会闪过无数个问题:这个a到底是个什么东西?为什么后面又冒出个a = "hello",它不应该是数字吗?Python怎么不报错?
这篇笔记就是来解决这些问题的。我只讲一个主题:变量和数据类型,但我会用大白话把“变量为什么叫变量”、“类型到底是什么”、“新手最常见的翻车点”讲透。你现在零基础也能看懂,会敲键盘就能跟上。看完你就能看懂Python里最基础的那些代码,也能写出第一段能实际运行的小程序——比如算BMI、做个迷你购物车。如果你刚装好Python、刚看完安装教程但还不会用,这篇同样适合你。
我不会扔给你一堆定义然后让你自己悟。每一步我都会说清楚“为什么是这样”,因为我发现,编程里大部分坑,都源于没搞懂最基础的概念。
1. 变量到底是什么:先把这个概念讲透
1.1 变量是一个贴了标签的盒子?不对,是一张贴纸
很多教材喜欢说“变量是存放数据的盒子”。这个类比能帮你入门,但容易留下隐患,因为Python里的变量,更像是一张“贴纸”。
想象一个仓库,里面有很多储物柜。你在一个柜格里放了一箱苹果,然后在柜门上贴了一张纸条,写上“a”。这时候别人问“a在哪”,你带他到那个柜格前,说“这就是a”。关键点来了:柜格里装的不是“a”,而是“一箱苹果”。隔天你把柜格里的东西换成了一箱橘子,柜门上的纸条没撕,你还是挂着“a”。别人再问“a是什么”,答案是“一箱橘子”,而不是“那箱苹果”。
Python里的变量就是这个道理。代码a = 10的真实操作是:先在内存里创建一个数字对象10,然后拿一张叫a的贴纸贴上去。你去读a,其实是顺着贴纸找到了那个数字对象。你写a = "你好"时,并没有修改原来的数字10,而是又创建了一个新的字符串对象,然后把贴纸从10上撕下来,贴到了“你好”上。原来的数字10如果没人引用,会被Python自动回收。
这就是为什么我说“贴纸”比“盒子”更贴近真相:变量本身不装东西,它只是给内存里的数据起名字。所以Python里你不需要提前声明“a是整数类型”,你只需要把名字贴到你想要的数据上就行。想换就换,随时可以撕下来贴到别处。
1.2 赋值符号不是“等于”,是“把右边的结果给左边”
我见过最多的误解,是把=当成数学里的“等于”。数学里x = x + 1是荒谬的,但Python里这行代码天天见。它的含义特别直白:先算等号右边的x + 1,得到一个新值,再把这个值赋给左边的x。
打个比方,你有一个记账本,上面记着“今天的步数:8000”。晚上你又走了一千步,你会怎么做?不是拿橡皮擦掉8000再写9000,而是直接算8000 + 1000,把结果9000填进去。代码里写steps = steps + 1000,逻辑一模一样:先读旧值,加上1000,再把新值写回去。
赋值还有一个很好用的小技巧:多个变量同时赋值,以及一键交换。
# 连续赋同一个值 a = b = 0 # 同时赋不同值 name, age = "小明", 18 # 交换两个变量的值,不用中间变量 x, y = 10, 20 x, y = y, x print(x, y) # 输出 20 10最后一行的交换,在C语言或Java里得写三行,Python一行搞定。这个写法以后写排序、算法会经常用到,第一天先混个脸熟。
1.3 变量命名:三条铁律和三条建议
理解了变量是什么,接下来要面对的就是“怎么给变量取名字”。名字起得好不好,直接决定你三天后回来看代码能不能看懂。先记住三条铁律,犯了会直接报错:
- 变量名只能由字母、数字、下划线组成,不能有空格、不能有
-、不能有中文标点。my_name是对的,my name是错的,my-name也是错的。 - 不能以数字开头。
1abc会报错,abc1没问题。 - 不能使用Python的保留字,比如
if、for、while、class、def、True、False、None这些。
除了这些硬性规定,我还有三条经验建议:
第一,见名知意。写total_price比写tp好一百倍。第二,推荐蛇形命名法,全部小写,单词之间用下划线连接:user_name、student_score。第三,尽量别用list、str、type、print这种内置名字做变量名,它们会“覆盖”Python自带的功能,后面很容易踩坑,我怀疑很多人的TypeError就是从这里来的。
2. 小白第一天最该认识的7种数据类型
数据类型是什么?用最通俗的话讲:Python里的数据有不同“种类”,字符串是文字,数字是数字,列表是一串东西。Python会根据你写的字面值自动判断类型,并在内部给每种类型安排不同的行为和内存方式。你不需要背全部,先把最常见的7种混熟。
2.1 数字型:int 和 float,别被“整数”骗了
整数的英文是int,全称integer。Python 3里的int非常强大,它没有长度限制,你想写多长的整数都行,不像有些语言超过某个范围就溢出报错。小数在Python里叫float,全称floating-point,浮点数。3.14、-0.5、1.0都是float。
注意一个小陷阱:1和1.0在Python眼里是两种类型,虽然值相等。1是int,1.0是float。很多刚开始学的人看不出区别,但后面一遇到除法和类型判断就会露馅。
数字之间最常见的运算有这几个:
print(7 / 2) # 3.5 普通除法,结果是 float print(7 // 2) # 3 整除,丢掉小数部分 print(7 % 2) # 1 取余数 print(2 ** 3) # 8 幂运算,2的3次方//和%这两个很多新手记不住,其实它们是一对好兄弟:整除给你商,取余给你余数,就像小学学除法时先写“商几余几”。后面判断一个数是不是偶数、做循环计数,就靠它们。
浮点数还有一个必须提前知道的坑:0.1 + 0.2不等于0.3,而是一个很长的近似值0.30000000000000004。这是计算机用二进制表示小数的先天限制,不是Python的bug。第一天不用深入研究,只要知道算结果后最好用round()圆整一下就行。
2.2 字符串:带引号的就是字符串
在Python里,被单引号或双引号包起来的文本都叫字符串,类型名是str。"你好"是字符串,'hello'也是字符串。为什么要加引号?因为只有加了引号,Python才知道这是“文本数据”而不是变量名。你说print(hello),Python会去找一个叫hello的变量,找不到就会报NameError;你说print("hello"),Python就知道你只想把那几个字母原样打出来。
字符串有三种常见写法:
s1 = '单引号' s2 = "双引号" s3 = """三引号,可以 写成多行文本"""单引号和双引号没本质区别,用法主要看里面是否包含引号:say "hello"这种句子,外面用单引号写起来更舒服;It's ok这种,外面用双引号更舒服。
字符串最常见的操作是拼接和重复:
name = "小明" print("你好," + name + "!") # 拼接 print("哈哈" * 3) # 字符串乘法:输出 哈哈哈哈哈哈拼接用+,重复用*,这两个和数字运算长得一样,但行为完全不同。这就是“类型不同,行为不同”的直观体验。新手最容易在这翻车:字符串和数字相加会报错,这个坑我后面单独说。
现代Python里最推荐的字符串格式化方式是f-string,在引号前面加个小写f,里面用花括号{}直接塞变量:
name = "小明" age = 18 print(f"我叫{name},今年{age}岁")这个写法我强烈推荐第一天就用,可读性强,也不容易忘了转字符串。后面你会一直用它。
2.3 布尔值和NoneType:一半是开关,一半是“空”
布尔值只有两个:True和False。注意首字母一定要大写,写成true或false会直接报错,它是Python的保留字。布尔值是很多判断逻辑的基础,比如3 > 2,这个表达式的结果就是True。
还有一个新手容易误解的是“假值”这个概念。在Python里,下面这堆看起来毫不相干的东西,在条件判断时统统会被当作“假”:False、0、0.0、""、[]、()、{}、None。这些值本身不是同一个类型,但在“这个有没有货”这个层面上,它们都被算作“空”或“否定”。理解这点,对以后写if判断非常有帮助。
None是NoneType这个类型唯一的值,表示“没有值”,或者“值还没确定”。它不等于0,不等于空字符串,更不等于False,它是一个独立的存在。你可以把它理解为填空题里的横线:还没填,但保留了填的空间。后面写函数时经常用None当作“什么都没返回”的默认值。
2.4 列表、元组、字典、集合:四个容器型选手
前几种类型都像一个值,而列表、元组、字典、集合这四种可以装一堆值,在Python里叫“组合数据类型”。
列表(list)用方括号[],可以放任意类型,而且允许修改:
cart = ["苹果", "香蕉", "牛奶"] cart.append("面包") print(cart) # ['苹果', '香蕉', '牛奶', '面包'] print(cart[0]) # 苹果,下标从0开始 print(cart[1:3]) # ['香蕉', '牛奶'],切片:包前不包后“下标从0开始”是所有程序员绕不过的坎。也就是说第一个元素在[0],不是[1]。切片[1:3]的意思是取下标1到2的元素,最后一个3不包含,记住这个“包前不包后”的规则,切片就不会错。
元组(tuple)用圆括号(),和列表很像,但创建后不能改:
point = (1, 2) point[0] = 5 # 报错:TypeError元组适合放那些“不该变更”的数据,比如坐标、配置项。一旦你想修改,Python直接抛TypeError,这其实是好事,帮你阻止程序里的意外修改。
字典(dict)用花括号{},存的是“键值对”,就是一张查询表:
user = {"name": "小明", "age": 18} print(user["name"]) # 小明 print(user.get("city")) # None,键不存在时返回None而不是报错字典可以把各种信息关联起来,"name"是键,"小明"是值。读取时用方括号必须保证键存在,否则会报KeyError;用get()方法更安全,找不到时返回None。
集合(set)也用花括号,但存的是无序、不重复的元素:
s = {1, 2, 2, 3} print(s) # {1, 2, 3},重复的2被自动去掉集合很适合去重。注意,创建空集合要写set(),不能写{},因为{}会创建一个空字典。
2.5 怎么知道一个变量是什么类型:type() 是你的第一把刀
前面说了这么多种类型,实践中怎么快速知道某个变量到底是什么?一句话:用type()函数。
a = 10 print(type(a)) # <class 'int'> b = 3.14 print(type(b)) # <class 'float'> c = "hello" print(type(c)) # <class 'str'>这个习惯极其重要。很多新手写输出不对,直接盯着代码发呆,其实第一招就应该是print(type(变量)),先确认这个变量到底是什么类型,再决定怎么处理它。我在调试上半数的问题,都是靠这一行代码解决的。
3. 动态类型、类型转换和那些坑
3.1 同一个变量,今天叫int明天叫str
Python是动态类型语言,意思是你不需要声明变量的类型,而且同一个变量可以随时指向不同类型:
x = 10 print(type(x)) # int x = "hello" print(type(x)) # str x = [1, 2] print(type(x)) # list这在C语言或Java里是不可想象的。我刚开始学时会觉得这样很随便,但用久了发现它真的很方便,尤其写临时脚本、做数据分析时,不用为了一个变量反复声明类型。
但方便也带来了隐患。比如你写了一半去接电话,回来忘了x里面到底是什么,一顿操作后报错。这就是为什么我特别强调用type()来排查——动态类型意味着“变量名在哪都行,但类型你说了不算,得看实际指向谁”。
3.2 类型转换的真香用法
Python里几个内置函数专用于类型转换:int()转整数、float()转小数、str()转字符串、list()转列表。最常见的场景就是处理用户输入。input()函数从键盘读到的内容永远是字符串:
age_str = input("请输入年龄:") # 用户输入 18,收到的却是字符串"18" age = int(age_str) # 必须转成整数才能做算术 print(age + 1) # 输出19转换很灵活,int("123")能得到整数123,float("3.14")得到浮点数3.14,str(100)得到"100",list("abc")得到['a', 'b', 'c']。
最常用的格式化技巧也和类型转换有关:当你需要把数字拼进字符串,除了用f-string,也可以手动str(数字)再拼接。但我还是建议优先用f-string,简洁又不容易错。
3.3 类型转换最容易踩的三个坑
第一个坑:int("3.14")会报错。很多人觉得“这能转啊”,但其实int()遇到小数点字符串会直接懵,正确的做法是先转成float再转int:先float("3.14")得到3.14,再int(3.14)得到3。要注意,int(3.9)的结果是3,它是直接截断小数,不是四舍五入。
第二个坑:字符串拼接数字。写了"我今年" + 18,Python报TypeError: can only concatenate str (not "int") to str。解决办法就是用f-string:f"我今年{18}岁"。
第三个坑:用变量名覆盖内置函数。有人把变量命名成list = [1, 2, 3],然后后面又写list("abc")想转列表,结果报TypeError: 'list' object is not callable。因为list这个名字已经被你改成了列表对象,Python以为自己要“调用”一个列表,而不是内置函数。这类报错非常隐蔽,排查方式就是看看有没有把内置名当变量用。
4. 第一天就能上手的3个实操小案例
4.1 跑起来之前:环境和VSCode这三个设置
我默认你已经装好了Python。如果还没装,去python官网下载稳定版,安装时务必勾选“Add Python to PATH”,不然命令行里敲python会提示找不到命令。
编辑器我推荐VSCode,配置也简单:装一个官方Python扩展,打开文件夹,新建.py文件,右上角会出现一个三角形运行按钮,点一下就能跑。跑通第一句print("hello"),后面的练习就有了根据地。
4.2 计算BMI:组合int、float和算术运算
BMI的计算公式是体重(千克)除以身高(米)的平方。这个案例能把变量、浮点数、算术运算符全串起来:
height = 1.75 # 身高,单位:米 weight = 68.5 # 体重,单位:千克 bmi = weight / height ** 2 print(f"你的BMI是:{bmi:.2f}")height ** 2就是身高二次方,f"{bmi:.2f}"的意思是:把bmi当浮点数,保留两位小数。跑一下,你会得到一个带两位小数的结果。试着把身高体重改成自己的,你会立刻明白变量到底“帮我们省了什么事”:不用改公式,只改最开始两行的值就行。
4.3 用f-string输出个人名片
很多新手觉得字符串格式化只是“打印好看”,其实它是程序与人交互的门面。这个案例把字符串和三种常用写法练一遍:
name = "小明" age = 18 city = "上海" skill = "Python" print(f"姓名:{name}") print(f"年龄:{age}") print(f"城市:{city}") print(f"技能:{skill}") print(f"{name}今年{age}岁,来自{city},正在学{skill}")注意,这里age是int类型,但在f-string里直接放进{}完全没问题,不用手动转字符串。这就是为什么我说f-string是新手的救星。
《Python爱心代码》是B站和公众号里常见的流量话题,很多零基础玩家第一次接触Python就是为了打印爱心。它底层其实就是print和字符串重复,比如print("♥" * 5)能输出一排爱心。等你学完循环,用for加空格就能拼出漂亮图案。第一天不用追求花哨,能理解字符串乘法就够了。
4.4 用列表做一个迷你购物车
列表是可变的,这个特点很适合模拟“往购物车里加东西”:
cart = ["苹果", "香蕉", "牛奶"] print("初始购物车:", cart) cart.append("面包") print("加面包后:", cart) print("第一件商品是:", cart[0]) print("一共有", len(cart), "件商品")代码里用到了两个新东西:append()是列表的方法,调用它会修改列表本身;len()是一个内置函数,返回列表的长度,跟字符串的len()是同一个函数。你会发现,不管数据是字符串还是列表,len()的用途一脉相承——数它里面有几个元素。这个案例跑通后,你对“可变”和“容器”的抽象理解会往前迈一大步。
5. 新手翻车现场:常见报错与排查速查
5.1 四个最高频的报错,每个新手都必碰到
NameError: name 'xxx' is not defined八成是变量名拼错了,或者压根没赋值就使用。检查大小写、检查下划线,最好的办法是搜索你的变量名,看每个出现的地方拼写是否一致。
TypeError: can only concatenate str (not "int") to str字符串里直接+数字导致类型冲突。第一反应是问自己:这个变量到底是字符串还是数字?然后决定要不要用f-string或类型转换。
SyntaxError: invalid syntax语法错误,范围很广。新手最常见的原因是:行尾少了冒号、括号没配对、变量名以数字开头、或不小心用了中文标点。提示的位置一般就是出错点,把那一行认认真真看一遍,多半能找到。
TypeError: 'list' object is not callable如果你用了list、str、type这些内置名当变量名,Python就会“智能”地把你本来想调用的函数给替换成你的变量,然后一脸懵地告诉你:这东西不能当函数调。排查方式就是搜一遍代码里有没有用内置名做变量。
5.2 报错排查速查表
| 报错信息 | 常见场景 | 排查思路 | 经典示例 |
|---|---|---|---|
| NameError | 变量未定义或拼写错误 | 检查变量名拼写、作用域 | print(name)但名字是nmae |
| TypeError (拼接) | 字符串和数字用+连接 | 用f-string或转换类型 | "我" + 18 |
| TypeError (不可调用) | 变量覆盖内置函数 | 避免用内置名做变量 | list = [1,2]; list("abc") |
| SyntaxError | 语法、标点、括号错误 | 看报错行和上一行 | if True print(1)缺冒号 |
| KeyError | 字典用[]取不存在的键 | 改用get()或检查键名 | user["city"]但字典没有"city" |
| IndexError | 列表取不存在的下标 | 检查下标是否越界 | cart[100]但列表只有3个元素 |
这几种错误不用背,遇到时回来看就行。关键在于:报错信息里的方括号、单词、行号,都是Python给你的线索,不要害怕读它。
5.3 我的独家排查习惯
我学了这么久,最大的体会是:排查程序问题的第一步永远是“确认类型”。不管是报错还是结果不对,我都会在关键位置加一行print(type(变量)),先搞清楚Python眼里它到底是什么。很多百思不得其解的Bug,在看到<class 'str'>的那一刻瞬间就明白了。
另一个习惯是“最小化测试”。发现报错时,不要盯着整个文件瞎猜,抽出出问题的三行代码单独跑一下。比如怀疑类型转换有问题,就在终端里敲一行int("3.14"),立刻就能验证想法。这种“小步验证”的思路,比反复看代码效率高得多。
还有一个VSCode里的实用技巧:调试时可以在左侧“运行和调试”面板里添加Watch(监视),把变量名加进去,然后慢慢单步执行,实时看这个变量到底在什么时候变了、变成了什么类型。这比一堆print打印日志直观得多。第一天用不上,但知道有这么个工具,等写复杂程序时不至于两眼一抹黑。
我个人在实际学习中的体会是,第一天的目标不要定得太高。别指望一天就把所有概念都吃透,那是几个月后的事。今天只要做到三件事:能写出带变量的代码,知道type()这个工具存在,遇到报错敢去读提示信息。有这三个基础,第二天学条件判断和循环时会顺利得多。
最后再分享一个在社区里很实用的小技巧:把你今天练过的代码保存在一个叫day1_variable.py的文件里,作为你的“代码手账”。以后遇到类型转换报错,翻回去看一眼自己写过的例子,往往比搜索来的答案更顺手——因为那是你自己跑过的逻辑,印象最深。