【Python3基础】03-基本数据类型与表达式
[TOC] 系列文章导航【Python3基础】01-Python 环境与开发工具【Python3基础】02-输入输出与程序运行【Python3基础】03-基本数据类型与表达式【Python3基础】04-字符串与格式化【Python3基础】05-容器数据类型【Python3基础】06-条件判断与循环【Python3基础】07-函数基础与参数设计【Python3基础】08-高阶函数、闭包与装饰器【Python3基础】09-切片、推导式与迭代协议【Python3基础】10-类与对象【Python3基础】11-继承、多态与对象协议【Python3基础】12-动态类型与元编程【Python3基础】13-Python 常用设计模式【Python3基础】14-模块、包与虚拟环境【Python3基础】15-文件、目录与内存流【Python3基础】16-序列化、异常与调试【Python3基础】17-常用标准库与第三方库【Python3基础】18-多进程、多线程与协程【Python3基础】19-Socket 与 TCP、UDP 编程【Python3基础】20-网络应用与异步 IO概述变量保存的是对象引用运算符描述的是对象之间的计算和判断。数据类型和表达式是后续所有 Python 程序的地基。本篇把整数、浮点数、字符串、布尔值、空值、变量与常用运算符放在同一条学习线上重点说明每类数据能参与什么操作以及表达式最终会得到什么结果。本篇知识路线字面量 ──► Python 对象 ──► 变量名 10 int count 3.14 float price True bool enabled基本数据类型编程就是利用计算机程序模拟现实世界既然是模拟现实世界首先第一个问题就是用计算机程序定义什么样的数据类型来对等现实世界的类型。比如我们现实世界中有数字、真假、文本、图形、音频、视频等各种各样的数据我们在计算机中写程序就需要定义相应的数据类型来存储这些类型。我们 Python 中既有基本数据类型又有高级数据类型基本类型就如朴素唯物主义中的金木水火土高级数据类型就如金木水火土组成的更复杂的物质。高级数据类型都是由基本数据类型组成本节课我们先学习基本的数据类型。整数类型intPython 可以处理任意大小的整数当然包括 0 和负整数在程序中的表示方法和数学上的写法是一样的。比如100-10 等。a10b0c-10print(a)print(b)print(c)Python 语言的整数类型不但支持数学上的所有运算比如加减乘除开方等等还支持和字符串相乘以及其它操作等等。count3languagepythonprint(count*language)浮点数类型float数学上的小数在程序中叫浮点数浮点数当然可以包括正小数和 00 的写法要以小数的形式写和负小数。比如10.10.0-10.1 等。a10.1b0.0c-10.0print(a)print(b)print(c)整数和浮点数在程序中做运算的方式是不同的整数之间的四则运算结果是整数浮点数和浮点数或和浮点数和整数之间的运算结果是浮点数但有可能会出现四舍五入的现象。aint2bint3afloat2.0bfloat3.0print(aintbint)print(afloatbfloat)print(aintafloat)在 Python 中我们把整数类型和浮点数类型统称为数字类型其它语言中并没有这种统称大家用 Python 要习惯这种叫法。字符串类型str字符串是以英文字符单引号或英文字符双引号或英文字符三个单引号括起来的任意字符比如 ‘123’“abc”‘’‘老鸟Python’‘’ 在此我们用三个单引号作为程序作者的说明放在开头。author老鸟Pythonstrone123strtwoabcprint(strone)print(strtwo)如果字符串内部既包含单引号又包含双引号那应该如何在程序中写字符串呢我们可以用转义字符 \ 来标识 比如定义一个字符串Im studying python 在程序中我们可以写成I\m studying \python\。stroneI\m studying \python\print(strone)Python 还允许用在字符串前面加上 r 表示引号内的字符串默认不转义。stronerI\m studying \python\print(strone)如果我们程序中字符串的长度很多需要换行我们对使用单引号双引号或三个单引号的字符串都可以使用\来连接我们在程序中写的换行字符串打印出来不包含换行或者用三个单引号来写多行字符串会保留换行。 大家运行以下程序看看结果有什么区别。stronewhat are u doing baby\ balabalabala\ ahaahaahaahaahaprint(strone)strtwowhat are u doing baby balabalabala ahaahaahaahaahaprint(strtwo)大家经过上面两个例子应该能理会到我们一般习惯于用三个单引号作为程序的注释性说明或者多行字符串。布尔类型bool我们现实世界中存在非真既假的事物在此我们用布尔类型表示布尔类型只有两种值要么是 True要么是 False。ruhuaisgirlTrueruhuaisbeautyFalseprint(ruhuaisgirl)print(ruhuaisbeauty)数据可以通过比较运算符!,来进行运算结果是布尔值。print(32)print(3!2)print(32)print(32)我们把 and、or 或 not 叫做布尔运算只有布尔类型的值进行布尔运算结果才是布尔值。其它类型数据进行布尔运算我们在运算符章节讲解。print(TrueandFalse)print(TrueorFalse)print(notTrue)空值类型NoneType空值类型只有一个值用 None 表示。None 值和 0False空字符串等等不是一个值 因为他们的数据类型都不一样比如 0 是个整数类型False 是布尔类型空字符串是字符串类型而 None 是 NoneType 类型。print(None0)print(NoneFalse)print(None)其它语言中没有空值类型的概念一般用 False 表示NoneType 是我们 Python 语言独有的数据类型。变量和常量变量的概念基本上和初中代数的方程变量是一致的只是在计算机程序中变量不仅可以是数字还可以是任意数据类型比如我们上节课刚刚学过的基本数据类型或者我们后面要学的自定义数据类型。所谓常量就是不能改变的变量我们现实世界中存在这样的不可改变的东西比如圆周率 π万有引力常量 G 等等都是不可改变的量。本节我们学习变量和常量的定义和语法。变量在程序中我们用一个变量名来表示变量变量名的写法必须是大小写英文数字和_的组合且记不能用数字开头。小说明英文符号#表示注释#后面的内容程序在执行时会忽略掉只有我们程序员才能看到。name jack NAME jack _name jack name2 jack 2name jack # 错误数字不能在前面 name! jack # 错误不支持其它字符Python 中内置一些关键字我们可以使用 keyword 模块提供的函数打印出当前 Python 解释器规定的所有关键字注意 Python 版本不同所规定的关键字有所变化虽然这些关键字符合变量的命名规则但是 Python 解释器规定不能使用这些关键字作为变量名否则解释器报语法错误。importkeywordprint(keyword.kwlist)# 列出当前 Python 解释器的所有关键字and9# 关键字 and 不可以作为变量名在 Python 中英文等号 是赋值运算符可以把任意数据类型赋值给变量同一个变量可以反复赋值而且可以是不同类型的变量程序中的等号和数学上的等号不是一个意思 Python 程序中用两个等号来表示数学上的等号。data2print(data)dataTrueprint(data)data老鸟Pythonprint(data)print(22)我们也可以把一个变量赋值给另一个变量这个操作实际上是修改变量指向另一个变量所指向的数据看如下代码。stronePythonstrtwostrone stroneHelloprint(strone)print(strtwo)我们对以上代码进行分析看看每一句代码在内存中是如何表示的对于第一句代码strone PythonPython 解释器首先检查字符串 “Python” 中的每个字符在内存中是不是存在如果不存在就给每个字符分配内存空间如果存在则不给该字符创建内存然后 Python 解释器再次在内存中开辟一块内存比如内存地址为0x8899aa 的地方存放字符串 “Python” 中每个字符的地址然后 Python 解释器再次在内存中开辟一块内存存放 strone 变量比如内存地址为0x223388 strone 变量的值就是字符串 Python的地址。注意0x 开头是表示用十六进制表示数值。对于第二句代码strtwo stronePython 解释器再次在内存中开辟一块内存存放 strtwo 变量比如内存地址为0x223399然后 Python 解释器把 strone 变量内存里面的值0x8899aa赋值给 strtwo 的内存目前执行上面两句代码后的内存模型如下图。对于第三句代码strone HelloPython 解释器首先检查字符串 “Hello” 中的每个字符在内存中是不是存在如果不存在就给每个字符分配内存空间如果存在则不给该字符创建内存 Python 解释器再次在内存中开辟一块内存比如内存地址为0x8899bb 的地方存放字符串 “Hello” 中每个字符的地址然后 Python 解释器把字符串 “Hello” 的地址0x8899bb赋值给 strone 的内存最后的结果是 strone 内存的值为 0x8899bbstrtwo 内存的值为 0x8899aa如下图。注意Hello字符串中 有两个l字符成员在 Python 解释器第一次给l分配内存后就不会再给第二个l分配内存了所以字符串 “Hello” 中两个l成员的内存地址是一样的大家可以通过 Python 的 id 函数验证一下字符串中两个l成员的地址是否一样。stroneHelloprint(id(strone[2]))# 第一个 l 成员的内存地址print(id(strone[3]))# 第二个 l 的内存地址常量所谓常量就是不能改变的变量Python 中定义常量和其它语言中定义常量不同比如 c 语言可以在变量名前加上关键字 const 来定义这个变量是常量常量在定义的时候必须初始化在这之后就不能修改该常量的值否则解释器会报错。 Python 语言没有关键字可以把一个变量定义成一个常量所以 Python 语言本身并没有常量的语法定义但我们一般对全大写字母命名的变量来假定它是常量程序员本身约定成俗就行了。PI3.14159# 告诉程序员变量 PI 不要修改。PI3.2# 虽然修改解释器不会报错但最好不要修改。print(PI)在任何编程语言中字符串都是存放在常量区所以我们都说字符串是常量值也就是说任何一个变量的值如果是字符串的话我们则不能通过该变量修改字符串内的值。strone Hello strone[1] x # Python 解释器会报错Python 基本类型中的数字字符串None 和 bool 值True 和 False本身不能修改我们通常把这些数据类型的值叫做右值但在 Python2 中布尔值可以修改。8 9 # 8是右值并且 8 本身不符合变量名命名规则 hello byebye # hello 是右值并且不符合变量名命名规则 None 8 # None 是右值不可以修改 False True # False 是右值不可以修改初级运算符程序中少了运算就如人不会说话不会行走便成了行尸走肉我要要让程序动起来自然是少不了运算。在编程语言中运算符是一种告诉解释器或编译器执行特定的数学或逻辑操作的符号大家注意 Python 是动态语言所以是调用解释器执行代码。Python 语言内置了丰富的运算符并提供了以下类型的运算符算术运算符、比较运算符、位运算符、逻辑算符、成员运算符、身份运算符、三目算符等等。注意由于变量常量自定义类型变量都可以通过运算符进行运算在本节的描述中我们且把参与运算的各种类型的数据统一称为对象。算术运算符编程语言中的算符运算符和数学中的算术运算符大体一致 但有一些地方会不同假设对象a 7 b 3通过各种算符运算后的结果如下表格。算术运算符解释例子| 加表示两个对象相加 | a b 结果为 10| 减表示两个对象相减或表示负数 | a - b 结果为 4 -a 的结果为 -7| 乘表示两个对象相乘 | a * b 结果 为 21 / | 除表示两个对象相除 | a / b 结果为 2.3333333333333335 ** | 幂a的b次幂 | a ** b 结果为 343 // | 整除得到商的整数部分 | a // b 结果为 2 % | 取模取除法的余数 | a % b 结果为 1我们要区分算术运算符 / 和 // 的区别运算符 / 的结果和数学上的除法结果一样而 // 的结果是取运算结果的 整数部分注意如果参与运算的数据有任意一个数是小数则整数部分用浮点数表示。a7b3print(a/b)# 2.3333333333333335print(a//b)# 取整数部分 2a7.0b3print(a/b)# 2.3333333333333335print(a//b)# 取整数部分 2用浮点数 2.0 表示注意Python 语言中没有 和 – 运算符这两种运算符在其它语言中很常用。比较运算符编程语言中的比较运算符和数学上一致 假设对象a 7 b 3通过各种比较运算后的结果如下表格。比较运算符解释例子等于判断运算的两个对象是否相等a b 结果为 False!不等于判断运算的两个对象是否不相等a ! b 结果为 True不等于判断运算的两个对象是否不相等a b 结果为 True| 大于判断运算符左侧对象是否大于右侧对象 | a b 结果为 True | 小于判断运算符左侧对象是否小于右侧对象 | a b 结果为 False | 大于等于判断运算符左侧对象是否大于等于右侧对象 | a b 结果为 True | 小于判断运算符左侧对象是否小于等于右侧对象 | a b 结果为 False无论参与比较运算的是什么类型的对象得出的结果都是布尔类型注意字符串做运算符 和 比较时双方必须为字符串类型否则语法错误 。a7b老鸟Pythonprint(ab)# Falseprint(ab)# 语法报错Python2 则可以比较print(aFalse)注意不要把数学中的等号 和程序中的等号 混淆大于等于号 不要写成 ≥小于等于号 不要写成 ≤。赋值运算符目前我们知道 是赋值运算符但在编程语言中不止一种赋值运算符假设对象a 7 b 3通过各种赋值运算后的结果如下表格。赋值运算符解释例子直接赋值b a 意思为 a 赋值给 b加运算后赋值b a 意思为 b b a*乘运算后赋值b * a 意思为 b b * a/除运算后赋值b / a 意思为 b b / a**幂运算后赋值b** a 意思为 b b ** a//取整后赋值b // a 意思为 b b // a%取余后赋值b % a 意思为 b b % a注意对于直接赋值运算符 和所有算术运算符结合的间接赋值运算符 python 解释器在执行该语句时会先把这条间接赋值运算语句进行拆分 先执行算术运算符然后再执行直接赋值运算符 最后得到算术运算符执行的结果。a 240 a 10 # Python 解释器把该语句拆分成下面两句 #########################我是分割线######################## temp a 10 # Python 解释器先创建一个临时变量 temp a temp # 把临时变量 temp 赋值给变量 a位运算符虽然平时很少用到位运算符但是在某些时候位运算符确实能够给我们提供很好的解决方案 位运算符是把数字看作二进制来进行计算的假设对象a 7b 3对应的二进制格式为a 0000 0111b 0000 0011 通过各种位运算后的结果如下表格。位运算符解释例子按位与运算双目运算当对应的两个二进制位都为 1 则结果为 1否则结果为 0b a 结果为 3❘按位或运算双目运算当对应的两个二进制位有一个为 1 则结果为 1否则结果为 0b ❘ a 结果为 7^按位异或运算双目运算当对应的两个二进制位不同时 则结果为 1否则结果为 0b ^ a 结果为 4~按位取反运算单目运算对数据的每个二进制取反既把 1 变为 0 把 0 变为 1~a 结果为 -8左移运算单目运算运算数据的各个二进制位全部左移 符号右边数字指定了移动的位数高位丢弃低位补 0a 3 结果为 56| 右移运算单目运算运算数据的各个二进制位全部右移 符号右边数字指定了移动的位数低位丢弃高位补 0 | a 3 结果为 0注意Python 语言中没有同或运算符当然我们可以对异或取反实现同或。逻辑运算符逻辑运算非常简单当参与布尔运算的对象是布尔类型时结果为布尔值。其它非布尔类型的对象进行 and 或 or 进行布尔运算时结果是参与运算的最终类型值但无论对什么类型的对象进行 not 运算结果一定为布尔值。 假设对象a 7b Hello通过各种逻辑运算后的结果如下表格。逻辑运算符解释例子and布尔与运算如果 a 为真则运算结果为 b否则运算结果为 aa and b 结果为 “hello”or布尔或运算如果 a 为真则运算结果为 a否则运算结果为 ba or b 结果为 7not布尔非运算如果 a 为真则运算结果为 False否则运算结果为 Truenot a 结果为 Falseand 运算规则从参与运算的第一个值开始判断如果是假值则停止运算如果是真值则继续往后运算一直运算到假值或者最后一个值运算的结果为最后一个参与运算的值 or 运算规则从参与运算的第一个值开始判断如果是真值则停止运算如果是假值则继续往后运算一直运算到真值或者最后一个值运算的结果为最后一个参与运算的值。a-1bc0.2print(aandbandc)# print(aandborc)# 0.2print(aorborc)# -1print(aorbandc)# -1高级运算符初级运算符在各种编程语言中都存在在 Python 语言中还有一些高级运算符这些高级运算符并不是所有的编程语言都支持的。成员运算符假设变量val h, strone 老鸟python我们通过下面表格来了解成员运算符。成员运算符解释例子in如果 val 的值在 strone 中存在返回 True否则返回 Falseval in strone 结果为 Truenot in如果 val 的值在 strone 中不存在返回 True否则返回 Falseval not in strone 结果为 False成员运算符运算的结果为布尔值val 作为一个元素可以是任何类型的对象只要在 strone 中能找到 val就会返回 True。valhonstrone老鸟Pythonprint(valinstrone)身份运算符身份运算符判断的是两个变量指向的对象的内存地址是否相同Python 语言用 id 函数来获取变量指向的对象内存地址我们通过如下表格了解身份运算符。身份运算符解释例子isis 是判断两个标识符是不是引用同一个对象a is b 等价于 id(a) id(b) is notis not 是判断两个标识符是不是引用不同对象a is not b 等价于id(a) ! id(b)用身份运算符判断的是变量指向的对象的内存地址要注意被不同变量指向的不同对象的值相等对象内存地址不一定相等。a5aa5b5.1bb5.1cFalseccFalsedNoneddNonestronehellostrtwohellolistone[1,2]listtwo[1,2]tupleone(1,2)tupletwo(1,2)tuplethree(1,[2,3])tuplefour(1,[2,3])print(aisaa)# Trueprint(bisbb)# Trueprint(ciscc)# Trueprint(disdd)# Trueprint(stroneisstrtwo)# Trueprint(listoneislisttwo)# Falseprint(tupleoneistupletwo)# Trueprint(tuplethreeistuplefour)# False注意如上面代码我们知道数字类型布尔类型NoneType 类型和字符串类型的值相同则 id 相同list 类型的值相同而 id 不同成员里面不含有变量的 tuple 类型对应的值相同则 id 相同如果 tuple 里面的成员或者成员的成员的…无限递归)出现有变量的话虽然值相同但 id 不同。 我们来好好分析一下1.早期的 Python 解释器对布尔类型数字类型NoneType类型的变量都是通过分配不同的内存存储的自从 Python 2.7 之后解释器做了优化所以那些类型只要值相同所在的内存是同一个 2.其实字符串类型的值是放在常量区相同的字符串所在内存地址是一样的也就是只要变量指向的字符串值相同用的是同一块内存 3.对于 list 类型所有的 Python 版本包括 Python 2 采用的都是一样的内存机制就是无论 list 值是什么在每一次创建的时候 Python 解释器都会重新分配一块内存 4.对于 tuple 类型Python 3.6包括之后的版本则会判断里面的成员或者成员的成员的…无限递归)是否有变量如果有的话则重新分配内存否则共用一块内存而 Python 2 采用的机制是只要创建一个新的 tuple 对象都会重新分配一块内存 。大家注意到我们上面所举的例子都是右值赋值的方式如果是变量赋值呢我们看下如下代码。a5aaa b5.1bbb cFalseccc dNoneddd stronehellostrtwostrone listone[1,2]listtwolistone tupleone(1,2)tupletwotupleone tuplethree(1,[2,3])tuplefourtuplethreeprint(aisaa)# Trueprint(bisbb)# Trueprint(ciscc)# Trueprint(disdd)# Trueprint(stroneisstrtwo)# Trueprint(listoneislisttwo)# Trueprint(tupleoneistupletwo)# Trueprint(tuplethreeistuplefour)# True我只说一句Python 解释器所有的变量之间赋值都是采用的浅拷贝方案浅拷贝就是把赋值运算符右边的变量里面所指向值的内存地址直接赋值给左边的变量。三目运算符在其他语言CCJava中三目运算符的表示方式是判定条件? 为真时的结果: 为假时的结果。 在 python 语言中三目运算符的表示方式是为真时的结果 if 判定条件 else 为假时的结果。score59print(okifscore60elseno)# no运算符优先级当一个表达式中有多个不同种类的运算符时要按运算符的优先级进行先后运算我们通过如下表格了解运算符优先级。运算符优先级解释()最高优先级**指数~ -按位翻转一元的正号和负号/ % // | 乘除取模取整 - | 二元的加号和减号 | 位右移和左移 | 按位与 ❘ ^ | 按位或运算和按位异或运算 | 大于小于大于等于小于等于 ! | 等于和不等于 - / // % | 各种赋值 is is not | 身份运算 in not in | 成员运算 not | 逻辑取反运算 and | 逻辑与运算 or | 逻辑或运算如果一条表达式中有多个不同种类型的运算符时用小括号 () 括起来的先进行运算总之我们没必要死记硬背这些运算符优先级。sexmanscore59print(score60orsexman)# 糟糕的写法print((score60)or(sex!man))# 不错的写法我们在写一个表达式的时候尽量不要有多个不同种类型的运算符运算避免代码可读性差要把该表达式拆分多个只含有一个运算符的表达式。sexmanscore59print(score60orsexman)# 糟糕的写法scoreok(score60)man(sexman)print(scoreokorman)# 很棒的写法类型转换要明确而可检查Python 是动态类型语言变量名可以在运行过程中指向不同类型的对象但这并不代表类型不重要。外部输入进入程序后应在边界位置尽早转换并检查。例如把年龄从字符串转换为整数失败时给出明确提示不要让错误拖到后面的计算环节。总结int、float、bool、str和None各有用途Python 整数没有固定的位数上限实际大小受可用内存限制。变量保存的是对对象的引用赋值会改变变量的绑定常量名通常用大写表示约定而非强制限制。比较运算返回布尔值条件表达式还要理解真假值、and与or的短路规则。运算符优先级不清楚时用括号表达意图。in判断的是容器中的直接成员。可尝试画出连续赋值的对象关系并预测a or b and c与嵌套列表成员判断的结果再运行验证。