Loading

Python 3 快速入门 1 —— 数据类型与变量

本文假设你已经有一门面向对象编程语言基础,如Java等,且希望快速了解并使用Python语言。本文对重点语法和数据结构以及用法进行详细说明,同时对一些难以理解的点进行了图解,以便大家快速入门。一些较偏的知识点在大家入门以后根据实际需要再查询官方文档即可,学习时切忌胡子眉毛一把抓。同时,一定要跟着示例多动手写代码。学习一门新语言时推荐大家同时去刷leetcode,一来可以快速熟悉新语言的使用,二来也为今后找工作奠定基础。推荐直接在网页上刷leetcode,因为面试的时候一般会让你直接在网页编写代码。leetcode刷题路径可以按我推荐的方式去刷。以下代码中,以 >>>... 开头的行是交互模式下的代码部分,>?开头的行是交互模式下的输入,其他行是输出。python代码中使用 #开启行注释。

Python 简介

Python作为一门脚本语言,既可以在命令行以交互的方式进行程序编写和执行,也可以在*.py文件中进行编写然后通过解释器执行。前者适合验证阶段使用,后者更适合项目编写。(验证阶段更推荐使用Jupyter,在编写时可将顺序执行的代码人为的划分为相邻的代码块,执行时可以手动依次执行代码块,当某一个代码块出现错误时,修改了出错的代码块后无需再次重头执行,只需从修改处代码块接着执行即可。)

在学习的过程中,通过help()函数可以查看方法、对象等的官方文档。例如查看print函数的官方文档:

>>> help(print)
Help on built-in function print in module builtins:
print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

基本输入输出

输出:print()函数:

>>> print("sum( a + b ):", 10 + 20)
sum( a + b ): 30

如上,print 函数将前面的字符串和后面的计算结果通过空格拼接成字符串。你也可以指定sep = "\n"参数让其通过换行符拼接。如下:

>>> print("sum( a + b ): ", 10 + 20, sep = "\n")
sum( a + b ): 
30

输入:input()函数,该函数默认将所有读入的数据视为字符串:

>>> a = input()
>>> print(a)
>>> print(type(a))
>? 123
123
<class 'str'="">

数据类型和变量

数值型( immutable )

int   # 整型
float # 浮点型
bool  # 布尔型
complex  # 复数,需要时查询文档即可,这里不做讲解

Python 作为动态语言,在定义变量时无需指定数据类型,执行时解释器会自行推断出变量类型。在PycharmPython Console选项卡(建立项目后才可以看到,在界面的最下面一行)里可以实时显示变量的类型:

image-20211120165750940

Python 中除法默认返回浮点数,使用双斜杠除法//会舍去小数点后面的部分:

>>> a = 3       # 在交互模式下点击shift+enter可以实现多行代码编写
... b = 4
... print(a/b) 
0.75            # / 除法返回浮点数

>>> print(a//b)
0               # // 除法舍去小数部分

>>> a = 3.0
... b = 4.0
... print(a/b)
0.75

>>> print(a//b)
0.0

Python语言中使用 **表示幂次计算,如 2 的 3 次方写为:2 ** 3

>>> print(2 ** 3)
8

Python语言中的 bool 类型分为TrueFalse(严格区分大小写),bool 类型是 int 类型的子类,且True在值上等于1False在值上等于0

>>> True == 1
True
>>> False == 0
True
>>> issubclass(bool, int)
True

提示:Python中的数值类型是引用类型而不是值类型

字符串型(immutable )

str   # 字符串型

Python中被''""引住的内容表示一个字符串,Python中的字符串与Java中的字符一样为不可变( immutable )类型。如下:

image-20211120172106079

Python字符串的强大之处在于支持下标访问切片功能。通过下标访问我们可以直接拿到字符串中的某个字符(实际为只有一个字符构成的字符串),当下标为负数时表示从右侧开始:

image-20211120174342817

通过切片操作,我们可以获取某个字符串的任意子串,切片由一个区间表示,如[0: len]表示获取下标0 - len-1的子串,即左闭右开。此外[:3]等同[0: 3][3:]等同[3: len]。由于每次切片操作都会返回一个新的字符串

>>> a = 'python'

>>> print(a[:3])
pyt
>>> print(a[0: 3])
pyt

>>> print(a[3:])
hon
>>> print(a[3: len(a)])
hon

>>> print(a[:-3])  # 从开头到倒数第三个字符表示的子串(同样符合左闭右开)
pyt
>>> print(a[-3:])
hon

Python还支持多行字符串,需要时查询文档即可。

列表类型(mutable)

list  # 列表

Python 中的列表有点类似于 JavaList接口的实现(ArryListLinkedList),是一种高级数据结构,不同之处在于 Python 中的 list 可以存储不同类型的数据,但通常并不会这样使用。list 还支持切片操作,且是可变( mutable)类型。list 由中括号包住若干被逗号分隔的元素来表示,如:[1, 2, 3]

由于list是可变类型,我们可以对list进行修改:

>>> a = ['p', 'y', 't', 'h', 'o', 'n']
>>> a[1] = 'i'                  # 将下标1中的元素(引用)指向字符串'i'
>>> print(a)
['p', 'i', 't', 'h', 'o', 'n']  # 第2个元素(引用)指向的字符串对象由 'y' 变为 'i'

list 的切片操作返回的新列表是原列表的一个浅拷贝。浅拷贝是对象拷贝的一种方式,由于Python中只有引用类型,下面以list类型为例对引用类型的浅拷贝进行讲解。下图是列表 a 在内存中的示意图:

python-list内存分布

变量a是一个引用(地址),它指向内存中的list对象。list对象中的每一个元素(引用)又指向内存中的int对象。当对a执行如下切片操作时:

>>> a = [1, 2, 3, 4]
>>> b = a[:2]  # 1. b通过切片获取a前两个元素的浅拷贝
>>> print(a)
... print(b)
[1, 2, 3, 4]
[1, 2]
>>> b[0] = 6   # 2. 修改b[0]
>>> print(a)
... print(b) 
[1, 2, 3, 4]   # 修改b[0]并没有影响a,为什么呢?
[6, 2]

执行 b = a[:2]时,内存中会生成一个新的list对象,且b会指向这个新list对象,内存变化如下:

image-20211122115033653

执行b[0] = 6时,内存变化如下:

image-20211122115835385

由上图容易知道这种情况下修改b并不会影响a。接着往下看:

>>> a = [1, 2, 3, [0, 0]]
>>> b = a[-2:]     # b通过切片获取a后两个元素的浅拷贝
>>> print(a)
... print(b)
[1, 2, 3, [0, 0]]
[3, [0, 0]]
>>> b[1][0] = 6    # 修改b[1][0]
>>> print(a)
... print(b)
[1, 2, 3, [6, 0]]  # 修改b[1][0]时,影响了a
[3, [6, 0]]

执行b = a[-2:]时,内存变化如下:

image-20211122134618255

执行b[1][0] = 6时,内存变化如下:

image-20211122154441339

由上图容易知道,因为a[3]b[1]指向内存中同一个list,当通过b[1][0]修改b时会同时影响a

同时,我们还可以通过切片操作来修改列表:

>>> a = [1, 2, 3]
>>> a[1: 3] = [6, 6]  # 修改a中后两个元素;如果这里为a[1: 3] = [6, 6, 6, 6]会出错吗?动手试试
>>> print(a)
[1, 6, 6]

>>> a[:] = []         # 清空a
>>> print(a)
[]

此外,列表还支持合并与嵌套:

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b           # 合并
>>> print(c)
[1, 2, 3, 4, 5, 6]

>>> d = [a, b]          # 嵌套
>>> print(d)
[[1, 2, 3], [4, 5, 6]] 

最后,列表还提供了一系列成员方法:

  • list.append(x)
    在列表末尾添加一个元素,相当于 a[len(a):] = [x]

    >>> a = ['wjz']
    >>> a.append('lsl')
    >>> print(a)
    ['wjz', 'lsl']
    
  • list.extend(iterable)
    用可迭代对象的元素扩展列表。相当于 a[len(a):] = iterable

    >>> a = [1, 2, 3]
    ... b = [4, 5, 6]
    ... a.extend(b)
    ... print(a)
    [1, 2, 3, 4, 5, 6]
    
  • list.insert(i, x)
    在指定位置插入元素。第一个参数是插入元素的索引,因此,a.insert(0, x) 在列表开头插入元素, a.insert(len(a), x) 等同于 a.append(x)

  • list.remove(x)
    从列表中删除第一个值为 x 的元素。未找到指定元素时,触发 ValueError 异常。

  • list.pop([i])
    删除列表中指定位置的元素,并返回被删除的元素。未指定位置时,a.pop() 删除并返回列表的最后一个元素。(方法签名中 i 两边的方括号表示该参数是可选的,不是要求输入方括号。这种表示法常见于 Python 参考库)。

    >>> a = [1, 2, 3]
    >>> a.pop()   # 默认为 pop(-1),即倒数第一个
    3
    >>> print(a)
    [1, 2]
    >>> a.pop(0)  # 删除第一个
    1
    >>> print(a)
    [2]
    
  • list.clear()
    删除列表里的所有元素,相当于 del a[:]del语句可以删除一个变量,或按切片删除列表元素。

    # 删除变量
    >>> a = [1, 2, 3]
    ... b = a
    ... del a
    ... print(a)  # 删除变量a后再访问a,报错:未定义
    Traceback (most recent call last):
      File "<input>", line 4, in <module>
    NameError: name 'a' is not defined
    >>> print(b)  # b引用指向的列表对象还存在说明del只是删除了a这个引用
    [1, 2, 3]
    
    # del通过切片删除列表元素
    >>> a = [1, 2, 3]
    ... del a[:2]
    ... print(a)
    [3]
    
  • list.index(x[, start[, end]])
    返回列表中第一个值为 x 的元素的零基索引。未找到指定元素时,触发 ValueError 异常。可选参数 startend 是切片符号,用于将搜索限制为列表的特定子序列。返回的索引是相对于整个序列的开始计算的,而不是 start 参数。

    >>> a = [1, 2, 3, 4, 5]
    ... print(a.index(3))
    2  # a中3的下标为2
    
    >>> a = [1, 2, 3, 4, 5]
    ... print(a.index(3, 2, len(a)))  # 从第3个元素开始查找3
    2
    
  • list.count(x)
    返回列表中元素 x 出现的次数。

  • list.sort(*, key=None, reverse=False)
    就地排序列表中的元素(要了解自定义排序参数,详见 sorted())。该方法先忽略,入门2中有讲解。

  • list.reverse()
    翻转列表中的元素。

  • list.copy()
    返回列表的浅拷贝。相当于 a[:]

元组类型(immutable )

tuple  # 元组

元组与列表很相似,但元组为不可变类型,元组通常用来包含异质元素(类型不同)而列表通常用来包含同质元素。tuple 由小括号包住若干被逗号分隔的元素来表示,如:(1, 2, 3)。元组同样支持切片、下标(索引)访问。

定义一个元组:

>>> a = (1, 2, 3)
>>> b = 1, 2, 3  # 定义时省略括号也行,但不建议
>>> print(a, b)
(1, 2, 3) (1, 2, 3)

# 定义一个空元组
>>> a = ()
... print(a)
()

# 定义只有一个元素的元组
>>> a = (1,)
... print(type(a))
... print(a)
<class 'tuple'="">
(1,)

# 没有逗号 a 就是值为 1 的int型变量
>>> a = (1)
... print(type(a))
... print(a)
<class 'int'="">
1

元组的不可变是指元组中的每一个元素(引用)的指向不能改变,以a = (1, 2, 3, 4)为例:

image-20211126164823623

上图中被椭圆圈起来的四个指向都不能修改,但如果元组中元素(引用)指向的是一个可变类型,指向虽然不能修改,但可变类型本身是可以修改的,以a = ([1, 2], [3, 4])为例:

image-20211126170343296

上图中被红色椭圆圈起来的指向不能修改,被蓝色椭圆圈起来的指向可以修改:

>>> a = (1, 2, 3, 4)
>>> a[0] = 6  # 不能修改a[0]的指向
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

>>> a = ([1, 2], [3, 4])
>>> a[0] = [6, 6]  # 不能修改a[0]的指向
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[0][0] = 6    # a[0] 指向的list可以修改
>>> print(a)
([6, 2], [3, 4])

集合类型(mutable)

set  # 集合类型

集合是用来存放不含重复元素的无序容器。

定义集合:

# 通过花括号定义集合
>>> a = {1, 2, 3, 2}
... print(a)
{1, 2, 3}  # 去重

# 通过set()函数定义集合。只能传入一个参数,且为可迭代类型。
# 会取出可迭代类型中的每一个元素为一个集合元素
>>> set("123 4")  # 传入字符串
{'3', ' ', '2', '4', '1'}
>>> set(["1", "2", "3"])  # 传入list
{'3', '1', '2'}

# 定义空集合只能使用set()函数
>>> a = set()
... print(type(a))
... print(a)
<class 'set'="">
set()

# {}表示一个空字典
>>> a = {}
... print(type(a))
... print(a)
<class 'dict'="">
{}

字典类型(mutable)

dict  # 字典

字典类型是可变类型,类似与Java中的Map。字典类型用来存储键值对,关键字通常是字符串或数字,也可以是其他任意不可变类型。若元组直接或间接地包含了可变对象,就不能用作关键字。

创建字典:

# 创建空字典
>>> a = {}
>>> print(a)
{}
>>> a = dict()
>>> print(a)
{}

# 常用创建方式
# 直接在花括号中申明键值对
>>> a = {"chengdu": "A", "mianyang": "B", "guangyuan": "C"}
>>> print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

# 关键字传参的方式调用dict函数
>>> a = dict(chengdu="A", mianyang="B", guangyuan="C")
>>> print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

# 构造函数中传入键值对序列
>>> a = dict((("chengdu", "A"), ("mianyang", "B"), ("guangyuan", "C")))
>>> print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

>>> a = dict([("chengdu", "A"), ("mianyang", "B"), ("guangyuan", "C")])
>>> print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

>>> a = dict([["chengdu", "A"], ["mianyang", "B"], ["guangyuan", "C"]])
>>> print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

对字典进行增删改:

>>> a = dict([["chengdu", "A"], ["mianyang", "B"], ["guangyuan", "C"]])
>>> a["zigong"] = "C"  # 为不存在的key赋值即可添加新的键值对
... print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C', 'zigong': 'C'}

>>> del a["zigong"]    # 删除key为 “zigong” 的键值对
... print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'C'}

>>> a["guangyuan"] = "F"  # 为已经存在的key赋值即可对已存在的键值对进行修改
... print(a)
{'chengdu': 'A', 'mianyang': 'B', 'guangyuan': 'F'}

常用高级数据结构

栈的特性是先进后出,使用list非常容易实现;使用append(e)将元素添加到栈顶,使用pop()将栈顶元素弹出:

>>> stack = [1, 2, 3]
>>> stack.append(4)  # 4入栈
... print(stack)
[1, 2, 3, 4]

>>> stack.pop()  # 4出栈
... stack.pop()  # 3出栈
... print(stack)
[1, 2]

队列

队列的特性是先进先出,使用list也能实现队列,即使用append(e)将元素入队尾,使用pop(0)使队头元素出队。但pop(0)操作很费时(其他元素都必须向前移动一位),故不推荐使用list实现队列。

实现队列最好用 collections.deque,可以快速从两端添加或删除元素(双端队列):

  • append():从右边入队
  • appendleft():从左边入队
  • popleft():从左边出队
  • pop():从右边出队
>>> from collections import deque
... myDeque = deque([1, 2, 3])
... print(myDeque)
... myDeque.append(4)  # 4入队尾
... print(myDeque)
... myDeque.popleft()  # 1出队头
... print(myDeque)
deque([1, 2, 3])
deque([1, 2, 3, 4])
deque([2, 3, 4])

posted @ 2021-12-01 21:45  WINLSR  阅读(347)  评论(0编辑  收藏  举报