⭐️有一定基础的可以跳过前边部分,直接从目录中有星号标记⭐️的地方开始
最近又奋起了,暂时不是咸鱼了,混了一个多月的问答,发现了很多小伙伴甚至连基本的语法都没搞清楚就开始码代码,对计算机来说,这些码出来的东西无疑就是天书了,他是不会懂的。所以老顾就在想,写一写基础的东西,至少要搞明白我们用的东西到底是个什么,有什么样的约定,什么样的语法,可以通过什么方式实现我们的想法。万丈高楼平地起,一砖一瓦皆根基,只有基础打得牢靠,高层建筑才不会是空中楼阁。所以,老顾就在这里准备开一个系列讲解 python 基础,穿插一些编程思路,以及其他语言的比较和范例。
在任何地方进行沟通,都需要一种语言,与计算机沟通同样如此,也需要学习可以进行有效沟通的语言,比如 python ,比如 c,又或者 java。语言没有高低之分,只有应用场景的区别,就好比你要研究佛学,那么梵语是必学的,你要研究藏传佛教,那么藏语是必学的,你要研究数学,嗯,咱也不知道要学啥。
那么话说回来,任何一门语言,必定有其内在逻辑,表达方式,语法结构之类的,如果无视这些,那么这个语言你肯定是学不会的,更不要说学好了。
本次老顾难得雄起,就以 python 语言为主,讲解一下编程语言的一些讲究。毕竟python 上手难度低,语法糖(可以理解为中文中的成语、典故之类的,就是用较少的文字表达较多的意思,这里就是用较少的代码描述更多的运算)较多,而且轻量级,安装调试都很方便。
约定所有阅读本文的读者都已经安装了 python 语言,本文以 python 3 为基础,python 2老顾并未接触过,在转入到这个语言时,都已经 python 3.7 了。
约定所有读者已有调试开发环境,不管是 spyder 也好,vscode 也好,其他什么也好,总之不是在交互行中进行代码编写。
约定在很多示例中,并未使用输出指令,而是使用开发环境自带的反馈机制得到结果,阅读本文的读者应理解ide环境结果返回机制,工作环境中,请带上输出指令。
约定老顾可以答疑,文后发表评论即可,还望关注并收藏。
在任何一门语言里都有着对应的语法,编程语言也一样,且由于编程语言兴起才不足百年,大部分的基础语法都很接近,所以学号一个语法,其他编程语言的语法也就掌握的七七八八了。而语法又是服务于实体的,对编程语言来说,就是服务于各种数据的,那么数据类型就很重要了。
在 python 代码中,有一些内容是不被运行的,那就是注释,注释的定义就是 # 号了,在非字符类型定义中出现的 # 都会被当做注释
# 注释内容是不被执行的,这里可以写任何东西
嗯,这个和自然语言很接近,就是数字,各种数字,在 python 中很友好,科学计数法也是直接支持的
在计算机语言中,数字类型分为两大类,一种是整数型,一种是小数型,分别就是上图两种类型 int 和 float,我们称之为整型和浮点型
在我们的自然语言里,也会有各种约定,比如诗词,我们一念就知道这是一首诗,因为其有特定格式,那么计算机怎么知道你输入的是字符,而不代表其他意义呢?这里约定了,使用 引号 将其标注出来,这就是字符型 str,在 python 中,字符型可以由成对单引号标注,也可以用成对双引号标注,甚至可以哟弄成对三引号(全单引号,或全双引号)来定义更长的文本字符内容。
也有很多人,喜欢用三引号定义,当做注释来使用,只要没有把这些数据记录在程序运行中,那么是没有问题的。
在有很多情况下,我们说的话,可能不是字面意思,比如行业黑话,江湖黑话,甚至故意说反话,在计算机语言的世界里,也存在这种情况。比如上边截图中的反馈结果中,出现了很多 \n ,他并不是字符 \ 和 字符 n 的字面意思了,这是一个转义内容,也就是黑话,表示这是一个换行符,即 \n 等于换行,类似的还有很多,\r 表示回车,\t 表示 tab 缩进等等,后边遇到更多的时候再讲解,这里了解一下有这个概念即可。
很多人喜欢叫他布尔型,boolean嘛,问题是对新手不太友好,还要补充解释一句,就是逻辑值,只有两个值,要门真要么假。大部分语言中,true 和 false 都是纯小写,python这里需要注意,首字母大写。嗯最近混插着写代码,连 true 和 True 我都分不清了。
True
Out[54]: Truetype(True)
Out[55]: booltype(False)
Out[56]: bool
在我们日常生活中,也会有很多列表类型的东西,比如看小说有书单,去饭店有菜单,去超时有购物单,这些都是列表形式的内容,在计算机领域使用中括号来描述列表。
[1,2,3,4,5]
Out[12]: [1, 2, 3, 4, 5]type([1,2,3,4,5])
Out[13]: list
在 python 中一个很大的亮点就是,不要求列表中所有元素的类型是一致的,你可以让人和狗一起在队伍里,也可以让恐龙和美女在一个组合中,更可以让机器人和板凳都在你前边排队。
使用列表中的数据也很简单,直接给出索引即可,比如国外点菜的时候,不认识文字,也可以指着图片说,我要第一个,我要第三个,那就是索引了,不过需要注意的是,在计算机的索引中,0是第一个,1是第二个,以此类推。而下标则是用另一个中括号来描述,比如下边的例子,前边的中括号是列表,后边的中括号是下标索引。索引数字3表示第四项,不要弄错了哦。
['小明','韩梅梅','王麻子','王致和','王老吉','隔壁老王','王婆','王守义'][3]
Out[14]: '王致和'
在很多时候,我们说出一个词,大家立刻能联想到相关的内容,有着其对应关系,这种关系,在计算机中实现的方式就是词典,词典使用花括号描述的,里面的内容应该是(关键词:数据)的格式,这点很重要哦。关键字不会重复,如果重复,按照同一个关键字处理。
{'小明':'童年阴影','韩梅梅':'童年阴影的另一个元凶','王麻子':'卖菜刀的','王致和':'卖臭豆腐的','王老吉':'卖红茶的','隔壁老王':'人妻爱好者','王婆':'卖瓜的','王守义':'卖香料的'}
Out[15]:
{'小明': '童年阴影','韩梅梅': '童年阴影的另一个元凶','王麻子': '卖菜刀的','王致和': '卖臭豆腐的','王老吉': '卖红茶的','隔壁老王': '人妻爱好者','王婆': '卖瓜的','王守义': '卖香料的'}type({'小明':'童年阴影','韩梅梅':'童年阴影的另一个元凶','王麻子':'卖菜刀的','王致和':'卖臭豆腐的','王老吉':'卖红茶的','隔壁老王':'人妻爱好者','王婆':'卖瓜的','王守义':'卖香料的'})
Out[16]: dict
词典的使用,和列表差不多,不过这里由于没有索引,所以大部分时候,是通过关键词来检索的,同样,索引也放到中括号里。
{'小明':'童年阴影','韩梅梅':'童年阴影的另一个元凶','王麻子':'卖菜刀的','王致和':'卖臭豆腐的','王老吉':'卖红茶的','隔壁老王':'人妻爱好者','王婆':'卖瓜的','王守义':'卖香料的'}['王婆']
Out[17]: '卖瓜的'
注意:在词典中,关键词必须是合法的数据格式,比如字符型,比如数值型,或者元组,但不可以是列表,他会报类型错误。
{[1,2,3,4]:10}
Traceback (most recent call last):File "C:\Users\sosome\AppData\Local\Temp\ipykernel_67284\2763533465.py", line 1, in {[1,2,3,4]:10}TypeError: unhashable type: 'list'
|
字典中,除了关键字之外,数据的类型也是不限制的,可以字典套字典列表套列表。更多的词典操作,后续补充,这里先理解其概念。
与列表类似,使用圆括号进行定义,这个数据类型目前老顾只在 python 中见到过。
(1,2,3,'ab')
Out[21]: (1, 2, 3, 'ab')type((1,2,3,'ab'))
Out[22]: tuple(1,2,3,'ab')[3]
Out[23]: 'ab'type((1,2))
Out[77]: tupletype((1))
Out[78]: int
元组中的数据类型同样不限,使用方式和列表也基本一致,唯一的区别是,列表中的元素在后续使用中可以发生改变,而元组中的数据则不可修改。需要注意的是,当你元组只有一个元素的时候,其实是无法定义成元组类型的,元组中最少两个元素,如果只有一个元素,则返回该元素本身,这涉及到语法问题了,因为圆括号可以参与正确的运算中,我们在数学中的表达一样,只要这个括号内的数据最终是一个,那么他就是分组、分段的运算符,而不是元组定义。
嗯。。。也是 python 特有的,别的编程语言基本就是列表操作,而 python 则提供了一种不带数据的字典,也就是集合了,定义方式也是花括号,不过没有冒号及之后的数据了。和字典一样,集合中的元素不会重复,如果重复,则自动丢弃一个。
{1,2,3,'aa',(1,2)}
Out[24]: {(1, 2), 1, 2, 3, 'aa'}type({1,2,3,'aa',(1,2)})
Out[26]: set{1,1,2}
Out[17]: {1, 2}
在集合中,他的数据排序是无序的,至少老顾没测出规律来,而且见鬼的是,很可能每台电脑上,同样的集合,排序也是不一样的。
集合的使用方式则只能通过迭代的方式来取,他并没有提供通过索引方式获取数据的方法。
以上就是python中,5种最重要,最常用,最基础的数据类型了,有了这些类型,我们就可以使用计算机进行一些运算了。
在不同的语言里,总会有一个特殊类型,用来表示没有,不存在,空集等等,大部分语言中,使用的是 null ,而python很个性的不随大流,自己定了个None出来。你想输出None的值,是不可能的,下边的代码不是我少贴了,None就是没东西哦。
Nonetype(None)
Out[39]: NoneType
顾名思义,数值类型的数据进行的运算,在编程语言里,基本上都支持一些简单的运算,部分复杂的计算可能需要引入额外的支持。
简单运算包括加、减。乘、除、余、整除。
3 + 5 # 加法
Out[28]: 83 * 5 # 乘法
Out[29]: 158 - 3 # 减法
Out[30]: 58 / 3 # 除法
Out[31]: 2.66666666666666658 // 3 # 整除除法
Out[32]: 219 % 7 # 求余数
Out[33]: 5
曾经有小伙伴在问答里提问 % 是啥,也是哭笑不得
在计算表达式中,我们还可以加入圆括号,来实现更复杂的四则运算
(1 + 2) * 8 / (4 + 2)
Out[37]: 4.0
然后,刚才我们看到了两个除号,他就改成整除了,那么两个乘号能行吗?python 告诉你行,js 也告诉你行,c# 告诉你不行。告诉你行的语言,两个乘号表示次方,比如 2 ** 3,就是2的三次方。
3**5
Out[40]: 2432**5
Out[41]: 32
在计算机中,总所周知,所有数据都是二进制的,全是由0和1组成的,那么就产生了一个很特殊的运算方式,可以大量的节省算力,那就是位运算。比如数字2,二进制形式就是 10,左移一位编程 100,那么就变成10进制的4了,右移1位变成1,就变成了十进制1了,左移相当于乘2操作,右移相当于整除2操作。虽然大部分工作中用不到,但是对于位运算,我们还是要了解了解的。
# 左移运算符是 << 后边的数字表示移动几位
3 << 2
Out[42]: 12
# 右移运算符是 >>
8 >> 1
Out[43]: 4
# 异或运算符是 ^ 5 是 101,3 是 011,结果就是110,即相同位置的数字不同,保留1,相同保留0
5 ^ 3
Out[44]: 6
# 与运算 11 是 1011,7 是 0111,得到结果是 0011,只有两个相同位置的都是1才保留1
11 & 7
Out[47]: 3
# 或运算 8 是 1000,7 是 0111,任意有一个位置是1,就保留1,得到 1111
8 | 7
Out[48]: 15
顾名思义,就是比较运算,大了还是小了
5 > 3
Out[57]: True5 < 3
Out[58]: False
# 相等比较,需要用两个等号,一个等号是赋值哦
5 == 3
Out[59]: False5 >= 3
Out[60]: True8 != 7
Out[63]: True
在这里要称赞一下 python ,可以连续比较,得到所有比较结果的与运算后的结果,也就是并且后的结果。
8 > 5 > 2
Out[61]: True8 > 5 > 7
Out[62]: False
在 python 中又一个不一样的地方是非运算和与运算,别的地方都是什么 &&啦,|| 啦,! 啦,在python这里全都不好使,给我老老实实写单词去。
True and True
Out[65]: TrueTrue and False
Out[66]: FalseTrue or False
Out[67]: Truenot True
Out[68]: False
嗯,字符串拼接,字符串替换,一些基本的操作罢了。
'a' + 'b'
Out[81]: 'ab''a' + ('ab')
Out[82]: 'aab''abcdefg'.replace('abc','xyz')
Out[83]: 'xyzdefg''abcdefghijklmn'[3:7]
Out[84]: 'defg'
貌似混进去个奇怪的东西[3:7]是个什么东西?小伙伴不要急,稍后解答python中一些基本的骚操作。
以上运算都是直接有反馈结果的运算了,然后,还有很多运算,是原数据的基础上进行的,我们需要进行一些变量的定义,才能看出结果了。变量指的就是用来记录我们指定的数据,并在运算中可以发生变动的记录符号。变量需要有变量名称,而命名规则则是老生常谈了。在 python 中,变量名可以由字母数字下划线组成,且不能以数字开头。
a = 1
b = (1,2,3,4)
c = {1,2,3,4}
d = [1,2,3,4]
在 spyder 的开发环境中,可以在右侧方便的看到我们已定义的变量内容,在有了变量的情况下,我们就可以继续观察更多的运算情况了。
现在以刚才定义的4个变量为依据,来进行观察。并且,所有结果我们以输出指令 print 来进行显示,不再依靠编译环境的反馈机制了。
变量 c 是一个集合,我们可以通过 len 得到集合的元素数量,可以通过 add 来增加元素,可以通过remove来移除元素
c = {1,2,3,4}
print(c)
c.add(5)
print(c)
c.remove(2)
print(c)
{1, 2, 3, 4}
{1, 2, 3, 4, 5}
{1, 3, 4, 5}
然后就是集合与集合的运算。。。。python 虽然也有一些基于函数方法的操作,但大部分都无需这些方法,可以直接用运算符就可以了。。。
# 求差集,如果减号前的元素在减号后的集合中没有,则保留
# c = {1,2,3,4}.difference({1,3,5,7})
c = {1,2,3,4} - {1,3,5,7}
print(c)
{2, 4}
# 求交集,即 & 符号前后都有的元素
# c = {1,2,3,4}.intersection({1,3,5,7})
c = {1,2,3,4} & {1,3,5,7}
print(c)
{1, 3}
# 求并集,即把两个集合合并成一个更大的集合,注意,这里用的不是加法哦
# c = {1,2,3,4}.union({1,3,5,7})
c = {1,2,3,4} | {1,3,5,7}
print(c)
{1, 2, 3, 4, 5, 7}
# 求补集,即组成最大集合后分别减去前后两个集合的并集
# c = {1,2,3,4}.symmetric_difference({1,3,5,7})
c = {1,2,3,4} ^ {1,3,5,7}
print(c)
{2, 4, 5, 7}
# 使用 remove 删除一个指定的元素,无返回信息
c = {5,1,2,3,4}
print(c.remove(5))
print(c)
None
{1, 2, 3, 4}
# 使用 pop 删除一个元素,并将删除的元素返回
c = {1,2,3,4}
print(c.pop())
print(c)
1
{2, 3, 4}
与集合不同的是,列表不会对重复的数据进行任何操作,该多少数据就是多少数据,所以列表也有其必要性。
# 列表合并
d = [1,2,3,4] + [2,3,4,5]
print(d)
[1, 2, 3, 4, 2, 3, 4, 5]
# 使用 pop() 删除最后一个,或指定索引的元素
print(d.pop())
5
print(d)
[1, 2, 3, 4, 2, 3, 4]
print(d.pop(0))
1
print(d)
[2, 3, 4, 2, 3, 4]
在 python 里,有一个很常用的方法,就是 range,用来指定一个迭代范围,或者说枚举范围,再通俗点就是范围内每个数用一次。但是,他并不是一个列表对象,而是一个独有的范围对象。范围就是范围,即不是列表,也不是集合。就像日常说的,1到5,13号到18号,嗯。。。很形象吧。
range(10)
Out[35]: range(0, 10)type(range(10))
Out[36]: range
Definition : range(stop)
定义:range(stop)
Type : Function of builtins module
类型:内置功能模块
range(stop) -> range object range(start, stop[, step]) -> range object
语法:
range(stop) -> 范围对象仅仅使用停止限制,默认从0开始
range(start, stop[, step]) -> 范围对象
定义开始数字和结束数字,步长为可选
Return an object that produces a sequence of integers from start (inclusive) to stop (exclusive) by step. range(i, j) produces i, i+1, i+2, …, j-1. start defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3. These are exactly the valid indices for a list of 4 elements. When step is given, it specifies the increment (or decrement).
在其他语言环境里,我们要表明一个从1到10的10个数字,那么我们需要用循环的办法,一个一个写出来,并给到数组中。在 python 中,由于有了 range 这个范围表达式。。。。那么,是不是可以用范围表达式来完成这一过程呢?答案是可以的,通过推导表达式,结合范围表达式。
# 使用推导表达式生成 1 到 10 的数字列表
[n + 1 for n in range(10)]
Out[38]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 返回的结果的确是 list 类型
type([n + 1 for n in range(10)])
Out[39]: list
# 使用推导表达式生成 1 到10 的数字集合
{n + 1 for n in range(10)}
Out[40]: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
# 返回的结果的确是 set 类型
type({n + 1 for n in range(10)})
Out[41]: set
# 使用推导表达式生成 1 到 10 的元祖。额。。。返回一个推导表达式
(n + 1 for n in range(10))
Out[42]: at 0x000001EF68508120>
# 类型也是推导表达式
type((n + 1 for n in range(10)))
Out[43]: generator
行吧。。。元祖很特殊,之前老顾其实并没有注意到这一点,而是有小伙伴在问答中问了,为什么使用推导表达式的元祖,第一次正常使用,第二次就没有内容了。据老顾观察,应该是推导表达式类型,是开辟临时空间,执行一次之后,空间就释放了,并不会运行多次。所以在使用 tuple 转换了类型后,该推导式就应给废弃了。
x = (n + 1 for n in range(10))
print([i for i in x])
print([i for i in x])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[]
跳过元祖,我们再看,使用推导表达式可以完成什么,比如一个全是单数的列表?
# 使用步长控制
[n for n in range(1,20,2)]
Out[4]: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
# 使用推导式控制
[n for n in range(20) if n % 2 == 1]
Out[5]: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
# 使用三元式控制,明显这个不合格
[n if n % 2 == 1 else 0 for n in range(20)]
Out[6]: [0, 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 0, 15, 0, 17, 0, 19]
# 使用数学方法控制
[n * 2 + 1 for n in range(20)]
Out[7]: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39]
简单来说,就是在一个可以有多个数据的类型中,使用 for 来迭代一个可迭代的对象(比如范围,比如列表、词典、元组甚至字符串),最后返回一个经过处理的多数据集合、列表之类的结构化数据组合。在推导表达式的迭代对象后可以跟一个限制,不符合限制的,则不在返回的数据中。在for 之前也可以加一个限制,但是必须有 else ,来生成不符合预期的内容生成的结果。而结果本身是可以进行各种计算的。
# 使用的字母,每个都后移两位
[chr(ord(c) + 2) for c in 'abcdefghijklmn']
Out[8]: ['c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p']
在大多数时候,乘法,就表示数学的乘法,而在 python 中,乘法就不仅仅是数学运算了。
# 字符串重复 3 遍,并返回
'abc' * 3
Out[10]: 'abcabcabc'
# 列表长度乘 10,并按原内容顺序填充
[0] * 10
Out[11]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
# 返回一个重复 n 次的元祖
(1,2) * 4
Out[12]: (1, 2, 1, 2, 1, 2, 1, 2)
在使用 乘法 时,需要注意,他返回的是一个引用地址,如果对一个引用型的数据使用乘法时,他引用的将是同一个地址。
# 可以看到,只修改一个数据,结果另一行的数据也跟着改变了
a = [[0] * 5] * 2
print(a)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
a[0][0] = 1
print(a)
[[1, 0, 0, 0, 0], [1, 0, 0, 0, 0]]
# 而另一种单独使用推导式的,则不存在这个问题
a = [[0] * 5 for _ in range(2)]
print(a)
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
a[0][0] = 1
print(a)
[[1, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
在一个支持索引的对象中,比如列表,咱们日常都说第一个,第二个,这样的,偶尔会说倒数第一个,倒数第二个,大部分的编程语言都是支持正着数的,如果要找倒数第一个,需要先计算出长度,然后从长度上实现最后一个,倒数第二个这样的写法。而python逆天的支持了负数索引!
# H e l l o w o r l d !
# 0 1 2 3 4 5 6 7 8 9 10 11 正数索引
#-12-11-10-9 -8 -7 -6 -5 -4 -3 -2 -1 负数索引
a = 'Hello world!'
print(a[3])
l
print(a[-2])
d
当然,如果你使用的数字超出了索引范围,他还是会提示超出索引的。
print(a[12])
IndexError: string index out of range
print(a[-13])
IndexError: string index out of range
在其他语言中,我们如果想获取一个序列中一些数据片段,我们只好写循环,一个一个的拿出来再拼接,在 python 中,则可以用一个非常骚的操作来实现!
a = 'Hello world!'
print(a[0:5])
Hello
print(a[-6:-1])
world
print(a[0::2])
Hlowrd
这个给出两个下标,中间用冒号分隔的提取数据的操作就称之为切片了。需要注意的是,在切片时,前边的值应该小于后边的值。他的语法是:
[start:end[:step]]
start 为起始位置索引
end 为结束位置索引,取到的数据长度是 end - start,所以,起始位置是包含在数据中,而结束位置不包含在数据中
step 则为步长,即每多少个数据取一个
在切片的基础上,由于负数索引的支持,所以步长如果是一个负数,那就有一个更骚的结果了。他直接逆转了数据的顺序!
print(a[::-1])
!dlrow olleH
本文,及以后本系列文章,只为初学者打一个基础,不要犯一些基础性的错误。如果大家有什么想问的,还请在文后发表评论,不要私信老顾哦。
本章内容主要是为了那些基础不牢靠的小伙伴们补课所用,如有错漏,还望指正。
最后,祝愿所有小伙伴一步一个台阶,平步青云,步步高升。
print('\n'.join([' ' * (50 - n) + ''.join(['平步青云步步高升'[v % 8] for v in range(n)]) for n in range(49)]))
下一篇: 宾馆消防安全管理制度