美文网首页python web
第3天,Python字符编码/文件操作/函数

第3天,Python字符编码/文件操作/函数

作者: CaiGuangyin | 来源:发表于2017-05-17 01:37 被阅读57次

    一、字符编码

    1、字符编码发展史

    • 阶段一:现代计算机起源于美国,最早诞生的也是基于英文考虑的ASCII码;

      ASCII:一个bytes代表一个字符(英文字符/键盘上的所有其他字符),1bytes = 8bit,8个bit位可以产生2**8 = 256种变化,即可以表示256个字符。

    • 阶段二:为了满足中文,中国人定制了GBK编码

      GBK:2bytes表示一个字符;
      其他国家也纷纷定制自己的编码,如日本把日文编到shift_JIS里,韩国把韩文编到Euc-kr里

    • 阶段三:各国都有各自的编码标准,就会不可避免地出现冲突,结果就是在多语言混合的文本中,显示出来就会乱码。

      • 于是产生了unicode,统一用2bytes代表一个字符,2bytes = 16bit ,16个bit位可以产生2**16 = 65536种变化,可以表示65536个字符,然后将全世界各国的文字符号全都包含在内,因而兼容万国文字语言。
      • 但对于英文文本来说,这种编码方式就会多出一倍的存储空间,为了解决这个问题,于是又产生了UTF-8,它是对unicode的压缩优化,英文字符只占用1bytes,中文字符占用3bytes。
    • 注意:需要强调一点;

    • unicode:简单粗暴,所有字符都占2bytes,优点是字符 ---> 二进制表示 转换速度快,缺点是占用空间大
    • utf-8:精准,对不同的字符用不同的长度表示,优点是节省空间,缺点是:字符 ---> 二进制表示 转换速度慢,因为每次都需要计算出字符需要多长的bytes才能够准确表示
    • 内存中使用的编码是unicode,用空间换时间(程序都需要加载到内存中才能运行,因为内存应该是尽可能保证快)
    • 硬盘中或者网络传输用utf-8,网络 I/O 或磁盘 I/O 远大于utf-8的转换延迟,而且 I/O 应该是飞可能地节省带宽,保证数据传输的稳定性。

    注:所有程序,最终都要加载到内存,程序保存到硬盘,不同的国家用不同的编码格式,但是到内存中我们为了兼容万国(计算机可以运行任何国家的程序原因在于此),统一且固定使用unicode,这就是为何内存固定用unicode的原因,你可能会说兼容万国我可以用utf-8啊,可以,完全可以正常工作,之所以不用肯定是unicode比utf-8更高效啊(uicode固定用2个字节编码,utf-8则需要计算),但是unicode更浪费空间,没错,这就是用空间换时间的一种做法,而存放到硬盘,或者网络传输,都需要把unicode转成utf-8,因为数据的传输,追求的是稳定,高效,数据量越小数据传输就越靠谱,于是都转成utf-8格式的,而不是unicode。

    2、字符编码的使用

    无论是何种编辑器,要防止文件出现乱码(请一定注意,存放一段代码的文件也仅仅只是一个普通文件而已,此处指的是文件没有执行前,我们打开文件时出现的乱码)

    核心法则就是,文件以什么编码保存的,就以什么编码方式打开

    Paste_Image.png

    2.1 程序的执行

    python test.py (执行程序,一定是先将文件内容加载到内存中)

    步骤一:启动python解释器
    步骤二:python解释器此时就是一个文本编辑器,负责打开文件test.py,即从硬盘中读取test.py的内容到内存中。

    此时,python解释器会读取test.py的第一行内容,# -*-coding:utf-8 -*-,来决定以什么编码格式来读入内存,这一行就是来设定python解释器这个软件的编码使用的编码格式,这个编码可以用sys.getdefaultencoding()查看,如果不在python文件指定头信息#-*-coding:utf-8-*-,那就使用默认的python2中默认使用ascii,python3中默认使用utf-8。

    错误:

    错误

    正确:

    正确

    步骤三:读取已经加载到内存的代码(unicode编码的二进制),然后执行,执行过程中可能会开辟新的内存空间,比如 name = Alex

    • 内存的编码使用unicode,不代表内存中全都是unicode编码的二进制;
    • 在程序执行之前,内存中确实都是unicode编码的二进制,比如从文件中读取了一行name = Alex,其中“name”、“=”、引号,地位都一样,都是普通字符而已,都是 unicode编码的二进制形式存放在内存中的;
    • 但是程序在执行过程中,会申请内存(与程序代码所存在的内存是两个空间),可以存放任意编码格式的数据,比如name = Alex会被python解释器识别为字符串,会申请内存空间来存放“Hello”,然后让“name”指向该内存地址,此时新申请的该内存地址保存的也是unicode编码的“Alex”,如果代码换成name = "Alex".encode('utf-8'),那么新申请的内存空间里存放的就是utf-8编码的字符串“Alex”了。

    针对python3 如下图:

    Paste_Image.png

    浏览网页的时候,服务器会把动态生成的unicode内容转换为utf-8再传输到浏览器:

    Paste_Image.png

    如果服务器端encode的编码格式是utf-8,客户端内存中收到的也是utf-8编码的二进制。

    2.2、Python2与Python3的区别

    在Python2中有两种字符串类型:str 和 unicode

    str类型:当Python解释器执行到产生字符串的代码时(例如:s = "林"),会申请新的内存地址,然后将“林” encode成文件开头指定的编码格式,这已经是encode之后的结果,所以 s 只能decode,所以很重要的一点是:在Python2中,str 就是编码后的结果bytes,str = bytes,所以在Python2中,unicode字符编码结果就 str/bytes

    #coding:utf-8
    s='林' #在执行时,'林'会被以conding:utf-8的形式保存到新的内存空间中
    
    print repr(s) #'\xe6\x9e\x97' 三个Bytes,证明确实是utf-8
    print type(s) #<type 'str'>
    
    s.decode('utf-8')
    # s.encode('utf-8') #报错,s为编码后的结果bytes,所以只能decode
    

    unicode类型:当Python解释器执行到产生字符串的代码时(例如:s = u"林"),会申请新的内存地址,然后将”林“以unicode的格式存放到新的内存空间,所以 s 只能encode,不能decode 。

    s=u'林'
    print repr(s) #u'\u6797'
    print type(s) #<type 'unicode'>
    
    
    # s.decode('utf-8') #报错,s为unicode,所以只能encode
    s.encode('utf-8')
    

    打印到终端:对于print需要特别说明的是:当程序执行时,比如name = '蔡'print(name) #这一步是将name指向的那块新的内存空间(非代码所在的内存空间)中的内容,打印到终端,而终端仍然是运行于内存中的,所以这打印可以理解为从一块内存打印到另一块内存,unicode --> unicode 。

    对于unicode格式的数据来说,无论怎么打印,都不会乱码。

    Python3中的字符串与Python2中的 u"字符串” 一样,都是unicode,所以无论如何打印都不会乱码。

    在pycharm中,

    Paste_Image.png

    在windows终端

    Paste_Image.png

    但是在python2中存在另外一种非unicode的字符串,此时,print x,会按照终端的编码执行x.decode('终端编码'),变成unicode后,再打印,此时终端编码若与文件开头指定的编码不一致,乱码就产生了

    在pycharm中(终端编码为utf-8,文件编码为utf-8,不会乱码)

    Paste_Image.png

    在windows终端(终端编码为gbk,文件编码为utf-8,乱码产生)

    Paste_Image.png

    验证:
    分别验证在pycharm(默认是utf-8)中和cmd(默认是gbk)下述的打印结果:

    #coding:utf-8
    s=u'林' #当程序执行时,'林'会被以unicode形式保存新的内存空间中
    
    
    #s指向的是unicode,因而可以编码成任意格式,都不会报encode错误
    s1=s.encode('utf-8')
    s2=s.encode('gbk')
    print s1 #打印正常否?#在pycharm打印正,cmd中打印会乱码
    print s2 #打印正常否,正好与上面相反
    
    
    print repr(s) #u'\u6797'
    print repr(s1) #'\xe6\x9e\x97' 编码一个汉字utf-8用3Bytes
    print repr(s2) #'\xc1\xd6' 编码一个汉字gbk用2Bytes
    
    print type(s) #<type 'unicode'>
    print type(s1) #<type 'str'>
    print type(s2) #<type 'str'>
    

    2.3、在Python3中也有两种字符串类型str 和 bytes

    str 是 unicode

    #coding:utf-8
    s='林' #当程序执行时,无需加u,'林'也会被以unicode形式保存新的内存空间中,
    
    #s可以直接encode成任意编码格式
    s1 = s.encode('utf-8')
    s2 = s.encode('gbk')
    
    print(s1)   #b'\xe6\x9e\x97'(utf-8三个字节)
    print(s2)   #b'\xc1\xd6' (gbk两个字节)
    print(type(s)) #<class 'str'>
    

    bytes 就是 bytes

    #coding:utf-8
    s='林' #当程序执行时,无需加u,'林'也会被以unicode形式保存新的内存空间中,
    
    #s可以直接encode成任意编码格式
    s1=s.encode('utf-8')
    s2=s.encode('gbk')
    
    
    
    print(s) #林
    print(s1) #b'\xe6\x9e\x97' 在python3中,是什么就打印什么
    print(s2) #b'\xc1\xd6' 同上
    
    print(type(s)) #<class 'str'>
    print(type(s1)) #<class 'bytes'>
    print(type(s2)) #<class 'bytes'>
    

    二、文件操作

    1、文件处理流程

    • 1.打开文件,得到文件句柄并赋值给一个变量
    • 2.通过文件句柄对文件进行操作
    • 3.关闭文件

    2、基本操作

    2.1 打开文件并读取

    打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。

    f = open('data','r',encoding='utf-8')  #这里的f指向的是一个内存空间地址
    file = f.read()  #通过read方法将内存空间中的内容读取出来并赋值给file
    print(f)    #输出一个内存空间地址,及文件名、打开的模式、编码格式。
    f.close()  #关闭文件
    
    print(file) #输出文件内容
    
    输出:
    <_io.TextIOWrapper name='data' mode='r' encoding='utf-8'>
    

    打开文件的模式有:

    • r ,只读模式【默认】
    • w,只写模式【不可读;不存在则创建;存在则清空内容;】
    • x, 只写模式【不可读;不存在则创建,存在则报错】
    • a, 追加模式【可读; 不存在则创建;存在则只追加内容;】

    "+" 表示可以同时读写某个文件:

    • r+, 读写【可读,可写】
    • w+,写读【可读,可写】
    • x+ ,写读【可读,可写】
    • a+, 写读【可读,可写】

    "b"表示以二进制的方式操作

    • rb 或 r+b
    • wb 或 w+b
    • xb 或 w+b
    • ab 或 a+b

    以二进制的方式读写一个图片:

    with open('sb.jpg','rb') as f,\
            open('sb_alex.jpg','wb') as f1:
        data=f.read()
        f1.write(data)
    

    注:b 方式打开时,读取到的内容是bytes类型,写入时也需要提供bytes类型。


    2.2 with语句

    为了避免打开文件后忘记关闭,可以通过管理上下文,即:

    with open('log','r') as f:
         print(f.read())
    
    • 以此方式打开,当with代码块执行完毕时,内部会自动关闭并释放文件资源。
    • 在Python2.7后,with又支持同时对多个文件的上下文进行管理,即:
    with open('log1') as obj1, open('log2') as obj2:
        pass
    

    2.3 常用操作

    read
    读取文件

    with open('a.txt','r',encoding='utf-8') as f:
        print(f.read(4))    #数字指的是读的是字符个数
    

    write
    往文件中写入

    with open('access.log','a',encoding='utf-8') as f:
        f.write('\n我是一个好人')
    

    seek/tell
    seek是将光标跳转到指定位置
    tell是显示当前光标所在位置

    with open('a.txt','r',encoding='utf-8') as f:
        f.seek(3)       #seek内指定的数字代表字节,默认情况,是以文件起始位置作为开始,往后移动3个bytes
        print(f.tell()) # 打印当前光标所在的位置
    

    以当前光标所在的位置为开始,移动光标

    with open('b.txt','rb') as f:
        f.seek(2,1)    # 1 代表以当前光标所在的位置为开始,往后移动2个 bytes
    

    从文件末尾开始,移动光标

    with open('b.txt','rb') as f:
        f.seek(-3,2) # 2表示从文件末尾为开始,往前移动3个bytes
    

    truncate
    截断,从指定位置截断,truncate中的数字是字节数

    with open('a.txt','r+',encoding='utf-8') as f:
        f.truncate(3)   #truncate中的数字是字节数,3个字节可以保留一个汉字,如果只截断1个字节,文件将出现乱码
    

    模拟Linux命令tail -f access.log
    打开文件,并将光标移动到文件末尾,循环读取文件,这样每当文件中新增一条日志并保存后,就会被程序读取到并打印出来。

    # tail -f access.log
    import time
    with open('access.log','r',encoding='utf-8') as f:
        f.seek(0,2)       # 将光标移动末尾第一位
        while True:
            line=f.readline().strip()
            if line:
                print('新增一行日志',line)
            time.sleep(0.5)
    

    close
    关闭文件

    f = open('test','w')
    f.write('11111\n22222\n')
    f.close()
    

    closed
    判断文件是否关闭,关闭返回

    f = open('test','w')
    f.write('11111\n22222\n')
    f.close()
    print(f.closed)
    

    readline
    一行一行的读取文件

    with open('access.log','r') as f:
        print(f.readline())
        print(f.readline())
        print(f.readline())
     
    输出:
    11111
    
    22222
    
    33333  
    # 有空行是因print默认会打换行符,在print中加上end=''即可取消空行
    

    readlines
    一次读取全部文件

    with open('access.log','r') as f:
        print(f.readlines())
    输出:
    ['11111\n', '22222\n', '33333\n', '44444\n', '55555\n', '66666\n', '77777\n', '88888']
    # 可以看出readlines将文件内容变成一个列表了
    
    with open('access.log','r') as f:
        for i in f.readlines():
            print(i,end='')
    输出:
    11111
    22222
    33333
    44444
    55555
    66666
    77777
    88888
    

    注:以上两种方法都会将文件一次加载到内存中,如果文件特别大,比如打开一个20G的文件,而机器内存只有16G,通过这两种方法无疑会将机器内存撑爆。

    想要一行一行读取文件内容,而每次读取一行内容将覆盖之前一行,这样就不会将一个文件中的所有内容全部加载到内存了。想要实现这点,可以采用下面这种方法:
    直接循环文件句柄

    with open('access.log','r') as f:
        for i in f:
            print(i,end='')
    输出:
    11111
    22222
    33333
    44444
    55555
    66666
    77777
    88888
    

    模拟文件改名

    # 模拟文件改名
    f1 = open('c','r')
    f2 = open('.c.swap','w')
    
    for i in f1:
        # print(i)
        if i.startswith('5'):    # 修改以5开头的行
            i = '11111\n'
        f2.write(i)
    f1.close()
    f2.close()
    import os
    os.remove('c')    # 先删除,再改名
    os.rename('.c.swap','c')
    

    readable
    判断文件是否以只读模式打开

    with open('access.log','a',encoding='utf-8') as f:
        print(f.readable())
    输出:
    False
    # 因为是以a模式打开,所以返回False
    

    writeable
    是否以可写的模式打开文件,与readable类似

    writelines
    将列表写入文件,不过请注意,列表中的数据类型只能是字符串

    with open('access.log','w',encoding='utf-8') as f:
        f.writelines(['111\n','222\n','333\n'])
    

    flush
    操作系统在将数据写入硬盘时会等内存中积累到一定量时,才会数据一次性写入硬盘,这样可以节省磁盘 I/O ,flush方法是将内存中的数据强制刷到硬盘

    with open('access.log','w',encoding='utf-8') as f:
        f.write('111\n222')
        f.flush()
    

    三、函数

    • Python中函数的定义:函数是逻辑结构化和过程化的一种编程方法。
      函数的特性:

      • 减少重复代码
      • 使程序变的可扩展
      • 使程序变得易维护
    • 以我自己的理解,函数(function)--> 即功能,由一段代码实现的一个特定的功能,然后在程序中可以反复调用此功能,减少代码冗余。这是我简单的理解,不详之处还请大家多多指正。

    • 在python中,函数分为两类:

      • 内置函数,点击查看
      • 自定义函数,请继续向下看

    1. 函数的定义

    # 语法
    # def 函数名(参数1,参数2,...):
    #     """文档注释"""
    #     函数体
    #     return 值
    

    函数的定义主要有如下要点:

    • def:表示函数的关键字
      函数名:函数的名称,后续代码可根据函数名调用此函数
      函数体:函数中进行一系统的逻辑计算,如:发送邮件、计算出[11,22,38,55,2]中的最大数等。。。
      参数:为函数体提供数据
      返回值:当函数执行完毕后,可以给调用者返回数据。

    1.1 定义函数的二种形式

    1.1.1 无参函数

    如果函数的功能仅仅只是执行一些操作而已,就定义成无参函数,无参函数通常都没有返回值

    def print_star():
        print('#'*6)
    
    print_star()   # 调用函数
    
    1.1.2 有参函数

    函数的功能的执行依赖于外部传入的参数,有参函数通常都有返回值。

    def my_max(x,y):
        res=x if x >y else y  # 三元运算
        print(res)
        return res
    my_max(5,8)   # 5和8是传给my_max函数的参数
    

    2 函数调用

    按照有参和无参,可以将函数调用分为两种,如下:

    def foo():
        print('from foo')
    
    def bar(name):
        print('bar===>',name)
    
    foo()  # 定义时无参,调用时也无需传入参数
    bar('egon') # 定义时有参,调用时也必须传入参数
    

    按照函数的调用形式和出现的位置,分三种:

    • foo() # 调用函数的语句形式
    • 调用函数的表达式形式
    def my_max(x,y):
        res=x if x >y else y
        return res
    res=my_max(1,2)*10000000 #调用函数的表达式形式
    print(res)
    
    • 把函数调用当中另外一个函数的参数
    def my_max(x,y):
        res=x if x >y else y
        return res
    res=my_max(my_max(10,20),30) #把函数调用当中另外一个函数的参数
    print(res)
    输出:
    30
    

    3. 函数的返回值

    以下三种情况返回值都为None

    • 没有return
    • return 什么都不写
    • return None
    def foo():
        print('from foo')
        return None
    res=foo()
    print(res)  # res接收返回值None
    

    多个返回值,将返回成一个元组

    def foo():
        print('from foo')
        return 1,[2,3],(4,5),{}
    res=foo()
    print(res) #打印结果:(1,[2,3],(4,5),{})
    a,b,c,d=foo()  # 可以直接用函数的返回值赋值给变量
    print(d)
    
    输出结果:
    from foo
    (1, [2, 3], (4, 5), {})
    from foo
    {}
    

    4. 函数的参数

    4.1 从大的角度去看,函数的参数分两种:

    • 形参(可以理解为变量名)
    • 实参(赋予变量的值)
    形参与实参
    #定义阶段
    def foo(x,y): #x=1,y=2
        print(x)
        print(y)
    
    #调用阶段
    foo(1,2)
    
    输出:
    1
    2
    

    4.2 详细区分函数的参数

    详细的区分函数的参数分为五种:

    • 位置参数
    • 关键字参数
    • 默认参数
    • 可变长参数( *args,**kwargs)
    • 命名关键字参数
    4.2.1 位置参数

    实参必须与形参一一对应,实参的个数不能多也不能少。

    def foo(x,y,z):#位置形参:必须被传值的参数
        print(x,y,z)
    
    foo(1,2,3) #位置实参数:与形参一一对应
    输出:
    1 2 3
    
    4.2.2 关键字参数

    Key = value

    def foo(x,y,z):
        print(x,y,z)
    
    foo(z=3,x=1,y=2)
    输出:
    1 2 3 
    

    注:位置参数与关键字参数可以一起使用,但是需要注意以下问题:
    1.关键字实参必须在位置实参后面
    2.不能重复对一个形参传值

    # foo(1,z=3,y=2) #正确
    # foo(x=1,2,z=3) #错误
    # foo(1,x=1,y=2,z=3) #错误
    
    4.2.3 默认参数

    在定义函数时,如果使用了默认参数;那在调用此函数时,如果对默认参数指定了新值,则取新值;如果没有对默认参数指定值,则使用默认参数定义的值。

    def register(name,age,sex='male'): #形参:默认参数sex='male'
        print(name,age,sex)
    register('alex',age=40)  # 调用时没有给sex赋值
    输出结果:
    alex 40 male
    

    给默认参数赋新值:

    def register(name,age,sex='male'): #形参:默认参数
        print(name,age,sex)
    register('钢蛋',20,'female')
    register('铁蛋',sex='female',age=19)
    
    # 输出:
    钢蛋 20 female
    铁蛋 19 female
    

    默认参数需要注意的问题:

    1. 默认参数必须跟在非默认参数后面
    ```
    # def register(sex='male',name,age): #在定义阶段就会报错
    #     print(name,age,sex)
    ```
    
    1. 默认参数在定义阶段就已经赋值了,而且只在定义阶段赋值一次
    ```
    a=100000000
    def foo(x,y=a):
        print(x,y)
    a=0
    foo(1)
    # 输出结果:
    1 100000000
        ```
    注:由结果可以看出,后来给a赋值0后并没有生效
    
    1. 默认参数的值通常定义成不可变类型的数据
    4.2.4 可变长参数

    第一种:args*
    *会把溢出的按位置定义的实参都接收,以元组的形式赋值给args

    def foo(x,y,*args): #*会把溢出的按位置定义的实参都接收,以元组的形式赋值给args
        print(x,y)
        print(args)
    
    foo(1,2,3,4,5)
    输出:
    1 2
    (3, 4, 5)
    

    利用可变长参数计算任意长度的和

    def add(*args):
        res=0
        for i in args:
            res+=i
        return res
    print(add(1,2,3,4))
    print(add(1,2))
    输出:
    10 
    3
    

    *第二种:*kwargs **
    **会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs

    def foo(x, y, **kwargs):  # **会把溢出的按关键字定义的实参都接收,以字典的形式赋值给kwargs
        print(x, y)
        print(kwargs)
    foo(1,2,a=1,name='egon',age=18)
    输出:
    1 2
    {'age': 18, 'a': 1, 'name': 'egon'}
    
    4.2.5 命名关键字参数(了解)
    def foo(name,age,*,sex='male',height):
        print(name,age)
        print(sex)
        print(height)
    
    foo('egon',17,height='185')
    输出:
    egon 17
    male
    185
    

    *后定义的参数为命名关键字参数,这类参数,必须被传值,而且必须以关键字实参的形式去传值

    4.2.6 各种形式的参数混合使用
    def foo(name,age=10,*args,sex='male',height,**kwargs):
        print(name)
        print(age)
        print(args)
        print(sex)
        print(height)
        print(kwargs)
    
    foo('alex',1,2,3,4,5,sex='female',height='150',a=1,b=2,c=3)
    

    输出结果:

    alex
    1       # 虽然age是默认参数,但是这里以位置参数的方式,将1传给age为值
    (2, 3, 4, 5)
    female
    150
    {'b': 2, 'c': 3, 'a': 1}
    
    4.2.7 其他姿势

    可变长参数的其他玩法:
    *args :

    # def foo(*args):
    #     print(args)
    # foo(1,2,3,4) # 1,2,3,4 <=====>*(1,2,3,4)
    
    #*['A','B','C','D'], 等同于'A','B','C','D'
    # foo(*['A','B','C','D']) ===> foo('A','B','C','D')
    # foo(['A','B','C','D']) #
    
    # def foo(x,y,z):
    #     print(x,y,z)
    #
    # # foo(*[1,2,3]) #相当于foo(1,2,3)
    # foo(*[1,2]) #相当于foo(1,2)
    

    **kwargs :

    def foo(**kwargs):
        print(kwargs)
    
    foo(**{'y': 2, 'x': 1,'a':1}) #相当于foo(a=1,y=2,x=1)
    输出:
    {'y': 2, 'x': 1, 'a': 1}
    

    *args 与 *kwargs*混合使用:

    def wrapper(*args,**kwargs):
        print(args)
        print(kwargs)
    
    wrapper(1,2,3,a=1,b=2)
    输出:
    (1, 2, 3)
    {'b': 2, 'a': 1}
    

    嵌套:

    def foo(x,y,z):
        print('from foo',x,y,z)
    def wrapper(*args,**kwargs):
        print(args) #args=(1,2,3)
        print(kwargs) #kwargs={'a':1,'b':2}
        foo(*args,**kwargs) #foo(*(1,2,3),**{'a':1,'b':2}) #foo(1,2,3,b=2,a=1)
    # wrapper(1,2,3,a=1,b=2)
    wrapper(1,z=2,y=3)
    
    # 输出:
    (1,)
    {'y': 3, 'z': 2}
    from foo 1 3 2
    

    注:函数定义阶段到底干了什么事情:只检测函数体的语法,并不会执行

    相关文章

      网友评论

      本文标题:第3天,Python字符编码/文件操作/函数

      本文链接:https://www.haomeiwen.com/subject/rxbrxxtx.html