01.Python基础

发布于 2025-07-03  140 次阅读


一、注释

1.单行注释

  • 单行注释使用#进行注释,只对#所在行生效
  • 单行注释可以使用在一行代码的末尾
  • 单行注释的快捷键是Ctrl+/
    #这是一条单行注释
    
    print('一个输出函数')#代码尾部可以添加单行注释

2.多行注释:'''或"""

  • 多行注释使用'''或者"""进行注释,在一对'''或"""之间生效
  • 多行注释不能使用在代码的末尾
  • 多行注释没有快捷键
    '''
    多行注释1
    多行注释2
    多行注释3
    '''
    
    """
    多行注释1
    多行注释2
    多行注释3
    """

二、变量

1.变量声明

声明方式:变量名=变量值

age=12
#Python中的变量声明无需显式地声明变量类型,但变量类型依然存在
#Python中不能仅进行变量声明而不进行赋值,因为无法确定变量类型

2.变量类型

#整型:int
#浮点型:float
#布尔型:bool
#字符串类型:str
#列表:list
#元组:tuple
#字典:dict
#集合:set

#在Python中可以使用type()获取变量的类型

3.标识符和关键字

在Python中会使用一些具有特殊功能或含义的字符组合,起到类似名字的作用

其中由程序员可以自主决定的称为标识符,由官方已经决定的称为关键字

#标识符的命名规则:
#1.只能由字母、数字、下划线组成
#2.不能以数字开头
#3.不能使用关键字
#4.严格区分大小写

三、输出函数print

1.普通输出

#普通数据输出
print(123)#输出数值
print('提示')#输出字符串
print(1+3)#输出计算式
print('hello','world')#一次输出多个数据

2.格式化输出

#格式化输出
#'要输出的字符信息%s'%变量名
age=13
print('小明今年%d岁了'%age)
#注意:格式化与print函数没有关系,格式化是字符串的功能!
str1='小明今年%d岁了'%age
print(str1)

#多占位符的格式化方式
name='小明'
age=13
gender='男'
#格式化字符串后的%只能识别一个变量,因此多个变量需要使用括号
print('%s,性别%s,年龄%d'%(name,gender,age))

#精度问题
#%f可以设置保留小数点后几位,例如%.2f保留两位,多余则四舍五入
#%d可以设置输出的位数并补零,例如%03d输出三位,不足则补几个零

3.print函数的其他参数

#print函数中有一些默认的参数
#def print(self, *args, sep=' ', end='n', file=None): # known special case of print
#sep:多个数据之间的分隔符,默认为' '
#end:打印结束后的结束符,默认为'n'

#1.修改间隔符
print('Jack','Mike','Lisa')#同时打印,默认分隔符为' '
print('Jack','Mike','Lisa',sep=',')#指定分隔符为','

#2.修改结束符
print('床前明月光',end=',')
print('疑是地上霜',end='.')
print('举头望明月',end=',')
print('低头思故乡',end='.')

四、输入函数input

  • 输入函数
    password=input('请输入您的密码:')
    print('password:%s'%password)
    print(type(password))
    #注意:input接收的所有数据类型都是字符串类型

五、f-string字符串

  • f-string字符串

    f-sting字符串是Python3.6版本以上才能使用的一种字符串方式

    name='小明'
    age=12
    height=1.68
    str_NO=3
    #格式化输出
    #1.百分号输出
    print('学生姓名为%s,年龄为%d,身高为%.2f,学号为%03d'%(name,age,height,str_NO))
    #2.f-string字符串输出
    #格式:f'要输入的字符串{变量}'
    print(f'学生姓名为{name},年龄为{age},身高为{height},学号为{str_NO}')
    #使用F也可以
    print(F'学生姓名为{name},年龄为{age},身高为{height},学号为{str_NO}')
    
    #精度问题的解决方法
    #1.保留n位小数{变量:.2f}
    #2.补零{变量:03d}
    print(F'学生姓名为{name},年龄为{age},身高为{height:.2f},学号为{str_NO:03d}')

六、数据类型转换

1.类型转换

int1=10
float1=3.7
str1='10'
str2='3.7'
str3='abc'

#转换为int
#1.float转换为int
#转换过程中会直接丢弃小数部分
print(int(float1))
print(type(int(float1)))

#2.str转换为int
print(int(str1))
print(type(int(str1)))
#str2与str3转换失败,因为str2与str3内部并非整型数据
'''
print(int(str2))
print(type(int(str2)))
print(int(str3))
print(type(int(str3)))
'''

#转换为float
#1.int转换为float
print(float(int1))
print(type(float(int1)))
#2.str转换为float
print(float(str1))
print(type(float(str1)))
print(float(str2))
print(type(float(str2)))
#str3转换失败,因为str3内部并非浮点型数据
'''
print(float(str3))
print(type(float(str3)))
'''

#转换为str
#1.int转换为str
print(str(int1))
print(type(str(int1)))
#2.float转换为str
print(str(float1))
print(type(str(float1)))

2.eval函数

#eval()会去除str两侧的引号,内部是什么就允许什么
#1.去除后为int
print(eval(str1))
print(type(eval(str1)))
#2.去除后为float
print(eval(str2))
print(type(eval(str2)))
#3.不能处理内部是str的字符串,因为会识别为一个没有赋值的变量
'''
print(eval(str3))
print(type(eval(str3)))
'''
#4.去除后为代码
eval("print('hello world')")

七、运算符

1.算术运算符

#算术运算符
#1.加:+
print(1+2)
#2.减:-
print(1-2)
#3.乘:*
print(1*2)
#4.除:/
print(1/2)
#5.整除://
print(1//2)
#6.取余:%
print(1%2)
#7.幂次:**
print(1**2)

#注意:除法运算的结果是浮点型数据,其他运算若操作数存在浮点型则结果为浮点型

2.赋值运算符

#赋值运算符
#1.单个赋值运算
name='Jack'#右侧可以为数据
name2=name#右侧也可以为变量
#2.多个赋值运算
a=b=c=1#赋予同一个值
num1,num2=1,2#赋予不同的值
#3.复合赋值运算
base1=10
base1+=3#等价于base=base+3
#其他算术运算符同理

3.比较运算符

#比较运算符
#比较运算符输出的结果为布尔类型
#1.等于:==
print(1==2)
#2.不等:!=
print(1!=2)
#3.大于:>
print(1>2)
#4.大于等于:>=
print(1>=2)
#5.小于:<
print(1<2)
#6.小于等于:<=
print(1<=2)

#除了int,float,bool类型之间,其他不同类型之间不能进行大小比较,相等比较会视为不相等

4.逻辑运算符

#逻辑运算符
#1.逻辑与:and[同真则真]
print(True and True)
print(True and False)
print(False or False)
#2.逻辑或:or[同假则假]
print(True or True)
print(True or False)
print(False or False)
#3.逻辑非:not[真假互换]
print(not True)
print(not False)

5.三目运算符

#三目运算符
#格式:条件成立的结果 if 条件 else 条件不成立的结果
#1.三目运算符无法返回复杂的代码结构
#2.三目运算符如果过于复杂则可读性差
#3.三目运算符的结果可以返回给变量
a=12
b=16
print(a if a<b else b)

八、逻辑语句

1.顺序语句

#顺序语句
#默认的流程语句,代码自上而下依次执行
num=12
num+=1
print(num)

2.分支语句

#分支语句
#通过判断条件选择分支路径执行代码
#由于Python中没有{}来约束作用域,因此要注意缩进!
age=int(input('请输入年龄:'))
#1.单条件分支语句
if age>=18:
    print('该用户已经成年')
#2.对立条件分支语句
if age>=18:
    print('该用户已经成年')
else:
    print('该用户为未成年')
#3.多条件分支语句
if age<12:
    print('用户为儿童')
elif age<18:
    print('用户为青少年')
else:
    print('用户已成年')

3.循环语句

  • while循环
    #1.while循环
    i=0
    while i<10:
      print(i)
      i+=1
  • for循环
    #2.for循环
    #循环规则:依次从容器或序列中获取每一个元素,所有元素获取完毕之后退出循环
    #a.可以使用range
    for i in range(10):
      print(i)
    #b.可以使用str
    for j in 'hello':
      print(j)
    
    '''
    for循环的缺点:
    1.循环次数与容器内元素个数有关,会产生空间占用
    2.循环次数不明确,部分条件下难以直观看到是第几次循环
    for循环的优点:
    1.代码较为精简
    2.无需控制循环变量
    '''
    
    #range函数
    #使用格式:range(起始位置,终止位置,步长)
    #1.区间是一个左闭右开区间
    #2.步长必须为整数,可以省略,默认为1
    #3.起始位置可以省略,默认为0
  • 循环控制语句
    #循环控制语句
    #1.break
    #执行break会无条件直接退出循环体
    for i in range(5):
      print(i)
      if i==3:
          break
    
    i=0
    while i<5:
      print(i)
      if i==3:
          break
      i+=1
    
    #2.continue
    #执行continue会退出该次循环,继续执行下一次循环
    for i in range(5):
      print(i)
      if i==3:
          continue
    
    i=0
    while i<5:
      print(i)
      if i==3:
          continue
      i+=1
    
    #3.else
    #当循环条件不满足导致的正常循环终止时,会执行else中的代码
    #对于for循环来说,会在容器结束后执行else代码
    for i in range(5):
      print(i)
    else:
      print(i+1)
    #对于while循环来说,会在条件不满足时执行else代码
    while i<5:
      print(i)
    else:
      print(i+1)

九、容器类型

1.字符串

  • 字符串的定义
    #字符串的定义
    #1.单引号定义
    str1='单引号定义'
    print(type(str1))
    str2='''三对单引号定义'''
    print(type(str2))
    #2.双引号定义
    str3="双引号定义"
    print(type(str3))
    str4="""三对双引号定义"""
    print(type(str4))
    
    #使用多对引号定义的字符串可以在内部换行
    #''符号表示下一行内容接续该行内容
    str5='''abc
    123'''
    print(str5)
    print(type(str5))
    str6='''abc
    123'''
    print(str6)
    print(type(str6))
  • 字符串的引号冲突
    #字符串引号冲突的解决方法
    #1.使用转义字符''
    print('I'm a student')
    #2.使用与外部定义不同的引号
    print("I'm a student")
    print('''他说:"I‘m a student"''')
    #三对引号会视为一种外部定义
  • 字符串的索引
    #字符串的索引
    #1.正数索引(左向右)
    str1='百川东到海,何时复西归。'
    print(str1[0])
    print(str1[3])
    #2.负数索引(右向左)
    str2='少壮不努力,老大徒伤悲。'
    print(str2[-1])
    print(str2[-3])
  • 字符串的子串
    #字符串的子串
    #[起始位置:结束位置:步长] 左闭右开区间
    str1='abcdefg'
    #1.正数步长,从左到右
    print(str1[0:3:1])
    print(str1[-3:-1:1])
    #2.负数步长,从右到左
    print(str1[5:2:-1])
    print(str1[::-1])#可以使用这种方式进行字符串的翻转
    #3.超出范围的部分会返回一个空字符
    print(str1[0:25:1])
    
    #省略各部分的默认值:
    #起始位置:步长为正数时,默认为字符串起始位置;步长为负数时,默认为字符串结束位置
    #结束位置:步长为正数时,默认为字符串结束位置;步长为负数时,默认为字符串起始位置
    #步长:默认为1
    #冒号:步长前的冒号不能省略,标识获取字符串
  • 字符串的常见操作
    • 查找
    #查找
    str1='abcdefg'
    #1.find()
    #格式:str.find(self,sub,__start,__end)
    #返回int类型的下标位置,数值为模式串首字母所在的下标,未找到返回-1
    #self:无需主动传值
    #sub:需要匹配的模式串
    #__start:查找的起始位置,默认为字符串起始位置
    #__end:查找的结束位置,默认为字符串结束位置
    result1=str1.find('c',0,7)
    print(result1)
    print(type(result1))
    #2.index()
    #使用方法与find相同,但若未找到会直接报错
    result2=str1.index('c',0,7)
    print(result2)
    print(type(result2))
    • 替换
    #替换
    str1='hello a and b and c'
    #1.replace
    #格式:str.replace(self,__old,__new,__count)
    #self:无需主动传值
    #__old:旧值,若旧值不存在则不会发生替换
    #__new:新值
    #__count:替换次数,默认情况或者其值大于字符串长度,则全部替换
    str2=str1.replace('and','&&')
    print(str2)
    str3=str1.replace('and','&&',1)
    print(str3)
    • 拆分
    #拆分
    #1.split
    #格式:split(self,sep,maxsplit)
    #从左向后拆分,返回的数据类型为list类型
    #split生成新的字符串列表,对字符串无影响
    #self:无需主动传值
    #sep:拆分的分隔符,默认为' ',分隔符将被去除
    #maxsplit:最大拆分次数
    str1='hello world and python'
    str2=str1.split(' ')
    print(str2)
    print(type(str2))
    str3=str1.split(' ',2)
    print(str3)
    • 其他操作
    #其他操作
    str1='   hello world   '
    #1.count
    #查询子串在字符串中出现的次数
    print(str1.count('h'))
    #2.len
    #查询字符串的长度
    print(len(str1))
    #3.strip
    #去除字符串两侧的指定字符
    print(str1.strip(' '))
    #4.join
    #合并字符串,格式:分隔符.join(字符串列表)
    str_list=['hello','world']
    str2='@'.join(str_list)
    print(str2)
    • 字符串大小写转换
    #字符串大小写转换
    str1='hello World'
    #1.upper
    #将字符串转换为全大写
    print(str1.upper())
    #2.lower
    #将字符串转换为全小写
    print(str1.lower())
    #3.title
    #将字符串每个单词的首字母大写,以非字母作为识别单词的分隔符
    print(str1.title())
    #4.capitalize
    #将字符串的第一个字母大写,其余为小写
    print(str1.capitalize())
    • 字符串判断
    #字符串判断
    str1='hello world'
    #1.startwith
    #判断字符串是否以某个子串开始,区分大小写
    print(str1.startswith('hello'))
    #2.endwith
    #判断字符串是否以某个子串结束,区分大小写
    print(str1.endswith('world'))
    #3.isupper
    #判断字符串是否全是大写
    print(str1.isupper())
    #4.islower
    #判断字符串是否全是小写
    print(str1.islower())
    #5.istitle
    #判断字符串每个单词是否均为首字母大写
    print(str1.istitle())
    #6.isdecimal,isdigit,isnumeric
    #判断字符串中是否为纯数字
    print(str1.isdecimal())
    print(str1.isdigit())
    print(str1.isnumeric())
    #7.isalnum
    #判断字符串中是否为数字或字母
    print(str1.isalnum())
    #8.isaloha
    #判断字符串中是否为纯字母
    print(str1.isalpha())

2.列表

  • 列表的定义
    #列表的定义
    #格式:变量=[元素1,元素2,元素3,……]
    #1.存储int数据
    list1=[1,2,3]
    print(list1)
    print(type(list1))
    #2.存储str数据
    list2=['a','b','c']
    print(list2)
    print(type(list2))
    #3.混合存储
    list3=['a','2','c']
    print(list3)
    print(type(list3))
  • 列表的索引
    #列表的索引
    list1=[1,2,3]
    #1.正数索引
    print(list1[0])
    #2.负数索引
    print(list1[-1])
  • 列表的常见操作
    #增
    #1.append
    #在原列表末尾添加元素,任何类型都会视为一个元素添加到列表末尾
    list1=[1,2,3]
    list1.append(4)
    print(list1)
    #2.extend
    #在原列表末尾添加容器类型的元素,容器内的元素会被拆分后依次添加
    list2=[1,2,3]
    list2.extend([4,5,6])
    print(list2)
    #3.insert
    #使指定位置为添加的元素,若大于列表长度,则添加到末尾
    #格式:insert(索引,元素)
    list3=[1,2,3]
    list3.insert(1,7)
    print(list3)
    #查
    list1=[1,2,3]
    #1.使用索引
    print(list1[0])
    #2.index
    #查询指定元素出现的索引值,未出现则报错,若存在多个则只输入第一个元素的索引值
    print(list1.index(3))
    #3.count
    #查询指定元素出现的次数
    print(list1.count(3))
    #4.in,not in
    #判断元素是否在列表中
    print(3 in list1)
    print(3 not in list1)
    #删
    #1.remove
    #根据元素值删除元素
    #a.在原列表上进行删除,不会产生新列表,因此不能被变量接收
    #b.只能删除自左向右出现的第一个匹配的元素
    #c.删除的元素值若不存在,则会报错
    list1=[1,2,3,3,3,4,5]
    list1.remove(3)
    print(list1)
    #2.pop
    #根据索引值删除元素
    #a.删除数据后会将数据返回,因此可以使用变量接收
    #b.删除的索引值若不存在,则会报错
    list2=[1,2,3,3,3,4,5]
    list2.pop(0)
    print(list2)
    #3.clear
    #清空列表
    #a.list4=list3实际上赋值的是指针,使用clear清除的是指针指向的空间,因此list4也会变为空列表
    #b.使用list3=[]的方式,实际上是让list3指向新的空间,空间内容为空列表
    list3=[1,2,3,3,3,4,5]
    list4=list3
    list3.clear()
    print(list3)
    print(list4)
    #4.del
    #通用的容器删除方法,前提是能够找到该元素
    #a.若不小心写成了del list5,那么整个列表都会被删除
    list5=[1,2,3,3,3,4,5]
    del list5[5]
    print(list5)
    #改
    #1.通过索引值进行修改
    #a.不存在的下标不能修改
    list1=[1,2,3,4,5]
    list1[0]=6
    print(list1)
    • 其他操作
    #其他操作
    #1.列表反转
    #a.可以使用与字符串相同的反转方法
    list1=[1,2,3,4,5]
    print(list1[::-1])
    #b.reverse
    #在原列表上进行反转,不会产生新列表,因此不能被变量接收
    list2=[1,2,3,4,5]
    list2.reverse()
    print(list2)
    #2.列表排序
    #a.sort
    #在原列表上进行排序,不会产生新列表,因此不能被变量接收
    #排序顺序默认为升序,若需要降序,可以传入参数reverse=True
    list3=[1,5,3,2,4]
    list3.sort()
    print(list3)
    list4=[1,5,3,2,4]
    list4.sort(reverse=True)
    print(list4)
    #3.列表的嵌套
    list5=[[1,2],[3,4,5],[6]]
    print(list5[0][1])
    print(list5[1][2])
    print(list5[2][0])
    #循环遍历
    for it1 in list5:
        for it2 in it1:
            print(it2)
    • 列表推导式
    #列表推导式
    #根据一定的规则快速生成列表
    #格式:变量=[插入数据 for 临时变量 in 容器 (if 条件)]
    #1.常规推导式
    #常规方法:
    list1=[]
    for i in range(5):
        list1.append(i)
    print(list1)
    #推导式方法
    list2=[i for i in range(5)]
    print(list2)
    #2.格式化推导式
    #常规方法
    list3=[]
    for i in range(5):
        list3.append(f'NO.{i}')
    print(list3)
    #推导式方法
    list4=[f'NO.{i}' for i in range(5)]
    print(list4)
    #3.判断推导式
    #单个判断
    list5=[i for i in range(5) if i%2==0]
    print(list5)
    #多个判断
    list6=[i for i in range(5) if i%2==0 if i!=0]
    print(list6)

3.元组

  • 元组的定义
    #元组的定义
    #元组中的元素不能进行修改,只能进行查询
    #格式:变量=(元素1,元素2,元素3,……)
    #1.普通元组
    tuple1 = (1, 2, 3)
    print(tuple1)
    print(type(tuple1))
    #2.空元组
    tuple2=()
    print(tuple2)
    print(type(tuple2))
    #3.单元素元组
    #对于tuple3,会被认为是使用()修改算术优先级,因此tuple3的类型是int
    #单元素元组在创建时,必须在元素结尾添加',',如tuple4
    tuple3=(1)
    print(tuple3)
    print(type(tuple3))
    tuple4=(1,)
    print(tuple4)
    print(type(tuple4))
    #4.略写元组
    #可以省略元组外侧的'()',会自动添加'()',但仅限于元组的定义和返回
    tuple5=1,2,3,4,5
    print(tuple5)
    print(type(tuple5))
  • 元组的特性
    #元组的特性
    tuple1 = (1, 2, 3)
    #1.通过索引获取内部元素
    print(tuple1[0])
    #2.不能通过索引修改内部元素
    #tuple1[0]=3
    #3.不能通过索引删除内部元素
    #del(tuple1[0])
    #4.不能追加内部元素
    ##简而言之,不能对元组内部的元素进行修改,只能进行查询
    #5.元组切片
    #元组是可以切片的,本质上是生成了一个新的元组
    print(tuple1[:2])
  • 元组的查询
    #元组的查询
    tuple1 = (1, 2, 3, 3, 3, 3)
    #1.通过索引查询
    print(tuple1[0])
    #2.index
    #查询从左至右元素第一次出现的索引位置,不存在则报错
    print(tuple1.index(3))
    #3.count
    #查询指定元素出现的次数
    print(tuple1.count(3))
    #4.len
    #查询元组的长度
    print(len(tuple1))

4.集合

  • 集合的定义
    #集合的定义
    #格式:变量={元素1,元素2,……}
    #1.普通集合
    set1={1,2,3}
    print(set1)
    print(type(set1))
    #2.空集合
    #注意,仅使用'{}'创建的是字典!
    set2={}
    print(set2)
    print(type(set2))
    #创建空集合的方法
    set3=set()
    print(set3)
    print(type(set3))
    #3.单元素集合
    set4={3}
    print(set4)
    print(type(set4))
  • 集合的特性
    #集合的特性
    #1.无序:集合内元素有一定的顺序,不能被人为控制
    set1={5,3,4,2,1}
    set2={4,2,3,5,1}
    print(set1)
    print(set2)
    #字符串类型每次打印的结果不一定相同
    set3={'a','b','c'}
    print(set3)
    #2.不重复:集合内的元素会自动去重
    #去重规则是后添加的重复元素会被去除
    set4={1,1,1,1,2,2,2,2,3,3,3,3,3,}
    print(set4)
    #数值型元素在去重时,True>>>1>>>1.0,False>>>0>>>0.0
    set5={True,False,1.0,1,0,0.0}
    print(set5)

5.字典

  • 字典的定义
    #字典的定义
    #格式:变量={键1:值1,键2:值2,……}
    #1.常规字典
    #键是值的唯一标识,通过键可以获取值,因此,字典中键不可以重复,但值可以
    dict1={'name':'Jack','age':18,'gender':'male'}
    print(dict1)
    print(type(dict1))
    #重复的键会覆盖已有的值,重复的值不会
    dict2={'name':'Jack','age':18,'gender':'male','name':'Tom','age2':18}
    print(dict2)
    print(type(dict2))
    #2.空字典
    dict3={}
    print(dict3)
    print(type(dict3))
  • 字典的特性
    #字典的特性
    dict1={'name':'Jack','age':18,'gender':'male'}
    #1.无序:字典无法使用索引,因此也可以认为是无序的
    #print(dict1[1]) 报错!
    #2.键值对:字典通过键获取值
    print(dict1['name'])
  • 字典的常见操作
    #查
    dict1={'name':'Jack','age':18,'gender':'male'}
    #1.使用键值对
    #格式:变量[键]
    #若键不存在则会报错!
    print(dict1['name'])
    #print(dict1['weight']) 报错!
    #2.get
    #使用get时,若键不存在会默认返回None,或者可以自定义返回的默认数据
    print(dict1.get('age'))
    print(dict1.get('weight'))
    print(dict1.get('weight','没有这个数据'))
    #3.keys
    #查询字典中所有的键
    print(dict1.keys())
    #4.values
    #查询字典中所有的值
    print(dict1.values())
    #5.items
    #查询字典中所有的键值对,以元组形式返回
    print(dict1.items())
    #增
    #字典中只能增加键值对
    dict1={}
    #1.键=值
    #格式:变量[键]=值
    dict1['name']='Jack'
    print(dict1)
    #2.update
    #a.格式:变量.update(字典类型数据)
    dict1.update({'age':18})
    print(dict1)
    #b.格式:变量.update(键=值)
    #注意,键不能添加引号
    dict1.update(gender='male')
    print(dict1)
    #改
    #其实就是添加一个重复键,覆盖原有键
    dict1={'name':'Jack','age':18,'gender':'male'}
    #1.键=值,前提是键存在
    dict1['name']='Tom'
    print(dict1)
    #2.update
    dict1.update({'age':20})
    print(dict1)
    dict1.update(gender='female')
    print(dict1)
    #删
    dict1={'name':'Jack','age':18,'gender':'male','NO.':'001',"weight":50,'height':180}
    #1.pop
    #根据指定的键删除对应的值,删除的同时会返回对应的值,若键不存在则报错
    print(dict1.pop('gender'))
    print(dict1)
    #2.popitem
    #删除最后一个键值对
    dict1.popitem()
    print(dict1)
    #3.clear
    #清空字典
    dict1.clear()
    print(dict1)
    • 遍历
    #遍历
    dict1={'name':'Jack','age':18,'gender':'male','NO.':'001',"weight":50,'height':180}
    #1.for循环遍历
    #i是键
    for i in dict1:
        print(i,dict1[i])
    #2.keys
    #i是键
    for i in dict1.keys():
        print(i,dict1[i])
    #3.values
    #i是值
    for i in dict1.values():
        print(i)
    #4.item
    #i是键值对
    for i in dict1.items():
        print(i)
    #可以通过两个变量分别获取键和值
    for i,j in dict1.items():
        print(i,j,sep=':')

6.公共方法

  • 公共运算符
    • +
    #+
    #容器的加法就是进行拼接
    #1.str
    print('123'+'456')
    #2.list
    print([1,2,3]+[4,5,6])
    #3.tuple
    print((1,2,3)+(4,5,6))
    #d.set和dict不能使用加法运算
    • *
    #*
    #容器的乘法就是n个容器相加
    #1.str
    print('123'*3)
    #2.list
    print([1,2,3]*3)
    #3.tuple
    print((1,2,3)*3)
    #4.同理,set和dict不能使用乘法运算
    • in和not in
    #in和not in
    #判断元素在容器内是否存在
    #1.dict
    dict1={'name':'Jack','age':18}
    print('name' in dict1)
    #in判断是字典的键
    #print('Jack' in dict1) 报错
    print('age' not in dict1)
    #2.str
    str1='hello world'
    print('hello' in str1)
    print('world' not in str1)
  • 公共函数
    • len
    #len
    #获取容器元素的个数
    #1.list
    list1=[1,2,3,4,5]
    print(len(list1))
    #2.tuple
    tuple1=(1,2,3,4,5)
    print(len(tuple1))
    #3.set
    #set会自动去重,因此len计算的是去重之后的长度
    set1={1,2,3,4,5,5,5,5}
    print(len(set1))
    #4.dict
    #dict中存储的是键值对,因此len计算的是键值对的个数
    dict1={'name':'Jack','age':18}
    print(len(dict1))
    • del
    #del
    #删除容器中的元素
    #1.list
    list1=[1,2,3,4,5]
    del list1[0]
    print(list1)
    #2.dict
    dict1={'name':'Jack','age':18}
    del dict1['age']
    print(dict1)
    #3.无法删除set,因为set的数据无法定向获取
    #4.无法删除str和tuple,因为str和tuple无法修改
    • max和min
    #max和min
    #max:获取容器中的最大值
    #min:获取容器中的最小值
    #1.list
    print(max([1,5,4,7,2]))
    print(min([1,5,4,7,2]))
    #2.dict
    #dict中比较的是值,输出的是键
    print(max({'a':1,'b':2,'c':3}))
    print(min({'a':1,'b':2,'c':3}))
    • 其他函数
    #1.sum
    #获取容器中所有数据的和,前提是保证容器中所有数据的数据类型一致
    print(sum([1,2,3,4,5]))
    #2.any
    #判断容器中元素是否都为空
    print(any([1,2,3,4,5]))
    print(any([None,None]))
    #3.all
    #判断容器中元素是否都不为空
    print(all([1,2,3,4,5]))
    print(all([None,None,5,4,3]))

十、函数

1.函数定义

  • 函数的定义
    #函数的定义
    """
    格式:
    def 函数名(参数列表):
      函数体
    """
    #1.定义函数
    def func():
      print("hello world")
    #2.调用函数
    func()
  • 函数定义的注意事项
    #注意事项
    #1.函数需要先定义后调用
    func() #报错,函数未定义
    #2.定义同名函数,后定义的函数会覆盖先定义的函数
    def func1():
      print('hello world')
    def func1():
      print('你好')
    func1() #实际打印的是'你好'
    #3.定义同名变量,同名变量会覆盖同名的函数
    def func2():
      print('hello world')
    func2='hello world'
    func2() #报错,此时func2是str类型
  • 函数说明文档
    #函数说明文档
    #使用方式:鼠标悬停在函数调用位置,或者按住Ctrl+鼠标悬停
    #创建方式:在函数定义下方的第一行进行多行注释,系统会建议使用三双引号多行注释法
    #使用:param解释参数、:return解释返回值
    def Sum(num1, num2):
      """
      实现两个数的加法
      :param num1: 左侧加数
      :param num2: 右侧加数
      :return: 返回两个数的和
      """
      return num1 + num2
    Sum(1,2)
  • 函数的参数与返回值
    #函数的参数与返回值
    #1.函数的参数
    #在函数的参数列表可以添加参数,参数可以作为函数体内已知的变量使用,我们称之为形参
    #在调用函数时传入参数,可以为函数参数列表对应位置的参数赋值,我们称之为实参
    #若形参与实参的个数不同,会产生报错
    def Line(n):
      """打印从0到n的数字"""
      for i in range(n+1):
          print(i)
    Line(5)
    #2.函数的返回值
    #返回值是函数体执行产生的结果,具有一定的数据类型,使用return进行返回
    def Sum(num1,num2):
      return num1+num2
    print(Sum(1,2))
    print(Sum(2,3))

2.作用域

  • 变量的作用域
    #变量的作用域
    """
    作用域可以认为是一个区域,位于该区域内的事物可以在该区域内使用
    作用域之间可以相互嵌套,类似于数学集合中包含和属于的关系
    暂称包含其他作用域的为外侧作用域,被包含的作用域为内侧作用域
    当然,这种关系是相对的,一个作用域可以是其包含的作用域的外侧作用域,也可以是其被包含的作用域的内侧作用域
    在外侧作用域定义的事物可以在内侧作用域使用,因为内侧作用域本身就属于该作用域,因此也是外侧作用域的范围之内
    但在内侧作用域定义的事物不能在外侧作用域使用,因为超出了内侧作用域的范围
    建议参考C++,在C++内会使用{}标明作用域范围,在Python中则是使用缩进
    注意,可能存在多个同级作用域,但它们互不相交
    例如:作用域a,b,c同属于全局作用域,a,b,c是同级作用域,但a,b,c互不相交,因此其中的变量不能在其他作用域使用
    """
    #1.全局变量
    #定义在文件作用域,也就是在最外侧作用域的变量,因此可以在文件的任何位置进行使用
    age=18
    def func1():
      print(age)
    func1()
    #2.局部变量
    #定义在内侧作用域的变量,只能在内侧作用域的范围内使用,不能在外侧作用域使用
    def func2():
      name='Jack'
    print(name) #报错,因为name在内侧作用域,不能在外侧作用域使用
    #无需纠结,重点是弄清楚变量存在的作用域
  • 不同作用域的同名变量
    #不同作用域的同名变量
    #在不同作用域中可以定义同名变量,不会对其他作用域中的变量产生影响
    num=100
    def func():
      num=500 #这里的num是局部作用域的变量,不会影响全局作用域的num
      print(num)
    func() #打印的是函数体内的num
    print(num) #打印的是全局的num
  • global关键字
    #global
    #作用是在局部作用域声明全局变量
    num=100
    def func():
      global num #声明了num为全局变量,若全局变量存在,则直接使用该全局变量
      num=500 #此时修改的是全局变量num的值
      print(num)
    func()
    print(num)
    #注意
    #a.在局部作用域不能直接修改全局变量,会生成同名的局部变量进行修改,若需要修改全局变量,要使用global关键字声明其为全局变量
    #b.若作用域内已经存在同名变量,则不能使用global声明同名的全局变量,反之同理

3.函数的细节

  • 函数嵌套
    #函数嵌套
    #在函数的函数体中可以调用其他函数
    def Output(num):
      print(num)
    
    def Sum(num1, num2):
      num3 = num1 + num2
      Output(num3)
    
    Sum(1, 2)
  • 函数执行过程
    #函数执行过程
    """
    Python是解释型语言,其中的函数在主程序执行时,只会记录函数名称,当实际调用函数时才会解释函数体
    1.若函数没有被执行,其函数体中错误的部分也不会在执行中产生报错
    2.函数嵌套时,函数的定义没有顺序之分,因为只有在函数被调用时才会进入函数体内进行解释
    3.系统内置函数会在Python启动时自动加载
    """
  • 返回值
    #return
    #1.return的作用
    #函数体中的return起到返回函数的返回值和结束函数体的作用
    #因此一个函数体中只会有一个return被执行
    #return之后的代码不会被执行
    def func1():
      print('hello')
      return
      print('world')
    func1()
    #2.return的默认值
    #在不使用return或不填写return的返回值时,默认返回None
    def func2():
      return
    result=func2()
    print(result)
    #3.return返回多个值
    #return后若存在多个数值,则会返回元组类型
    def func3():
      return 1,2,3
    result=func3()
    print(result)
  • 实参
    #实参
    def func1(a,b,c,d):
      print(a,b,c,d)
    #1.位置参数赋值
    #实参的位置参数赋值法,是按照对应位置进行实参参数的传递,自左向右依次赋值
    func1(1,2,3,4)
    #2.关键字参数赋值
    #关键字参数赋值是根据形参的标识符进行精确赋值,无关顺序,但标识符指向的形参要存在
    #格式:标识符=值
    func1(d=4,c=3,b=2,a=1)
    #3.位置与关键字混合赋值
    #位置参数赋值和关键字参数赋值可以混合使用,但要注意不能给同一参数重复赋值
    func1(1,2,d=4,c=3)
  • 形参
    #形参
    #1.位置参数
    #形参的位置参数自左向右依次定义,必须依次赋值
    def func1(a,b,c,d):
      print(a,b,c,d)
    func1(1,2,3,4)
    #2.缺省参数(默认参数)
    #形参在定义时可以赋予默认值,在该形参没有得到传值时,可以使用默认值
    #缺省参数必须出现在位置参数之后!
    def func2(a,b,c,d=5):
      print(a,b,c,d)
    func2(1,2,3,4)
    func2(1,2,3)
    #3.位置不定长参数
    #可以定义任意个位置参数
    #格式:*args
    def func3(*args):
      print(args)
    #a.当有多个实参传入时,args会将其打包为元组存储
    func3(1,2,3,4)
    #b.args不能使用关键字参数赋值
    #func3(args=(1,2,3,4)) #报错
    #c.args是官方文档中的默认名,也可以修改为其他名称
    def func4(*num):
      print(num)
    func4(1,2,3,4)
    #d.args可以和其他形参混合使用
    #注意,args会接收所有的位置参数赋值,下方的错误在于a,b,c没有赋值
    """
    def func5(*args,a,b,c,d=4):
      print(a,b,c,d,args)
    func5(1,2,3,4,5,6,7,8,9)
    """
    #解决方案:
    #(1)使用关键字赋值为其他参数赋值
    #(2)将args放置在位置参数之后,建议顺序为:位置参数--位置不定长参数--缺省参数(一般缺省参数较少赋值)
    #4.关键字不定长参数
    #可以接收任意个关键字参数
    #格式:**kwargs
    #a.在实参部分使用关键字不定长参数,会使用字典的方式存储在kwargs中,关键字存储为键,赋值存储为值
    def func6(**kwargs):
      print(kwargs)
    func6(a=1,b=2,c=3,d=4)
    #b.kwargs不能使用关键字参数赋值,无法达到预期结果
    def func7(**kwargs):
      print(kwargs)
    func7(kwargs={'a':1,'b':2,'c':3,'d':4})
    #视为为一个名为kwargs的变量赋予一个字典类型的值
    #c.kwargs是官方文档中的默认名,也可以修改为其他名称
    def func8(**nums):
      print(nums)
    func8(a=1,b=2,c=3,d=4)
    #d.kwargs可以与其他形参混合使用
    #(1)kwargs需要放置在末尾
    #(2)使用关键字参数赋值时,会优先赋值存在的形参,不存在的形参会赋值给kwargs

十一、引用

1.引用

#引用
#Python中变量和值是通过引用连接起来的,所有的数据存储都是引用关系
a=1
b=True
#1.id()
#输出变量的引用地址
print(id(a))
#2.is
#判断变量的引用地址是否相同
print(a is b)
#注意区别,判断变量的值是否相同
print(a == b)

2.容器类型的值与引用

#容器类型的值与引用
#1.list
list1=[1,2,3]
list2=[1,2,3]
print(list1 == list2)
print(list1 is list2)
#2.tuple
tuple1=(1,2,3)
tuple2=(1,2,3)
print(tuple1 == tuple2)
print(tuple1 is tuple2)
#3.set
set1={1,2,3}
set2={1,2,3}
print(set1 == set2)
print(set1 is set2)
#4.str
str1='hello'
str2='hello'
print(str1 == str2)
print(str1 is str2)
#5.dict
dict1={'a':1,'b':2,'c':3}
dict2={'a':1,'b':2,'c':3}
print(dict1 == dict2)
print(dict1 is dict2)
"""
结论:
(1)list、set、dict的数据相同,类型相同,引用地址不一定相同,因为可修改的数据类型会存储在不同空间
(2)str,tuple的数据相同,类型相同,引用地址相同,因为不可修改的数据类型会存储在同一空间
"""
#6.赋值情况
list1=[1,2,3,4,5]
list2=list1
print(list1 == list2)
print(list1 is list2)
list1.append(6)
print(list2)
"""
结论:
(1)使用容器为容器赋值时,会使用同一引用地址
(2)修改同一引用地址的数据,所有使用同一引用地址的变量都会改变
"""

3.可变数据类型和不可变数据类型

#1.可变数据类型
#在不改变引用地址的前提下,存储数据可以被修改
#a.list
list1=[1,2,3,4,5]
print(list1)
print(id(list1))
list1.append(6)
print(list1)
print(id(list1))
#b.set
set1={1,2,3,4,5}
print(set1)
print(id(set1))
set1.add(6)
print(set1)
print(id(set1))
#c.dict
dict1={'a':1,'b':2,'c':3}
print(dict1)
print(id(dict1))
dict1.update({'d':4})
print(dict1)
print(id(dict1))
#2.不可变数据类型
#在不改变引用地址的前提下,存储数据不可以被修改
#a.基础数据类型:int、float、bool都是不可变数据类型
#b.str、tuple类型

#补充:修改引用地址必须使用'='

十二、lambda表达式

1.lambda的定义

#lambda表达式(匿名函数)
#lambda的定义
#格式:lambda 参数列表:返回值
lambda num1,num2:num1+num2

2.lambda的调用

#lambda的调用
#1.直接调用
#格式:(lambda表达式)(实参列表)
#这种调用方式只能使用一次,下一次使用需要重新定义lambda表达式
res=(lambda num1,num2:num1+num2)(3,4)
print(res)
#2.间接调用
#使用变量接收lambda表达式,可以多次使用
Sum2=lambda num1,num2:num1+num2
print(Sum2(3,4))
print(Sum2(4,4))

3.lambda的作用

#lambda的作用
#lambda表达式可以被变量接收,因此可以作为参数被传递
"""
示例:sort函数
sort的完整格式sort(self,key,reverse)
self:系统自动传值
key:排序规则,常用lambda作为参数传递
reverse:排序顺序,默认为False(升序),可以更改为True(降序)
"""
list1=[(3,4),(1,2),(6,8),(7,9)]
#自定义排序根据元组第二项排序
#格式:key=lambda 元素:排序规则
list1.sort(key=lambda x:x[1])#匿名函数传入list1中的元素x,x是一个元组,返回元组中下标为1的数值被key接收作为排序关键字
print(list1)

十三、文件

1.文件的读取

#文件的读取
#1.打开文件(只读模式)
"""
打开文件:
函数格式:open(file,mode,encoding) 返回file对象
file(文件路径):默认为py文件的当前目录,可以指定绝对路径或相对路径
mode(读写模式):r-只读,w-只写,a-追加
encoding(编码集):指定编码集
"""
file=open('26_file.txt','r',encoding='utf-8')
#2.读取文件
#a.read():一次读取全部文件内容
"""
content=file.read()
print(content)
"""
#b.read(n):一次最多读取n个字符
"""
content=file.read(5)
print(content)
"""
#c.readline():一次读取一行数据
"""
content=file.readline()
print(content)
"""
#d.readlines(n):一次读取n个数据(默认为-1:表示全部),返回列表,以行为单位进行分割
"""
content=file.readlines()
print(content)
"""
#上述函数会改变文件指针的位置,多次读取会从上次文件指针的位置开始
#3.关闭文件
file.close()

2.文件的写入

#文件的写入
#1.打开文件(只写模式)
file=open('26_file.txt','w',encoding='utf-8')
"""
注意
(1)以只写模式打开时,若文件存在,该文件会被清空!!!
(2)以只写模式打开时,若文件不存在,则会创建同名文件。
(3)在Windows系统环境下,encoding的默认值为gbk,一般指定为utf-8。
"""
#2.写入文件
#a.write()
file.write('hello world!')
#b.writelines():极少使用
#传参格式:[字符串1n,字符串2n,...,字符串n]
file.writelines(['hello world!n','hello!n','world!'])
#上述函数会改变文件指针的位置,多次写入会从上次文件指针的位置开始
#3.关闭文件
file.close()

3.文件的追加

#文件的追加
#1.打开文件(追加模式)
file=open('26_file.txt','a',encoding='utf-8')
"""
注意:
(1)以追加模式打开时,若文件存在,文件不会被清空,文件指针指向文件末尾
(2)以追加模式打开时,若文件不存在,则会创建同名文件
"""
#2.写入文件
file.write("hello world!")
file.writelines(['hellon','world'])
#3.关闭文件
file.close()

4.文件的读写模式

#文件的读写模式
"""
对于读写模式:
r,w,a:字符型文件读写模式
r+,w+,a+":加强版字符型文件读写模式(可以同时进行读写)
rb,wb,ab:字节型文件读写模式(也可以操作字符型文件)
rb+,wb+,ab+:加强版字节型文件读写模式(可以同时进行读写)
"""
#1.打开文件
#file=open('26_file.txt','r+',encoding='utf-8')#r+不会清空文件,且将文件指针指向开头
file=open('26_file.txt','w+',encoding='utf-8')#w+会清空文件,且将文件指针指向开头
#file=open('26_file.txt','a+',encoding='utf-8')#a+不会清空文件,且将文件指针指向末尾
#2.写入文件
file.write('hello world')#文件指针一开始在开头,若文件原本存在内容,写入会直接覆盖对应数量的字符
#3.读取文件
"""
#解决方案:seek
将文件指针指向文件开头位置
前一位:偏移量
后一位:0-文件开始位置,1-当前位置,2-文件末尾
"""
file.seek(0,0)
content=file.read()#由于write变动了文件指针的位置,read无法读取到新写入的内容
print(content)
#4.关闭文件
file.close()

5.文件类型与编码集

#文件类型与编码集
"""
字节型文件:以字节形式存储的数据文件,如图片、音频、视频等
字符型文件:使用字符集将字节进行编码之后形成的文件
"""
#1.创建不同类型数据
#a.创建字符型数据
str1='abc'
print(str1)
print(type(str1))
#b.创建二进制字符串
byte1=b'def'
print(byte1)
print(type(byte1))
#2.字节字符类型转换
#a.字符->字节
byte2=str1.encode(encoding='utf-8')
print(byte2)
print(type(byte2))
#b.字节->字符
str2=byte1.decode(encoding='utf-8')
print(str2)
print(type(str2))

十四、异常

1.异常与警告

  • 异常:程序运行过程中出现的错误,会造成程序的终止(有时候我们会故意制造异常来发现问题,优化程序)
  • 警告:程序运行可能会导致未知的效果,但不会造成程序的终止(注意,第三方库中被认为废弃的方法也会引起警告)

2.常见异常

  • NameError
  • TypeError
  • KeyError
  • ValueError
  • IndexError

3.异常捕获

#异常捕获
#1.常规异常捕获
"""
异常捕获方式
try:
    可能出现异常的代码
except:
    出现异常后执行的代码

try必须和except同时使用!!!
"""
try:
    print(1/0)
except:
    print('0不能作为除数出现')
#2.指定类型异常捕获
"""
指定类型异常捕获方式
try:
    可能出现异常的代码
except 异常类型1:
    解决方案1
except 异常类型2:
    解决方案2
......   
"""
#a.捕获方法一
try:
    print(a) #NameError
    print(1+'2') #TypeError
except NameError:
    print('变量未定义!')
except TypeError:
    print('类型错误!')
except Exception:
    print('Exception可以捕获任何异常')
#b.捕获方法二
try:
    print(a)
    print(1+'2')
except (NameError,TypeError):
    print('变量未定义或者类型错误')
#3.捕获异常描述信息
"""
try:
    可能出现异常的代码
except 异常类型 as 变量:
    print(变量)
"""
try:
    print(1/0)
except ZeroDivisionError as e:
    print(e)

4.异常的其他控制逻辑

#异常的其他控制逻辑
#1.else
"""
try:
    可能出现异常的代码
except:
    出现异常时执行的代码
else:
    未出现异常时执行的代码
"""
try:
    print('111')
except Exception:
    print('出现异常')
else:
    print('未出现异常')
#2.finally
"""
try:
    可能出现异常的代码
except:
    出现异常时执行的代码
else:
    未出现异常时执行的代码
finally:
    无论出现异常都会执行的代码
"""
try:
    print('111')
except Exception:
    print('出现异常')
else:
    print('未出现异常')
finally:
    print('finally被执行')

5.异常穿透(异常传递)

#异常穿透(异常传递)
#当异常嵌套时,若内层出现异常却没有捕获成功,则会将异常传递给外层捕获
#若外层也没有捕获成功,则继续向外层传递,直到最外层的系统层次,系统层次会报错终止程序
try:
    print('外层try')
    try:
        print('内层try')
        print(1/0) #0除异常
    except NameError:
        print('内层NameError异常')
except:
    print('外层异常')

十五、模块

1.模块导入

#模块的导入
#1.全局导入
"""
全局导入:导入整个模块的数据
导入方式:import 模块名
调用方式:模块名.函数名
"""
# import random
# print(random.randint(1,10))
#2.局部导入
"""
局部导入:仅导入模块中的某一个函数
导入方式:from 模块名 import 函数名
调用方式:函数名

函数名处可以使用通配符'*'导入多个函数
"""
# from random import randint
# print(randint(1,10))

2.模块的别名

#模块的别名
#1.为模块起别名
"""
格式:import 模块名 as 别名
     import 模块名1 as 别名1,模块名2 as 别名2,..(不建议使用!因为模块中可能存在同名函数!)

给模块起别名后,原名称将无法在程序中使用
"""
import random as rd
print(rd.randint(1, 10))
#2.为函数起别名
"""
格式:from 模块名 import 函数名 as 别名
     from 模块名 import 函数名1 as 别名1,函数名2 as 别名2,...

给函数起别名后,原名称将无法在程序中使用
"""
from random import randint as rdt
print(rdt(1, 10))

3.自定义模块

#自定义模块
"""
导入自定义模块的方式与导入系统模块的方式一样

可以导入的内容:
(1)被标识符存储的内容,例如函数、全局变量等
(2)作用域为全局
"""
import my_module
my_module.output()

4.all的使用

#在模块开始时可以使用__all__存储一个字符串列表
#在使用from ... import *时就会导入__all__存储的内容
#使用其他导入方式不会被影响

__all__=['name','output']#导入的内容是name和函数output,age和gender无法使用

name='Jack'
age=18
gender='male'

def output():
    print('hello world!')

5.包

  • 包的创建
    #包:模块的集合
    
    #创建包的方式
    #1.通过PyCharm
    """
    在PyCharm中,可以右击目录->new->Python Package创建一个包
    这个包在PyCharm中会显示特殊的图标(文件夹图标中有一个小圆环)
    会默认创建__init__.py文件
    """
    #2.手动创建
    """
    手动在目录下创建一个__init__.py文件
    PyCharm会识别该文件夹为一个包
    """
  • 包的导入
    #包的使用
    #1.全部导入
    """
    导入格式:import 包名.模块名
    调用功能:包名.模块名.函数名
    """
    #2.局部导入
    """
    方式一:
    导入格式:from 包名 import 模块名
    调用功能:模块名.函数名
    
    方式二:
    导入格式:from 包名.模块名 import 函数名
    调用功能:函数名
    """

附录:模块库

1.OS模块

#os模块:operator system---操作系统模块
#本质上是Python在调用操作系统的功能

open('1.txt','w',encoding='utf-8')
#1.导入方法
import os
#2.常用方法
#a.os.getcwd():获取当前文件所在的绝对路径
print(os.getcwd())
#b.os.rename(旧文件路径,新文件路径):为文件重命名
os.rename('1.txt','27_os.txt')
#c.os.remove(文件路径):删除文件
os.remove('27_os.txt')#慎用!删除的文件不会进入回收站暂存
#d.os.listdir():获取指定目录中所有文件名称,默认为当前目录
print(os.listdir())
#e.os.makedirs():创建一个空文件夹
os.makedirs('./dir')

#Windows中编写目录路径时,需要使用'\'来进行转义!!!
#Linux中使用'/'即可

学习是一段漫长的旅途