零基础学Python学习笔记

2023-05-16

Python学习笔记

代码下载地址

链接:https://pan.baidu.com/s/1yGnpfq4ZHeKpt4V0J_PTSg
提取码:hmzs

1. Python 基础语法

1.1 基本数据类型

  1. 整数(int):8
  2. 浮点数(float):8.8
  3. 字符串(str):“8” “Python”
  4. 布尔值(bool):True False
print(type(int('8'))) # 将字符串8转化为整型
print(type(str(123))) # 将整型123转为字符串类型
print(type(bool(123))) # 将整型123转为布尔类型
print(bool(0)) # 将整型0转为布尔类型 非0为True,0为False

1.2 变量的定义和常用操作

  • a = 123 a为变量名称,=为变量赋值,123为变量得到的值
# 网络带宽计算
print(100/8)

bandwidth = 100
ratio = 8
print(bandwidth/ratio)

Python编码风格指南

2. 序列

2.1 序列的概念

  • 特点:成员都是有序排列,并且可以通过下标偏移量访问到它的一个或几个成员

  • 字符串、列表、元组三种类型都属于序列

  • 字符串:“abcd”

  • 列表:[0, “abcd”]

  • 元组:(“abc”, “def”)

  • 思考:元组和列表的区别?

    答:相同点:都是序列,可以通过索引访问,可以存储任何数据类型

    不同点:写法不同,列表是可变的,元组是不可变的

  • 无关知识点 :在Python单引号跟双引号字符串没有区别,只是当你的字符串内容中有单引号出现时可以用双引号将整个字符串圈起来

chinese_zodiac = '鼠牛虎兔龙蛇马羊猴鸡狗猪'

print(chinese_zodiac[0:4]) # 下标从0开始
print(chinese_zodiac[-1]) # 取最后一个元素

2.2 字符串的定义和使用

# 记录生肖,根据年份来判断生肖
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'

year = 2022
print(year%12)
print(chinese_zodiac[year%12])

2.3 序列的基本操作

  1. 对象[not] in 序列
  2. 序列+序列
  3. 序列*整数
  4. 序列[0:整数]
chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'

print('狗' in chinese_zodiac)
print('狗' not in chinese_zodiac)
print(chinese_zodiac + 'abcd')
print(chinese_zodiac * 3)

2.4 元组的定义和常用操作

  • 比较操作
a = (4)
b = (5)
print(a > b) # 元组当中只有一个数时是按这一个元素的大小去比较
print(a < b)
c = (1,50)
d = (1,200)
print(c > d) # 当元组中有两个元素的时候是将这两个元素结合之后进行比较,此处是150 > 1200
print(c < d)
  • 案例演示
# 输入一个日期判断其是哪个星座
zodiac_name = (u'魔羯座', u'水瓶座', u'双鱼座', u'白羊座', u'金牛座', u'双子座', u'巨蟹座',
           u'狮子座', u'处女座', u'天秤座', u'天蝎座', u'射手座') # 在这u是指unicode编码,防止乱码
zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22), (7, 23),
               (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
(month, day) = (2, 15)

zodiac_day = filter(lambda x: x <= (month, day), zodiac_days)
# print(zodiac_day)
zodiac_len = len(list(zodiac_day))
print(zodiac_name[zodiac_len])

2.5 列表的定义和常用操作

常用操作

  • append(x):向列表中插入一个元素x
  • remove(x):从列表中删除元素x
a_list = ['abc', 'xyz']
a_list.append('X')
print(a_list)
a_list.remove('xyz')
print(a_list)

3. 条件与循环

3.1 条件语句

  • if语句

    • 关键字
    • 判断条件表达式
    • 判断为真时的代码块
    格式:
    if 表达式:
    	代码块
    
    
    • 可以和else、elif(else-if)语句组合成更复杂的判断
    if 表达式:
    	代码块
    elif 表达式:
    	代码块
    else:
    	代码块
    
    

3.2 循环

  • for语句

    for 迭代变量 in 可迭代对象:
    	代码块
        
    # 例子    
    chinese_zodiac = '猴鸡狗猪鼠牛虎兔龙蛇马羊'
    
    for cz in chinese_zodiac:
        print(cz)
    
    for i in range(3): # 输出0-2
        print(i)
    
    for i in range(1, 3): # 输出1-2
        print(i)
    
    for year in range(2000, 2023):
        print('%s 年的生肖是 %s' %(year, chinese_zodiac[year % 12]))
    
    
  • while语句

    while 条件表达式:
        代码块
    
    
  • for循环+if判断:

    # 输入一个日期判断其是哪个星座
    zodiac_name = (u'魔羯座', u'水瓶座', u'双鱼座', u'白羊座', u'金牛座', u'双子座', u'巨蟹座',
               u'狮子座', u'处女座', u'天秤座', u'天蝎座', u'射手座') # 在这u是指unicode编码,防止乱码
    zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22), (7, 23),
                   (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
    
    # 用户输入月份和日期
    int_month = int(input('请输入月份:'))
    int_day = int(input('请输入日期:'))
    
    for zd_num in range(len(zodiac_days)):
        if zodiac_days[zd_num] >= (int_month, int_day):
            print(zodiac_name[zd_num])
            break
        elif int_month == 12 and int_day > 23:
            print(zodiac_name[0])
            break
    
    
  • while循环+if判断

    # 输入一个日期判断其是哪个星座
    zodiac_name = (u'魔羯座', u'水瓶座', u'双鱼座', u'白羊座', u'金牛座', u'双子座', u'巨蟹座',
               u'狮子座', u'处女座', u'天秤座', u'天蝎座', u'射手座') # 在这u是指unicode编码,防止乱码
    zodiac_days = ((1, 20), (2, 19), (3, 21), (4, 21), (5, 21), (6, 22), (7, 23),
                   (8, 23), (9, 23), (10, 23), (11, 23), (12, 23))
    
    # 用户输入月份和日期
    int_month = int(input('请输入月份:'))
    int_day = int(input('请输入日期:'))
    n = 0
    while zodiac_days[n] < (int_month, int_day):
        if int_month == 12 and int_day > 23:
            break
        n += 1
    print(zodiac_name[n])
    
    

4. 映射与字典

  • 字典

    • 特性:包含哈希值和指向的对象

    • 格式:{"哈希值":"对象"}

    • 简单使用:

      dict1 = {}
      print(type(dict1))
      dict2 = {'x':1, 'y':2}
      dict2['z'] = 3
      
      print(dict2)
      
      
  • 列表推导式与字典推导式

    # 1. 列表一般写法
    even_list = []
    for i in range(1, 11):  # 记录1-10中所有偶数的平方
        if (i % 2) == 0:
            even_list.append(i * i)
    print(even_list)
    # 1. 列表的列表推导式写法
    even_list2 = [i * i for i in range(1, 11) if (i % 2) == 0]
    print(even_list2)
    
    zodiac_name = (u'魔羯座', u'水瓶座', u'双鱼座', u'白羊座', u'金牛座', u'双子座', u'巨蟹座',
                   u'狮子座', u'处女座', u'天秤座', u'天蝎座', u'射手座')
    # 2. 字典的一般写法
    z_dict = {}
    for i in zodiac_name:
        z_dict[i] = 0
    print(z_dict)
    
    # 2. 字典的字典推导式写法
    z_dict2 = {k: 0 for k in zodiac_name}
    print(z_dict2)
    
    

5. 文件和输入输出

5.1 文件的内建函数

  • 定义:python自带的函数,不需要额外去安装
  • 基本的函数
    1. open():打开文件
    2. read():输入
    3. readline():输入一行
    4. seek():文件内移动
    5. write():输出
    6. close():关闭文件
  • 注意
    • 在打开文件之后一定要对文件进行关闭,否则电脑突然关机的话你写入的信息就会丢失。

5.2 文件的常用操作

  • 读取一行:readline()

  • 读取多行:readlines()得到一个列表,列表中每一个元素都是一行的内容

  • 读取整个内容:read()直接得到整个文章的内容,用字符串的形式去存储

  • 读取固定数字符:read(x)x代表读取的字符数量

  • 移动文件读取指针:

    • 单个参数时:seek(x)代表移动到文章第几个字符处,从0开始
    • 两个参数时:seek(a, b) 第一个参数代表偏移位置 第二个参数0表示从文件开头偏移1表示从当前位置偏移2表示从文件结尾
  • 例子:

    # # 将小说的主要人物记录在文件中
    # # file1 = open('name.txt') # 默认以只读的方式打开文件
    # file1 = open('name.txt', 'w')  # 以写入的方式打开文件
    # file1.write('诸葛亮')
    # file1.close()
    #
    # file2 = open('name.txt')
    # print(file2.read())
    # file2.close()
    #
    # file3 = open('name.txt', 'a')  # 如果是以写入的方式打开文件在新写内容时会覆盖,这里用增加的方式进行写入
    # file3.write('刘备')
    
    # file4 = open('name.txt')
    # print(file4.readline()) # 读一行
    #
    # file5 = open('name.txt')
    # # print(file5.readlines()) # 读取多行
    # for line in file5.readlines():
    #     print(line)
    file6 = open('name.txt')
    print('当前文件指针的位置 %s' % (file6.tell()))  # 文件指针在哪个位置
    # print(file6.read())  # 读取所有文件
    print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1))  # 默认是读取所有文件,此处表读取一个字符
    print('当前文件指针的位置 %s' % (file6.tell()))
    file6.seek(2, 0)  # 第一个参数代表偏移位置   第二个参数 0表示从文件开头偏移 1表示从当前位置偏移 2从文件结尾
    print('我们进行了seek操作')
    print('文件指针回到了位置 %s' % (file6.tell()))
    print('当前读取到了一个字符,字符的内容是 %s' % file6.read(1))  # 默认是读取所有文件,此处表读取一个字符
    print('当前文件指针的位置 %s' % (file6.tell()))
    file6.close()
    
    

6. 错误和异常

  • 异常

    • 产生:出现错误时采用正常控制流以外的动作

    • 异常处理的一般流程:

      1. 检测到错误,引发异常
      2. 对异常进行捕获操作
    • 异常处理代码格式:

      try:
          <监控异常>
      except Exception[,reason]:
          <异常处理代码>
      finally:
          <无论异常是否发生都执行>  # 常用于文件关闭
      
      
    • 简单试验:

      # try:
      #     year = int(input('input year:'))
      # except ValueError:
      #     print('年份要输入数字!')
      
      # except (ValueError, AttributeError, KeyError) 捕获多个异常时使用元组将其整合成一个对象
      
      # try:
      #     print(1 / 0)
      # except Exception as e:  # Exception代表所有错误信息
      #     print('0不能做除数 %s' % e)
      
      # 自己定义错误信息
      try:
          raise NameError('helloError')
      except NameError:
          print('my Custom error')
      
      

7. 函数

  • 定义:对程序逻辑进行结构化的一种编程方法

  • 定义格式:

    def 函数名称():
    	代码
    	return 需要返回的内容
    
    
  • 函数的调用:函数名称()

  • 函数传参时使用指定关键字:

    print('abc', end='\n') # end是指定关键字参数,好处是不用按顺序输入参数
        
    def func(a, b, c):
        print('a = %s' %a)
        print('b = %s' %b)
        print('c = %s' %c)
    func(1, 2, 3)
    func(1, c = 2, b = 3) # 指定关键字,不用按顺序输入参数
    
    

7.1 函数的可变长参数

# 取得参数的个数
def howlong(first, *other):
    print(1 + len(other))
howlong(1, 2, 3)

7.2 函数的变量作用域

var1 = 123
def func():
    var1 = 456 # 它的影响范围只是在这个函数内,如果要让它的影响范围变大的话,要加上关键字global,即global var1 
    print(var1) # 输出456
func()
print(var1) # 输出的还是123

7.3 函数的迭代器与生成器

  • iter():用来生成迭代器
  • next():返回迭代器的下一个项目
list1 = [1, 2, 3]
it = iter(list1)
print(next(it))
print(next(it))
print(next(it))
print(next(it))

list2 = ['a', 'b', 'c']
for i in iter(list2):
    print(i)

  • 生成器:使用了yield的函数称为生成器,生成器是迭代器的一种。调用一个生成器函数,返回一个迭代器对象。
# 自己手写一个浮点数range
def frange(start, stop, step): # 使用了yield的函数我们称为生成器,也是迭代器的一种
    x = start
    while x < stop:
        yield x
        x += step
for i in frange(10, 20, 0.5):
    print(i)

7.4 Lambda表达式

  • 使用:在我们仅仅使用函数进行简单计算的时候使用。省去了写return和定义函数名称的过程。
def add(x, y):
    return x + y
lambda x,y: x + y

7.5 Python内建函数

  • filter(func, iterable):将符合指定函数的项给选出来

    a = [1, 2, 3, 4, 5, 6, 7]
    list(filter(lambda x:x>2, a)) # 将符合指定函数的项给取出来
    
    
  • map():对每个元素依次进行操作变变换

    a = [1, 2, 3]
    b = [4, 5, 6]
    list(map(lambda x:x+1, a)) # 对a列表中的每一项进行加一
    list(map(lambda x,y:x+y, a, b))# a列表中的每一项加上b列表中的每一项
    
    
  • reduce():序列的所有项和初始值依次按照函数做运算注意:reduce虽然是内建函数,但是得用from functools import reduce导入

    reduce(lambda x,y: x+y, [2,3,4], 1) # (( 1 + 2 ) + 3 ) + 4
    # 初始值可以省略,当省略时,默认为0
    
    
  • zip():可以使两个元组纵向合并。可以实现字典的key、value对调

    a = (1, 2, 3)
    b = (4, 5, 6)
    tuple(zip(a, b))
    for i in zip(a, b): # zip是一个可迭代的函数,其有一个iter方法
        print(i)
    dicta = {'a':'aaa', 'b':'bbb'}
    dictb = dict(zip(dicta.values(), dicta.keys()))
    dictb
    
    
  • 补充:

    • 可迭代的函数都会有一个iter的方法

7.6 闭包

  • 定义:嵌套的函数,且当外部函数的参数被内部函数给引用的情况下我们称其为闭包。

  • 小示例

    # 使用闭包实现计数器
    def counter(FIRST=0):
        cnt = [FIRST]
        def add_one():
            cnt[0] += 1
            return cnt[0]
        return add_one
    num1 = counter(5)
    num2 = counter(10)
    print(num1())
    print(num1())
    print(num2())
    print(num2())
    
    

    运行结果:

    6

    7

    11

    12

    发现:

    互不影响,这也是闭包的好处。

    # 使用闭包实现线段
    def a_line(a, b):
        def arg_y(x):
            return a * x + b
        return arg_y
    line1 = a_line(3, 5)
    line2 = a_line(10, 5)
    print(line1(5))
    print(line2(5))
    '''
    闭包优雅写法
    def a_line(a, b):
        return lambda x:a*x+b
    '''
    
    
    • 好处:比传统的实现方式传参少,定义函数时只需要传a、b两个参数,使用线段求y时只用传x一个参数。

7.7 装饰器

  • 定义与闭包类似,只不过它传递的参数是一个函数,使用方法经过不断演化后得到了简化。

  • 示例:

    • 粗略计算一下程序的运行时间
    import time
    # 未用装饰器前
    def I_sleep():
        time.sleep(3)
    start_time = time.time()
    I_sleep()
    stop_time = time.time()
    print("程序运行了%s" %(stop_time-start_time))
    
    # 用装饰器后
    def timer(func):
        def wrapper():
            start_time = time.time()
            func()
            stop_time = time.time()
            print("程序运行了%s" %(stop_time-start_time))
        return wrapper
    @timer # 语法糖,修饰I_sleep2
    def I_sleep2():
        time.sleep(3)
    I_sleep2() # 实际上是(timer(I_sleep2))()这么运行的
    
    
  • 带参数的装饰器:

    # 带参数的装饰器
    def out(func):
        def inner(a,b):
            print('start')
            func(a,b)
            print('stop')
        return inner
    @out
    def add(a,b):
        print(a + b)  
    add(7,3) # 实际上可以理解为运行的时候是这样的(out(add))(7,3),所以实际上是inner(7,3)
    
    
  • 针对不同函数装饰器做适应:

    # 带参数的装饰器
    def new(argv):
        def out(func):
            def inner(a,b):
                print('start %s %s' %(argv, func.__name__)) # __name__取传入函数的名字
                func(a,b)
                print('stop')
            return inner
        return out
    @new('add_module')
    def add(a,b):
        print(a + b) 
    @new('sub_module')
    def sub(a,b):
        print(a - b)
    add(3, 5)
    sub(5, 3)
    
    
  • 好处:

    1. 调用函数时不用在上面下面去编写重复的代码,可以将这些代码放在装饰器里面。
    2. 装饰器更易于复用

7.8 自定义上下文管理器

先来看看一般打开文件的方法

fd = open('name.txt')
try:
    for line in fd:
        print(line)
finally:
    fd.close()

上面这种方法是不优雅的

下面我们使用with上下文管理器的方法去精简

with open('name.txt') as f:
    for line in f:
        print(line)

通过这种方法省去了我们写finally,因为在出现异常的时候,它会自动帮我们做关闭的操作。

8. 模块

在代码量变得相当大之后,将需要重复使用的有组织的代码段放在一起组成一个文件,这个文件就是模块。可以附加到现有的程序中。

  • 导入:附加的过程

  • 导入的一般写法:

    import 模块名称 as 别名
    from 模块名称 import 方法名
    
    

9. 面向对象编程

9.1 类与实例

# 传统表示玩家信息的方法
user1 = {'name':'tom','hp':100}
user2 = {'name':'jerry','hp':80}

def print_role(rolename):
    print('name is %s,hp is %s' %(rolename['name'], rolename['hp']))
print_role(user1)
print_role(user2)
# 使用类的方法
class Player():
    def __init__(self, name, hp):
        self.name = name
        self.hp = hp
    def print_role(self): # 定义了一个方法
        print('name is %s,hp is %s' %(self.name, self.hp))
user1 = Player('Tom', 100) # 类的实例化
user2 = Player('Jerry', 80)
user1.print_role()
user2.print_role()

9.2 增加类的属性和方法

# 使用类的方法
class Player():
    def __init__(self, name, hp, occu):
        self.__name = name # 变量被称作属性
        self.hp = hp
        self.occu = occu
    def print_role(self): # 定义了一个方法(函数被称作方法)
        print('name is %s,hp is %s,occupation is %s' %(self.__name, self.hp, self.occu))
    def updateName(self, newname):
        self.__name = newname
user1 = Player('Tom', 100, 'war') # 类的实例化
user2 = Player('Jerry', 80, 'master')
user1.print_role()
user2.print_role()

user1.updateName('wilson')
user1.print_role()

其中name默认是公有成员,也可以通过实例.name的方式去访问和更改。

如果想使得name不能使用.name 的方式去访问和更改,可以在其类中使用__name

9.3 类的继承

class Monster():
    # 定义怪物类
    pass # 告知系统我们定义了一个Monster,但是现在我们还不想去实现它
class Animals(Monster): # 继承自Monster类
    # 普通怪物
    pass
class Boss(Monster):
    # Boss类怪物
    pass
# version 2
class Monster():
    # 定义怪物类
    def __init__(self, hp = 100):
        self.hp = hp
    def run(self):
        print('移动到某个位置')
    def whoami(self):
        print('我是怪物父类')
class Animals(Monster): # 继承自Monster类
    # 普通怪物
    def __init__(self, hp = 10):
        super().__init__(hp)
        
class Boss(Monster):
    # Boss类怪物
    def __init__(self, hp=800):
        super().__init__(hp)
    def whoami(self): # 有重名的方法,使用时会覆盖父类的方法
        print('我是Boss')
a1 = Monster(200)
a1.run()
print(a1.hp)

a2 = Animals(100)
a2.run()
print(a2.hp)

a3 = Boss(1000)
a3.whoami()

print('a1的类型 %s' %type(a1))
print('a2的类型 %s' %type(a2))
print('a3的类型 %s' %type(a3))

print(isinstance(a2, Monster)) # 判断对象是否是一个已知类型

9.4 自定义with语句

class Testwith():
    def __enter__(self):
        print('run')
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')
with Testwith():
    print('test is running')

运行结果:

run

test is running

exit

class Testwith():
    def __enter__(self):
        print('run')
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_tb is None: # 没有异常它的值就是None
            print('正常结束')
        else:
            print('has error %s' %exc_tb)
with Testwith():
    print('test is running')
    raise NameError('testNameError') # 手动抛出异常

10. 多线程编程

  • 定义:同时处理多个请求的方法

  • 线程的简单使用:

    import threading
    import time
    from threading import current_thread
    def myThread(arg1, arg2):
        # print(current_thread().getName(),'start')
        time.sleep(1)
        print('%s %s' %(arg1, arg2))
        # print(current_thread().getName(),'stop')
    for i in range(1, 6, 1):
        t1 = threading.Thread(target=myThread,args=(i, i + 1))
        t1.start()
    
    
  • 让主线程等待其他线程结束之后再结束

    import threading
    from threading import current_thread
    class Mythread(threading.Thread):
        def run(self):
            print(current_thread().getName(), 'start')
            print('run')
            print(current_thread().getName(), 'stop')
    t1 = Mythread()
    t1.start() # 线程使用start启动的时候实际上是调用了run方法
    t1.join() # 等待t1线程结束才会向下执行
    
    print(current_thread().getName(), 'end')
    
    
    
  • 生产者和消费者:

    from threading import Thread,current_thread
    import time
    import random
    from queue import Queue
    
    queue = Queue(5) # 定义队列的长度
    class ProducerThread(Thread):
        def run(self):
            name = current_thread().getName() # 获取线程的名字
            nums = range(100)
            global queue
            while True:
                num = random.choice(nums)
                queue.put(num)
                print('生产者 %s 生产了数据 %s' %(name, num))
                t = random.randint(1, 3)
                time.sleep(t)
                print('生产者 %s 睡眠了 %s 秒' %(name, t))
    class ConsumerThread(Thread):
        def run(self):
            name = current_thread().getName()
            global queue
            while True:
                num = queue.get()
                queue.task_done() # 封装好了关于线程等待和线程同步的代码
                print('消费者 %s 消耗了数据 %s' %(name, num))
                t = random.randint(1, 5)
                time.sleep(t)
                print('消费者 %s 睡眠了 %s 秒' %(name, t))
    p1 = ProducerThread(name = 'p1')
    p1.start()
    p2 = ProducerThread(name = 'p2')
    p2.start()
    p3 = ProducerThread(name = 'p3')
    p3.start()
    c1 = ConsumerThread(name = 'c1')
    c1.start()
    c2 = ConsumerThread(name = 'c2')
    c2.start()          
    
    

11. 标准库

  • 定义:安装python后自带的库
  • 目前比较广泛的模块
    1. 文字处理的re
    2. 日期类型的time、datetime
    3. 数字和数学类型的math、random
    4. 文件和目录访问的pathlib、os.path
    5. 数据压缩和归档的tarfile
    6. 通用操作系统的os、logging、argparse
    7. 多线程的threading、queue
    8. Internet数据处理的base64、json、urllib
    9. 结构化标记处理工具的html、xml
    10. 开发工具的unitest
    11. 调试工具的timeit
    12. 软件包发布的venv
    13. 运行服务的__main__

11.1 正则表达式库re的使用

  • 导入import re

  • 单个字符的匹配:

    import re
    p = re.compile('a')
    print(p.match('a'))
    print(p.match('b'))
    
    

    运行结果:

    <re.Match object; span=(0, 1), match='a'> # 匹配到的位置
    None # 匹配失败
    
    
  • 正则表达式元字符:

    • .匹配任意一个字符除换行符
    • \d匹配任意一个数字
    • 更多
  • 匹配日期:

    p = re.compile(r'(\d+)-(\d+)-(\d+)') # r是告知python字符串中的特殊符号不要进行转义
    print(p.match('2022-05-05').group()) # 获取匹配到的内容
    print(p.match('2022-05-07').group(1)) # 获取年
    print(p.match('2022-05-07').groups()) # 获取年月日,用元组去存
    year,month,day = ('2022', '05', '07')
    
    
  • 正则表达式match与search的区别

    • match要求原字符和输入字符完全匹配。即当第一个字符与原字符不匹配时便返回匹配失败。
    • search不会,它会沿输入字符继续向后进行匹配。
    • match经常是用于完全匹配之后进行分组。
  • 正则表达式库替换函数sub

    • sub(str1, str2, str3):

      • str1:匹配的规则
      • str2:匹配到的字符串要替换成的内容
      • str3:将要替换的字符串
    • 使用:

      # 删去电话号码结尾不合法部分
      phone = '123-456-789 # 这是一个电话号码'
      p = re.sub(r'#.*$', '', phone)
      print(p)
      # 删去-
      p2 = re.sub(r'\D','',p)
      print(p2)
      
      

      运行结果:

      123-456-789

      123456789

  • 补充:

    • search只能匹配一次,想要匹配多次要用findall

11.2 日期与时间函数库

  • 时间库:

    • 引入import time

    • 函数:

      • time():从1970年1月1日到现在经历了多少秒
      • localtime([sec]):格式化时间戳为本地的时间
      • strftime(str):返回str格式的当前时间
    • 使用:

      import time
      print(time.time()) # 查19700101到现在过了多少秒
      print(time.localtime())
      print(time.strftime('%Y%m%d'))
      
      
  • 以当前时间为准,计算指定偏移后的时间

    import datetime
    print(datetime.datetime.now())
    newtime = datetime.timedelta(minutes = 10) # 计算十分钟偏移量
    print(datetime.datetime.now() + newtime) # 显示十分钟后的时间
    
    one_day = datetime.datetime(2008,5,27)
    new_date = datetime.timedelta(days = 10)
    print(one_day + new_date)
    
    

11.2 数学相关库

  • math

  • random

    • randint():返回指定区间的随机数
    • choice(obj):从对象中任选一值
    import random
    print(random.randint(1, 5))
    print(random.choice([1, 2, 'a', 'b']))
    
    

11.3 文件与目录操作库

  • os.path

    • 引入:import os或者from os import path

    • 使用:

      from os import path
      print(path.abspath('..')) # 根据相对路径.获得绝对路径v
      print(path.exists('./01 hello_world.py')) # 判断文件是否存在
      print(path.isfile('./01 hello_world.py')) # 判断是否是文件
      print(path.isdir('./01 hello_world.py')) # 判断是否是目录
      print(path.isdir('.'))
      print(path.join('/tmp/','01 hello_world.py')) # 路径拼接
      
      
  • pathlib

    • 引入:from pathlib import Path

    • 使用:

      from pathlib import Path
      p = Path('.')
      print(p.resolve()) # 根据相对路径获得绝对路径,跟我们的path.abspath()一样
      print(p.is_dir()) # 判断当前位置是否是目录
      q = Path('./a/b/c')
      Path.mkdir(q, parents=True) # parents=True是当父级目录不存在时会创建父级目录
      
      
  • 特点:两者大多数功能类似,但pathlib好的是可以创建目录。

12. 机器学习库

12.1 Numpy库

  • 用途:主要用于高性能科学计算和数据分析,是常用的高级数据分析库的基础包。

  • 简单使用

    import numpy as np
    arr1 = np.array([2, 3, 4])
    print(arr1)
    print(arr1.dtype)
    
    arr2 = np.array([2.1, 3.1, 4.1])
    print(arr2)
    print(arr2.dtype)
    print(arr1 + arr2)
    
    # Numpy数组和标量的计算
    print(arr2 * 10)
    data = [[1,2,3], [4,5,6]]
    arr3 = np.array(data) # 将列表转为二维矩阵
    print(arr3)
    print(arr3.dtype)
    print(type(arr3))
    
    print(np.zeros(10)) # 定义了一个一维的长度为10的数组,这个数组的所有值都是0
    print(np.zeros((3, 5))) # 定义一个3x5的矩阵,这个矩阵的所有值为0
    print(np.ones((4, 6))) # 定义一个4x6的矩阵,初始值都为1
    print(np.empty((2,3,2))) # 定义了一个三维矩阵,初始值为随机值
    
    # Numpy数组的索引和切片
    arr4 = np.arange(10)
    print(arr4[5])
    print(arr4[5:8])
    arr4[5:8] = 0
    print(arr4)
    arr_slice = arr4[5:8]
    arr_slice[:] = 1 # 由于python这里是引用,故而这么做会影响到arr4的内容
    print(arr4)
    arr_slice = arr4[5:8].copy()
    arr_slice[:] = 0 # 这样子做操作不会影响arr4,因为它是arr4的一个副本
    print(arr4)
    print(arr_slice)
    arr5 = np.array(['a', 'b', 'c', 'd'])
    print(arr5[1]) # 下标从0开始计算
    
    

12.2 Pandas库

  • 好处(相比于Numpy):

    • 自动帮你将数据对齐显示
    • 可以灵活的处理缺失的数据、
    • 还可以实现像类似sql语句一样的连接操作
  • 特点

    • 会帮我们自动添加索引
    • 键值可以不唯一
  • 简单使用

    import pandas as pd
    obj = pd.Series([4, 5, 6, -7])
    print(obj)
    
    print(obj.index) # 打印索引
    print(obj.values) # 打印值
    
    obj2 = pd.Series([4, 5, 6, 3], index = {'a', 'b', 'd', 'c'})
    print(obj2)
    obj2['c'] = 6
    print(obj2)
    print('c' in obj2) # 判断是否存在键'c'
    print('f' in obj2)
    
    # 将字典转化到我们的series中
    sdata = {'beijing' : 35000, 'shanghai' : 70000, 'guangzhou' : 16000, 'shenzhen' : 5000}
    obj3 = pd.Series(sdata)
    print(obj3)
    obj3.index = ['bj', 'sh', 'gz', 'sz'] # 修改索引为它们的缩写
    print(obj3)
    
    # 将字典转化到我们的dataframe中
    data = {'city' : ['shanghai', 'guangzhou', 'beijing', 'shenzhen'],
            'year' : [2016, 2017, 2018, 2019],
            'pop' : [1.5, 1.8, 1.3, 2.0]}
    frame = pd.DataFrame(data)
    print(frame)
    
    frame2 = pd.DataFrame(data, columns = ['year', 'city', 'pop']) # 调换列的顺序
    print(frame2)
    
    # 将二维表格转换为一维的数据
    print(frame2['city'])
    print(frame2.year)
    
    # 为pandas增加一个新的列
    frame2['cap'] = frame2.city == 'beijing'
    print(frame2)
    # 求转置
    pop = { 'beijing' : {2008:1.5, 2009:2.0},
            'shanghai' : {2008:2.0, 2009:3.6}
           }
    frame3 = pd.DataFrame(pop)
    print(frame3)
    # 行和列的转换
    print(frame3.T)
    
    obj4 = pd.Series([4.5, 7.2, -5.3, 3.6], index = ['b', 'd', 'c', 'a'])
    obj5 = obj4.reindex(['a', 'b', 'c', 'd', 'e']) # 按索引顺序排序,不存在的索引将出现空值
    print(obj5)
    
    obj6 = obj4.reindex(['a', 'b', 'c', 'd', 'e'], fill_value = 0) # 给空值填充0
    print(obj6)
    
    obj7 = pd.Series(['blue', 'yellow', 'pink'], index = [0, 2, 4])
    print(obj7.reindex(range(6)))
    print(obj7.reindex(range(6), method = 'ffill')) # 空值填充为其前一个数值
    
    from numpy import nan as NA
    # 删除缺失值的一行数据
    data = pd.Series([1, NA, 2])
    print(data.dropna())
    
    # 在DataFrame删除缺失值的情况
    # 1. 某一列的某一行有缺失
    data = pd.DataFrame([[1.,  6.5, 3], [1., NA, NA], [NA, NA, NA]])
    data[4] = NA
    print(data)
    print(data.dropna()) # 发现只要出现了na的一行就会被全部删掉
    print(data.dropna(how = 'all')) # 只删掉全部出现na的一行
    # 2. 某一列的某一列有缺失
    print(data.dropna(axis = 1, how = 'all')) # 删掉全部出现na的一列
    data.fillna(0) # 这种方法是对data副本进行填充0,并返回,并不会直接修改data
    data.fillna(0, inplace = True) # 使用了inplace参数则代表是对data进行填充修改
    print(data)
    # 层次化索引
    import numpy as np
    data3 = pd.Series(np.random.randn(10),
                   index = [['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'd', 'd'],
                            [1, 2, 3, 1, 2, 3, 1, 2, 2, 3]])
    # 层次化索引的用途
    print(data3)
    print(data3.unstack()) # 将一维数据转化为二维数据
    print(data3.unstack().stack()) # 再转换回来
    
    

12.3 Matplotlib库

  • 用途:绘图

  • 简单使用

    import matplotlib.pyplot as plt
    
    # 绘制简单的曲线
    plt.plot([1, 3, 5], [4, 8, 10])
    plt.show()
    
    import numpy as np
    x =  np.linspace(-np.pi, np.pi, 100) # x轴的定义域为-3.14·3.14,中间间隔100个元素
    print(x)
    plt.plot(x, np.sin(x))
    # 显示所画的图
    plt.show()
    
    x = np.linspace(-np.pi * 2, np.pi * 2, 100)
    plt.figure(1, dpi = 50) # 创建图表,dpi代表精度,精度越高,画的图就越大就越清晰
    for i in range(1, 5): # 画四条线
        plt.plot(x, np.sin(x / i))
    plt.show()
    
    plt.figure(1, dpi = 50) # 创建图表1,dpi代表图片精细度,dpi越大文件越大,杂志要300以上
    data = [1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 5, 6, 4]
    plt.hist(data) # 只要传入数据,直方图就会统计数据出现的次数
    plt.show()
    
    x = np.arange(1, 10)
    y = x
    fig = plt.figure()
    plt.scatter(x, y, c = 'r', marker = 'o') # c = 'r' 表示散点的颜色为红色,marker表示指定三点多边形为圆形
    plt.show()
    
    import pandas as pd
    iris = pd.read_csv('./iris_training.csv')
    print(iris.head())
    # 绘制散点图
    iris.plot(kind = 'scatter', x = '120', y = '4')
    
    # 没啥用,只是让pandas的plot方法显示
    plt.show()
    
    # 使用seaborn来绘制图
    import seaborn as sns
    import warnings 
    warnings.filterwarnings('ignore')
    iris = pd.read_csv('./iris_training.csv')
    # 设置样式
    sns.set(style = 'white', color_codes = True)
    # 设置绘制格式为散点图
    # sns.jointplot(x = '120', y = '4', data = iris, size = 5)
    # distplot绘制曲线
    # sns.distplot(iris['120'])
    sns.FacetGrid(iris, hue = 'virginica', size = 5).map(plt.scatter, '120', '4').add_legend() # 按virginica属性分类,给点分配不同颜色
    sns.FacetGrid(iris, hue = 'virginica', size = 5).map(plt.scatter, 'setosa', 'versicolor').add_legend()
    
    

13. 爬虫

13.1 网页数据采集与urllib库

  • 网络库

    • urllib库:http协议常用库
    • requests库:http协议常用库
    • BeautifulSoup库:xml格式处理库

    urlib跟requests库都是用于收集数据的库,BeautifulSoup是用于数据处理的库

  • urlib库

    • 使用:from urllib import request

    • 例子:

      from urllib import request
      
      url = 'http://www.baidu.com'
      response = request.urlopen(url, timeout = 1)
      print(response.read().decode('utf-8')) # read直接读是按照单个字节解释出来的,而中文往往要占多个字节,所以要用decode做编码解析
      
      
    • 专门用于测试get和post请求的网页:http://www.httpbin.org/

    • 发送get请求:

      • 注意:使用urlopen的时候一般都要指定timeout,不然一旦请求超时程序会卡死
      from urllib import request
      response = request.urlopen('http://httpbin.org/get', timeout=1) 
      print(response.read())
      
      # 超时异常捕获处理
      import urllib
      import socket
      try:
          response3 = request.urlopen('http://httpbin.org/get', timeout=0.1)
      except urllib.error.URLError as e:
          if isinstance(e.reason, socket.timeout):
              print('TIME OUT')
      
      
    • 发送post请求:

      from urllib import parse # 处理post数据
      from urllib import request
      data = bytes(parse.urlencode({'word':'hello'}), encoding='utf8')
      # print(data)
      response2 = request.urlopen('http://httpbin.org/post', data=data)
      print(response2.read().decode('utf-8'))
      
      
    • HTTP头部信息的模拟:

      from urllib import parse # 处理post数据
      from urllib import request
      headers = {
          "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
          "Accept-Encoding": "gzip, deflate",
          "Accept-Language": "zh-CN,zh;q=0.9",
          "Host": "httpbin.org",
          "Upgrade-Insecure-Requests": "1",
          "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
          "X-Amzn-Trace-Id": "Root=1-627a1828-401ed66a579dbc0173b7ee85"
      }
      dict = {
          'name' : 'value'
      }
      data = bytes(parse.urlencode(dict), encoding = 'utf8')
      req = request.Request(url = 'http://httpbin.org/post', data = data, headers = headers, method = 'POST')
      response = request.urlopen(req)
      print(response.read().decode('utf-8'))
      
      

13.2 requests库的基本使用

  • 使用import requests

  • get请求

    import requests
    url = 'http://httpbin.org/get'
    data = {'key': 'value'}
    response = requests.get(url, data)
    print(response.text)
    
    
  • post请求

    import requests
    url = 'http://httpbin.org/post'
    data = {'key' : 'value'}
    response = requests.post(url, data)
    print(response.text) # 返回类型转为为json格式 response.json()
    
    
  • 爬虫小栗子

    import requests
    import re
    
    content = requests.get('http://www.mnw.cn/news/china/')
    content.encoding = 'utf8'
    # print(content.text)
    pattern = re.compile(r'<div class="item  noimg.*?<a.*?>(.*?)</a>', re.S)
    results = re.findall(pattern, content.text)
    # print(results)
    
    for result in results:
        print(re.sub('\s', '', result)) # 去除空白符
    
    
  • re.S的作用

    不使用re.S时,则只在每一行内进行匹配,如果存在一行没有,就换下一行重新开始,使用re.S参数以后,正则表达式会将这个字符串看做整体,在整体中进行匹配 。

13.3 BeautifulSoup库的基本使用

  • 作用:处理请求得到的html文本,一般情况下比使用正则更容易处理得到想要内容

  • 简单使用

    html_doc = """
    <html><head><title>网页标题</title></head><body>
    <p class= "item2">这是一个段落</p>
    <p class="item" id="first">这是第二个段落</p>
    <a href="http://baidu.com">百度一下</a>
    </body></html>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html_doc, 'lxml')
    print(soup.prettify()) # 格式化显示
    
    # 找到title标签
    print(soup.title)
    # 找到title标签里面的内容
    print(soup.title.string)
    
    # 找到第一个p标签
    print(soup.p)
    
    # 找到第一个p标签里面的内容
    print(soup.p.string)
    # 找到第一个p标签里面class的名字
    print(soup.p['class'])
    # 找到所有p标签
    print(soup.find_all('p'))
    # 找到id为first的标签
    print(soup.find(id='first'))
    # 找到所有a标签的链接
    for link in soup.find_all('a'):
        print(link.get('href'))
    
    
  • 爬取百度新闻

    from bs4 import BeautifulSoup  # 编码解码库
    import requests # 请求访问库
    
    # 用 dict 定义http头,伪装浏览器访问,避免被拒之门外
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36 LBBROWSER"
    }
    
    #目标网址为 百度新闻
    url = "http://news.baidu.com"
    
    
    # 创建函数,传入 URL 获取新闻标题 和对应链接
    
    def craw2(url):
        response = requests.get(url, headers=headers) # 获取 指定 URL 内容, 头部用 headers ,把这个动作 赋予给 response
        soup = BeautifulSoup(response.text, "lxml") # 用 BeautifulSoup 把 response 正文内容,用lxml 格式 整理,并赋值给Soup
        # print(soup)   #尝试打印, 能否获取内容
    
        # 把 soup 里面 ,class= mod-tab-pane active 的 <div> 标签,全部找出来,并 逐一赋值 给 title_href
        for title_href in soup.find_all("div", class_="mod-tab-pane active"):
            for title in title_href.find_all("a"):  # 然后把 title_href里的 <a> 标签 全部找出来,并逐一赋值给 title
                title_url=title.get("href") #在title 中,找出href 的值,并赋予给 title——url
                print(title.text,title_url)     #输出 标题和对应链接
    craw2(url)
    
    
  • 爬取图片网站的图片

    import os # 引入目录操作相关库
    import shutil 
    # 用 dict 定义http头,伪装浏览器访问,避免被拒之门外
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
    }
    url = "http://www.netbian.com/"
    def download_jpg(image_url, image_localpath):
        response = requests.get(image_url, stream = True)
        if response.status_code == 200: # 图片存在
            with open(image_localpath, 'wb') as f: # 打开本地路径
                response.raw.deconde_content = True
                shutil.copyfileobj(response.raw, f)
    
    # 获取图片
    def craw3(url):
        response = requests.get(url, headers=headers) 
        soup = BeautifulSoup(response.text, 'lxml')
        # print(soup.prettify())
        for div in soup.find_all('div', class_="list"):
            for img in div.find_all('img'):
                imgurl = img.get('src')
                dir = os.path.abspath('./爬取的图片/')
                filename = os.path.basename(imgurl) # 自动帮我们把https://th.wallhaven.cc/small/k7/k7v9yq.jpg前面的目录路径给去掉剩余k7v9yq.jpg
                imgpath = os.path.join(dir, filename)
                print('开始下载 %s' % imgurl)
                download_jpg(imgurl, imgpath)
    
    craw3(url)
    
    

14. 设计合理的代码结构

  • 如果使用的功能不需要调用库的话,尽量不要去调用库
  • 在编写大型程序时,优先把逻辑编写出来,具体实现封装到函数当中
  • 程序带有的功能建议单独写到一个模块中

知识点

  • 序列包含列表、元组、字符串,sort() 函数是列表的方法。
  • 元组和列表的删除都可以使用del()关键字
  • 语法错误跟finally中遇到文件打开失败都会引发异常
  • 不可变类型可以作为字典的key
  • python中类的父类可以有多个
  • queue库是线程安全的
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

零基础学Python学习笔记 的相关文章

随机推荐

  • Zookeeper入门之分布式集群的搭建(二)

    Zookeeper入门之分布式集群的搭建 xff08 一 xff09 Hadoop3 2 2完全分布式集群环境搭建 xff08 二 xff09 Zookeeper入门之分布式集群的搭建 xff08 三 xff09 HBase分布式集群的搭建
  • HBase分布式集群的搭建(三)

    HBase分布式集群的搭建 xff08 一 xff09 Hadoop3 2 2完全分布式集群环境搭建 xff08 二 xff09 Zookeeper入门之分布式集群的搭建 xff08 三 xff09 HBase分布式集群的搭建 安装 准备工
  • springboot集成swagger3.0

    Swagger3 0 最新版使用 Swagger 最新版的配置步骤和旧版本是一样 xff0c 只是每个具体的配置项又略有不同 xff0c 具体步骤如下 1 添加依赖 span class token comment lt https mvn
  • Windows/IDEA 常用快捷键

    windows 搜索的快捷键 ctr 43 F 切换窗口 win 43 1 2 3 根据任务栏切换 win 43 tab 显示图标 alt 43 esc 切换到上一个 最小化当前窗口 ctr 43 ESC 最小化所有窗口 CTR 43 D
  • windows mysql8.0.26的安装

    mysql8 0 26的安装 1 下载 https dev mysql com downloads mysql 2 解压并在mysql中的bin目录下创建my ini配置文件 mysqld 设置3306端口 port 61 3306 设置m
  • Linux(Debian,Centos,Ubuntu等) gcc的安装

    Linux gcc的安装 xff08 一 xff09 准备工作 1 什么是gcc xff1f GNU编译器集合 xff08 GCC xff09 是一个开源的编译器和库集合 xff0c 支持C xff0c C 43 43 xff0c Obje
  • nodeJs开发app.js解析

    在 node js 中模块分为核心模块和文件模块两种 xff0c 核心模块是通过 require 39 xxxx 39 导入的 xff0c 文件模块是以 require 39 xxxx 39 或 require 39 xxxx 39 req
  • Linux 安装最新版Redis(超简单详细)

    Redis最新版的安装 可以从官网下载 xff0c 然后传输到你的GUN linux中 xff0c 也可像下面那样用wget命令下载 xff0c 下载完后安装步骤基本一样 xff08 一 xff09 安装 1 下载 span class t
  • git:OpenSSL SSL_read: Connection was reset, errno 10054

    方式一 xff1a 可能为网络不稳定 xff0c 连接超时导致的 xff0c 可再次尝试提交 span class token function git span push 方式二 xff1a 打开Git命令页面 xff0c 执行git命令
  • springcloud nacos config快速入门

    nacos config 1 为什么需要配置中心 xff1f 传统配置的方式已经暴露出了很多问题 xff0c 其他的诸如 xff1a 历史版本管理 xff0c 权限控制 xff0c 安全性等等问题 xff0c 是传统的配置文件无法解决的 x
  • 左移运算符和右移运算符的使用

    先简单介绍一下 xff0c 左移运算符和右移运算符的功能 xff1a 计算机中的数字是以二进制补码的形式存放的 xff0c 而左移和右移运算符就是将内存中的二进制补码数字向左或者右移动 左移的结果 xff1a 1 左移会让最高位溢出 xff
  • 51单片机对直流电机的控制

    占空比 61 周期内高电平持续的时间 整个周期 直流电机驱动芯片选择L293D 电机正转 xff1a span class token macro property span class token directive hash span
  • C++结构体数组 | 结构体数组的使用

    C 43 43 结构体数组 C 43 43 结构体数组与以前介绍过的数值型数组的不同之处在于 xff1a 每个数组元素都是一个结构体类 型的数据 xff0c 它们都分别包括各个成员项 C 43 43 结构体数组定义 C 43 43 结构体数
  • 小程序开发学习(4)---天气预报接口API篇

    文章目录 1 实现用户定位API2 获取定位信息 1 实现用户定位API 天气预报API大多数都是需要收费的 xff0c 但是在现在学习阶段可以不需要购买收费的 xff0c 网上能找到免费的天气预报API地址 xff0c 但是可能不是很好找
  • SPSS的入门

    1 SPSS的起源 SPSS xff08 全称 xff1a Statistical Product and Service Solutions xff09 是世界上最早的统计分析软件 xff0c 由美国斯坦福大学的三位研究生Norman H
  • MySQL 1130错误,无法远程连接

    错误 xff1a ERROR 1130 Host 39 192 168 1 3 39 is not allowed to connect to thisMySQL serve 错误1130 xff1a 主机192 168 1 3 不允许连接
  • 【STM32f10】MDK编译报错:Undefined symbol TIM3_PWM_Init (referred from main.o)

    MDK编译报错 xff1a Undefined symbol TIM3 PWM Init referred from main o 一 问题出现 最近跟着正点原子学到了STM32的PWM内容 xff0c 运行了该内容的程序时 xff0c 发
  • 【记录】ssh连接wsl Debian过程

    参考 xff1a 使用ssh连接WSL 学亮编程手记的博客 CSDN博客 https blog csdn net a772304419 article details 119817163 ops request misc 61 amp re
  • 【项目实战15】k8s(1)—k8s的部署(图文详解安装,集群部署过程)

    kubernetes的部署 一 前言一 简介二 k8s特点 二 安装一 安装地址二 配置环境三 安装过程 三 初始化集群 一 前言 一 简介 为方便docker的管理 xff0c Kubernetes对计算资源进行了更高层次的抽象 xff0
  • 零基础学Python学习笔记

    Python学习笔记 代码下载地址 链接 xff1a https pan baidu com s 1yGnpfq4ZHeKpt4V0J PTSg 提取码 xff1a hmzs 1 Python 基础语法 1 1 基本数据类型 整数 int