首页 / 资讯中心 / 文章详情

第二章 Python语言基础

第二章 Python语言基础 ★ FEATURED ARTICLE
第二章 Python 语言基础第一章我们把环境搭起来了写了个能跑的猜数字游戏。但有件事我没敢在那时候告诉你第二章让我们来亲身感受下。打开命令行试一下这行。 0.1 0.2 0.30000000000000004别急着怀疑电脑也别怀疑 Python这个结果有它自己的道理本章会把它讲清楚。上一章我们写的是能跑就行的代码这一章要学怎么写对的代码。变量怎么存东西、数据分哪几类、运算符有哪些、输入输出怎么做得体面。学完你能写出带计算、带格式化输出、能跟人交互的小工具。我会按照下面内容讲解。第二章 Python 语言基础 │ ├── 1. 语法特点 → 缩进、换行、注释、大小写、动态类型 ├── 2. 保留字与标识符 → 35 个不能碰的词 命名规矩 ├── 3. 变量 → 它是标签不是盒子以及三种赋值写法 ├── 4. 基本数据类型 → 数字 / 字符串 / 布尔 / None 互相转换 ├── 5. 运算符 → 算术、比较、逻辑、优先级 ├── 6. 基本输入输出 → print 的隐藏参数、input 的返回类型 ├── 7. 实战 → 名片 / BMI / 小票 / 秒数换算 └── 8. 小结 → 一张表收口 5 道题 下一章预告老规矩别只阅读。把代码敲进你的常用IDE跑一遍改点参数再跑一遍。一、Python 语法特点1.1 用缩进来分块不用花括号这是 Python 最显眼的特征。别的语言用{}包住代码块Python 用缩进。// C 语言靠花括号 if (score 60) { printf(及格); printf(可以回家了); } printf(结束);# Python靠缩进 if score 60: print(及格) print(可以回家了) print(结束)每条内容给你讲解下。if score 60: ← 行尾的冒号等于说下面要开新块了 print(及格) ← 缩进 4 空格属于 if 的地盘 print(可以回家了) ← 同样缩进还是 if 的地盘 print(结束) ← 退回行首已经出了 if无论如何都会执行四条规矩记牢。同一个代码块里每一行的缩进量必须一模一样。推荐 4 个空格别用 Tab。混用会报IndentationError第一章 Q6 讲过怎么解决。冒号:是下面要开新块的信号灯看到if/for/def后面跟着冒号下一行就得缩进。缩进结束代码块就结束。没有end也没有}。我刚开始写 Python 的时候最不习惯的就是这个。写了两周之后反倒回不去了看别的语言那一堆花括号会觉得多余。1.2 一行一句分号可有可无Python 里换行就代表这句话说完了不用加分号。a 1 b 2非要写在一行也行用分号隔开。a 1; b 2 # 语法没问题但没人这么写一句话太长想换行用反斜杠或者直接套括号。total 1 2 3 \ 4 5 6 result (1 2 3 4 5 6)我个人偏好括号那一种反斜杠后面不小心多打个空格就报错太脆了。1.3 注释单行注释用#。# 这是单行注释 price 19.9 # 行尾也可以写注释多行说明用三个引号包起来。严格说它是个字符串字面量但放在文件开头或者函数下面Python 会把它当成文档字符串docstring。 价格计算模块 汇率按 7.2 算用之前记得确认下最新汇率 注释这事我只有一条建议写为什么别写做什么。# ❌ 废话注释代码本身已经说了在干嘛 price price * 0.8 # 价格乘以 0.8 # ✅ 有价值说清了 0.8 是怎么来的 price price * 0.8 # 会员八折运营给的口径1.4 大小写敏感Name、name、NAME在 Python 眼里是三个完全不同的东西。写错大小写是最常见的低级错误之一报错信息通常是NameError: name xxx is not defined。1.5 动态类型万物皆对象Python 的变量没有固定类型同一个变量可以随时装不同的东西。x 10 # x 现在是整数 x hello # 现在变成了字符串完全合法 x [1, 2, 3] # 又变成了列表想知道一个东西是什么类型问type()。 type(10) class int type(3.14) class float type(abc) class str对比一下静态语言。Java 里写int x 10;之后x这辈子只能是整数塞个字符串进去编译器直接报错。Python 没有这层约束写起来快代价是类型错误要等到运行时才暴露。二、保留字与标识符2.1 35 个不能碰的保留字保留字关键字是 Python 自己留着用的词你不能拿它们当变量名。想知道有哪些直接问解释器。import keyword print(keyword.kwlist) print(len(keyword.kwlist)) # 35按用途分个组看着就不乱了。分组保留字逻辑与空值TrueFalseNoneandornotisin控制流ifelifelseforwhilebreakcontinuepass定义与返回defclasslambdareturnyield异常处理tryexceptfinallyraiseassert作用域与删除globalnonlocaldel导入与上下文importfromaswith异步协程asyncawait几个容易踩的点。TrueFalseNone首字母必须大写。写成true或none会报NameError这是从其他语言转过来的人最常犯的错。matchcasetype_属于软关键字Python 3.10 引入match语句时加的。它们只在特定位置有特殊含义别的地方还能当变量名用但我不建议这么干容易把读代码的人绕晕。别拿内置函数名当变量。liststrdictidtypesummax这些不是保留字你确实能把它们覆盖掉然后整段代码就开始莫名其妙地报错。# 我年轻时候干过的蠢事 list [1, 2, 3] print(list) # 还行[1, 2, 3] x list(abc) # TypeErrorlist 已经被你改成列表了不再是那个函数2.2 标识符命名规则标识符就是你给变量、函数、类起的名字。规则很简单。名字合法吗原因name✅字母组成user_name✅字母加下划线_count✅下划线开头age2✅数字不在开头就行姓名✅Python 3 支持 Unicode 标识符2age❌数字开头user-name❌中划线会被当成减号user name❌不能有空格class❌保留字$price❌特殊字符只允许下划线中文变量名语法上合法我见过有人这么用。两年之后他自己回来看代码也看不懂别学。2.3 命名约定规则是强制的约定是自发的。按 PEP 8Python 官方代码风格指南来就行。场景约定例子变量、函数小写 下划线user_nameget_price()常量全大写 下划线MAX_RETRYPI类名大驼峰StudentInfo内部使用单下划线开头_helper()魔术方法双下划线包起来__init____str__名字长短这事我有点体会宁可长一点也别缩写到看不懂。usr_nm这种省三个字符的写法半年后你得靠猜。2.4 三个自检小技巧import keyword keyword.iskeyword(class) # True是保留字 keyword.iskeyword(name) # False可以放心用 user_name.isidentifier() # True是合法标识符 2age.isidentifier() # False起名字拿不准的时候这两个函数比翻文档快。三、变量3.1 变量是标签不是盒子很多入门书把变量画成一个装东西的盒子这个比喻在 Python 里会带你走偏。更准确的形容是这样。a 10 ┌────────┐ ┌───────────────┐ │ a │─────────▶│ 整数对象 10 │ └────────┘ └───────────────┘ 变量名 数据躺在内存里 b a ┌────────┐ ┌───────────────┐ │ a │─────────▶│ 整数对象 10 │ ├────────┤ ▲ └───────────────┘ │ b │─────┘ └────────┘ 两个标签贴的是同一个对象变量就是一张贴在对象上的标签。赋值这个动作是把标签贴到某个对象上。理解这一点下面这段代码的结果你就能预测了。a 10 b a a 20 # a 撕下来贴到 20 上b 还贴在 10 上 print(b) # 10没跟着变换成列表就不一样了。a [1, 2, 3] b a a.append(4) # 改的是对象本身不是换标签 print(b) # [1, 2, 3, 4]b 也跟着变了区别在于整数是不可变对象改不了只能换一个列表是可变对象能在原地改内容。这个话题第四章讲列表时还会展开。3.2 三种赋值写法# 1. 单个赋值 name 张三 # 2. 多元赋值一次给多个变量等号两边数量必须一致 x, y, z 1, 2.5, abc # 3. 交换两个变量Python 里不用临时变量 a, b 1, 2 a, b b, a # 交换完成a 是 2b 是 1 # 4. 链式赋值 pi rate 0.0交换变量那一行我第一次见到的时候愣了一下别的语言都得请出第三个变量当搬运工。多元赋值在后面拆包的时候还会用到很好使。3.3 id() 和 isid()返回对象在内存里的身份证号is比的就是这个号而比的是值。x [1, 2, 3] y [1, 2, 3] print(x y) # True值一样 print(x is y) # False两个各自独立的对象日常判断相等用就够了。只有一种情况必须用is判断是不是None。result None if result is None: # ✅ 正确写法 print(还没算出来) if result None: # ❌ 别这么写 print(还没算出来)顺带提一句CPython 把 -5 到 256 之间的整数做了缓存复用所以这个范围内用is比较会得到一些反直觉的结果。别去依赖它那是实现细节不是语言规则。3.4 del 与常量del删掉的是标签不是对象。a 10 del a print(a) # NameError标签没了Python 里没有真正的常量。PI 3.14159只是大家约定全大写代表别改你硬要改它也不拦着。靠自觉。四、基本数据类型4.1 类型家族树Python 内置类型 │ ├── 数字 Number │ ├── int 整数精度无限 │ ├── float 浮点双精度 │ ├── bool 布尔int 的子类 │ └── complex 复数用得少 │ ├── 序列 Sequence │ ├── str 字符串不可变 │ ├── list 列表可变 ← 第四章细讲 │ └── tuple 元组不可变 ← 第四章细讲 │ ├── 映射 dict 字典 ← 第四章细讲 ├── 集合 set 集合 ← 第四章细讲 │ └── NoneType 只有一个值 None本章只讲intfloatboolstrNone这五个剩下的第四章之后逐个来。4.2 数字age 18 # int price 19.9 # float big 2 ** 1000 # intPython 的整数没有上限2 ** 1000这行在别的语言里会直接溢出Python 算出来是一个 302 位的数一点不慌。 2 ** 1000 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376浮点数是双精度精度大约 15 到 16 位有效数字末尾那点误差是二进制表示的锅。布尔值在 Python 里是整数的子类True就是 1False就是 0。 True True 2 isinstance(True, int) True它真正解释的是另一件事为什么if 1和if True效果一样。4.3 字符串四种写法各有各的用处。s1 单引号 s2 双引号 s3 三引号 可以跨行写 s4 rC:\new\test # 原始字符串反斜杠不当转义符写 Windows 路径时r...能救命不然\n会被当成换行。转义字符就那么几个常用的。转义含义\n换行\t制表符\\一个反斜杠\\引号本身字符串可以按下标取字符下标从 0 开始负数表示从右往左数。P y t h o n 0 1 2 3 4 5 -6 -5 -4 -3 -2 -1s Python print(s[0]) # P print(s[-1]) # n print(s[1:4]) # yth左闭右开取到下标 4 之前 print(s[:3]) # Pyt print(s[3:]) # hon print(s[::-1]) # nohtyP倒着来切片是s[起始:结束:步长]左闭右开。[::-1]反转字符串这个技巧值得背下来。常用方法挑几个高频的。方法作用例子len(s)长度len(abc)→ 3s.upper()转大写abc.upper()→ ABCs.lower()转小写反过来s.strip()去掉首尾空白处理用户输入必备s.split(,)按分隔符切开a,b.split(,)→[a, b], .join(...)拼接第五章用s.replace(a, b)替换a-b.replace(-, )s.find(x)找位置找不到返回 -1x in s判断子串返回布尔th in Python→ True字符串是不可变的改单个字符会报错。s Python s[0] p # TypeError: str object does not support item assignment想要新字符串就重新赋值s python。4.4 类型转换int(18) # 18字符串转整数 int(3.99) # 3直接截断不是四舍五入 float(3.14) # 3.14 str(100) # 100 bool() # False bool(0) # True非空字符串一律为真几个坑。表达式结果说明int(3.14)报错得先转 float 再转 intint(float(3.14))int(abc)报错内容不是数字int(3.99)3向零截断不是四舍五入bool(0)True字符串 0 不是假值str(None)None处理用户输入时int()最容易炸因为用户什么都可能输。第一章那个温度转换器输入 abc 就崩对吧。4.5 格式化三种写法第一种%占位符老派写法现在新代码里基本不写了但你读老代码会遇到。print(姓名%s年龄%d % (张三, 18))第二种str.format()Python 2.6 之后的主流。print(姓名{}年龄{}.format(张三, 18))第三种f-stringPython 3.6 之后的首选我强烈推荐这个。name 张三 age 18 print(f姓名{name}年龄{age})f-string 里能直接写表达式还能带格式说明符。price 3.14159 print(f{price:.2f}) # 3.14保留两位小数 print(f{price:10.2f}) # 右对齐占 10 位 print(f{42:03d}) # 042不足补零 print(f{1234567:,}) # 1,234,567千分位 print(f{0.256:.1%}) # 25.6%百分比4.6 布尔与真值测试下面这些东西在if里一律是假其余都是真。假值说明FalseNone布尔假与空值00.00j各种零空字符串[](){}set()空容器判断真假不用刻意转 bool直接放进if就行。name input(请输入姓名) if name: # 空字符串就是假不用写 name ! print(f你好{name})五、运算符5.1 算术运算符运算符含义例子结果加7 29-减7 - 25*乘7 * 214/除7 / 23.5//整除7 // 23%取余7 % 21**幂2 ** 101024三个暗坑逐个说。第一/永远返回浮点数哪怕能整除。 10 / 5 2.0 # 注意那个 .0类型是 float 10 / 3 3.3333333333333335第二//是向下取整不是四舍五入负数方向要特别小心。 7 // 2 3 -7 // 2 -4 # 不是 -3它往更小的方向取整第三%的结果符号跟着除数走这一点跟 C、Java 不一样。 7 % 3 1 -7 % 3 2 # 除数 3 是正数结果就是正的 7 % -3 -2 # 除数是负数结果跟着变负5.2 比较运算符!结果是布尔值。Python 有个别语言没有的糖链式比较。age 25 if 18 age 60: # 等价于 18 age and age 60 print(在职年龄段)5.3 逻辑运算符andornot三个都会短路求值能省一步就省一步。name result name or 匿名用户 # name 为空取后者 print(result) # 匿名用户这里有个必须知道的细节and和or返回的不是布尔值是操作数本身。 3 or 5 3 # 3 是真的直接返回它不看后面 0 or 5 5 # 0 是假的返回后面那个 3 and 5 5 # 前面为真结果取决于后面返回 5 0 and 5 0 # 前面为假直接返回它记法是or找第一个为真的and找第一个为假的都找不到就返回最后那个。5.4 赋值运算符count 0 count 1 # 等价于 count count 1 count * 2 count - 3-*///%**全套都有。Python 里没有和--写i不会报错被当成两个正号但也不会加一这个坑我见过好几个人踩。Python 3.8 加了个海象运算符:能在表达式里顺手赋值。# 不用海象 n input(输入点什么) while n ! q: print(n) n input(输入点什么) # 用海象 while (n : input(输入点什么)) ! q: print(n)5.5 身份与成员运算符a is b # 比身份证号同一个对象 a is not b th in Python # 成员判断字符串里就是子串判断is和的区别前面讲过了再强调一次比值用比 None 用is。5.6 位运算符了解即可。我写这么多年业务代码用上位运算的场合一只手数得过来基本就是权限位和状态标记这两类。运算符含义按位与|按位或^按位异或~按位取反左移右移 6 3 # 110 011 010 2 1 3 # 左移三位等于乘 8 85.7 优先级金字塔** 最高 ~ x -x 正负号 * / // % - ^ | ! 比较 is is not in not in not and or - * ... 最低记不住就加括号。我本人就是这么干的写了这么多年遇到三四个运算符叠在一起的时候照样加括号不丢人。括号还能让读代码的人一眼看懂你的意图。5.8 浮点数精度问题回到开头那个问题。 0.1 0.2 0.30000000000000004这是二进制浮点的通病换 Java、C 也一样跟 Python 没关系。0.1 在二进制里是个无限循环小数就像十进制里的 1/3 一样存的时候只能截断误差就这么攒下来了。两个应对办法。# 1. 只要显示好看用 round 或格式化 print(round(0.1 0.2, 2)) # 0.3 print(f{0.1 0.2:.2f}) # 0.30 # 2. 算钱这种要精确的场合用 decimal from decimal import Decimal print(Decimal(0.1) Decimal(0.2)) # 0.3算钱一定用Decimal别用 float这是行业共识。六、基本输入和输出6.1 print 的三个隐藏参数大部分人只用到了print()的第一个参数其实它还有三个能玩的。print(苹果, 香蕉, 橙子) # 默认空格分隔 print(苹果, 香蕉, 橙子, sep | ) # 换成竖线分隔 print(加载中, end) # 结尾不换行 print(完成)第三个参数end默认是换行符\n改成空字符串就不换行了。用它刷个进度条。import time for i in range(101): print(f\r当前进度 {i}%, end) time.sleep(0.02) print(\n搞定)第四个参数file能把内容直接写进文件。with open(log.txt, w, encodingutf-8) as f: print(程序启动, filef)6.2 input 永远返回字符串这一点第一章提过这里再钉一次因为它是新手 bug 的头号来源。┌─── 终端 ────────────────────────────┐ │ 请输入年龄18 │ │ │ │ 你拿到的是字符串 18 │ │ int() 之后才是数字 18 │ │ 18 1 181 ← 拼接 │ │ int(18) 1 19 ← 加法 │ └─────────────────────────────────────┘age input(请输入年龄) # 用户输入 18 print(age 1) # TypeError字符串不能跟整数相加 print(int(age) 1) # 196.3 格式化输出实战想要输出看起来像那么回事掌握这四个就够用了。写法效果输出f{3.14159:.2f}保留两位小数3.14f{42:03d}补零到三位042f{1234567:,}千分位1,234,567f{0.256:.1%}百分比25.6%f{abc:10}右对齐占 10 位前面补 7 个空格f{abc:^10}居中两边各补空格对齐在做表格和小票的时候特别有用下面的实战三会用到。七、实战建个D:\code\python-learn\chapter02\目录本章代码都放这儿。实战一个人信息名片练的是变量、多行字符串和 f-string。# card.py name 张三 job 后端工程师 city 杭州 years 3 skills Python / MySQL / Docker card f ╔══════════════════════════════════╗ ║ 个人名片 ║ ╠══════════════════════════════════╣ ║ 姓名{name} ║ ║ 职业{job} ║ ║ 城市{city} ║ ║ 年限{years} 年 ║ ║ 技能{skills} ║ ╚══════════════════════════════════╝ print(card) print(f{name} 在 {city} 做了 {years} 年 {job})运行结果。╔══════════════════════════════════╗ ║ 个人名片 ║ ╠══════════════════════════════════╣ ║ 姓名张三 ║ ║ 职业后端工程师 ║ ║ 城市杭州 ║ ║ 年限3 年 ║ ║ 技能Python / MySQL / Docker ║ ╚══════════════════════════════════╝ 张三 在 杭州 做了 3 年 后端工程师右边框对不齐对吧。中文字符在终端里占两个英文字符的宽度靠数空格对齐是治不好的得按显示宽度算。这也是为什么做小票那种对齐输出时我更愿意用下面的等宽思路。实战二BMI 计算器练的是输入、类型转换、算术运算符和分支判断。# bmi.py name input(请输入姓名) weight float(input(请输入体重kg)) height float(input(请输入身高m)) bmi weight / (height ** 2) print(f\n{name} 的 BMI 指数是 {bmi:.1f}) if bmi 18.5: level 偏瘦 elif bmi 24: level 正常 elif bmi 28: level 超重 else: level 肥胖 print(f身体状态{level})跑一遍。请输入姓名张三 请输入体重kg70 请输入身高m1.75 张三 的 BMI 指数是 22.9 身体状态正常这里有两个细节。height ** 2比height * height更直观指数运算就用**。输出用:.1f保留一位小数不然 BMI 会甩出一长串小数。实战三购物小票练的是运算符、f-string 对齐和格式化。这个例子我很喜欢因为它输出的成果看着就像个正经东西。# receipt.py shop_name 街角便利店 item1, price1, count1 牛奶, 3.5, 2 item2, price2, count2 面包, 8.0, 1 item3, price3, count3 咖啡, 12.8, 3 amount price1 * count1 price2 * count2 price3 * count3 discount 0.9 # 会员九折 payable amount * discount payable round(payable, 2) # 算钱保留两位 line - * 42 print(f {shop_name}) print(line) print(f{商品:8}{单价:8}{数量:8}{小计:12}) print(line) print(f{item1:8}{price1:8.2f}{count1:8}{price1 * count1:12.2f}) print(f{item2:8}{price2:8.2f}{count2:8}{price2 * count2:12.2f}) print(f{item3:8}{price3:8.2f}{count3:8}{price3 * count3:12.2f}) print(line) print(f{合计:8}{:8}{:8}{amount:12.2f}) print(f{折扣:8}{:8}{:8}{discount:11.1%}) print(f{应付:8}{:8}{:8}{payable:12.2f}) print(line) print( 谢谢惠顾欢迎下次光临)输出长这样。街角便利店 ------------------------------------------ 商品 单价 数量 小计 ------------------------------------------ 牛奶 3.50 2 7.00 面包 8.00 1 8.00 咖啡 12.80 3 38.40 ------------------------------------------ 合计 53.40 折扣 90.0% 应付 48.06 ------------------------------------------ 谢谢惠顾欢迎下次光临几个值得学的点。f{牛奶:8}里的8是左对齐占 8 个字符宽8是右对齐。数字右对齐才符合看小票的习惯。price1, count1 3.5, 2这种多元赋值把三个商品的参数一次性摆开比一行行写清爽。算钱那一步round(payable, 2)不能省不然48.060000000000002这种结果会直接打印出来。折扣那行用了:11.1%百分比格式自带一个%号所以宽度比别的多留一位。等等{discount:11.1%}里的 discount 是 0.9输出是90.0%。如果你想要显示打九折写成f{(1 - discount) * 100:.0f}% 优惠更直白。加练秒数换算成时分秒//和%的经典练习题面试也爱考。# seconds.py total int(input(请输入总秒数)) hours total // 3600 minutes total % 3600 // 60 seconds total % 60 print(f{total} 秒 {hours} 小时 {minutes} 分 {seconds} 秒)跑一下。请输入总秒数3725 3725 秒 1 小时 2 分 5 秒拆解一下这三行。// 3600拿到能被整除的小时数% 3600拿到扣掉小时后剩下的秒数再// 60就是分钟最后% 60剩下的是秒。想让输出更好看点可以补零f{hours:02d}:{minutes:02d}:{seconds:02d}。八、小结8.1 本章知识小结模块你现在应该能做对的事自测语法特点说清缩进规则和注释写法□ 能解释为什么 Python 不用花括号保留字知道 35 个保留字会查□ 能用keyword.iskeyword()判断标识符起合规且规范的名字□ 能说出 snake_case 用在哪变量理解标签语义会三种赋值□ 能解释a, b b, a为什么能交换数据类型分得清 int / float / str / bool / None□ 知道bool(0)是 True类型转换会 int() float() str() 互转□ 知道int(3.14)会报错运算符会用算术比较逻辑懂优先级□ 能说出-7 // 2等于几输入输出会用 print 参数和 f-string 格式化□ 能输出对齐的小票8.2 五句话记住本章缩进就是语法冒号开块4 空格别混 Tab。变量是标签赋值是贴标签is比地址比值。/永远得浮点//向下取整%符号跟除数。input 拿到的一定是字符串要计算就得转类型。算钱用 Decimal别用 float。8.3 课后练习温度转换器升级输入摄氏度同时输出华氏度和开尔文K ℃ 273.15都保留一位小数。计算圆的周长和面积输入半径rπ 取 3.14159两个结果都保留两位小数。输入一个三位数用//和%把它拆成百位、十位、个位三个数字分别打印。写个个人信息录入输入姓名、年龄、身高用 f-string 拼成一句话输出年龄那栏右对齐占 5 位。挑战题输入一个总天数换算成「x 年 x 个月 x 天」一年按 365 天算一个月按 30 天算想想余数的处理顺序。8.4 下一章第三章讲流程控制if分支的各种写法、for和while循环、break和continue还有range()这个循环好搭档。这一章写的 BMI 和小票到时候都能用循环重写一遍代码能短一半。附录运算符与内置函数速查卡类别运算符 / 函数算术-*///%**比较!逻辑andornot赋值-*///%**:身份isis not成员innot in类型转换int()float()str()bool()常用内置type()id()len()print()input()round()abs()max()min()记不住就回来查这张表我当年贴在显示器边上贴了半年。
阅读完成 · 觉得有帮助?
咨询建站