Python系列(7)- Python 命名空间与作用域、输入与输出

 

1. 命名空间与作用域

    Python 中的 命名空间 (Namespace) 和作用域是密切相关的概念。Python 命名空间 (Namespace) 可以视为一个字典,其中键是变量名,值是与之关联的对象。

    各个命名空间是独立的,同一个命名空间中不能有重名(重名的以后一个为准),不同的命名空间是可以重名。
    
    命名空间类似于电脑的文件系统,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名。

    一般有三种命名空间:

        内置名称 (built-in names): Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等;
        全局名称 (global names): 模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量;
        局部名称 (local names): 函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。

    命名空间查找顺序: 局部的命名空间 -> 全局命名空间 -> 内置命名空间。

    命名空间的生命周期:命名空间的生命周期取决于对象的作用域,对象执行完成,则该命名空间的生命周期就结束。

    1) 作用域

        作用域就是 Python 程序可以直接访问命名空间的范围,或者说变量的有效范围。

        Python 的作用域有 4 种:

            L(Local):最内层,包含局部变量,比如一个函数/方法内部。
            E(Enclosing):包含了非局部 (non-local) 也非全局 (non-global) 的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
            G(Global):当前脚本的最外层,比如当前模块的全局变量。
            B(Built-in): 包含了内置的变量/关键字等。

        作用域查找遵循 LEGB 规则:
    
            Local -> Enclosing -> Global -> Built-in
    
        内置作用域是通过一个名为 builtins 的标准模块来实现的,查看内置作用域里的变量和关键字,可以运行如下代码:

            import builtins
            print(dir(builtins))

            注:可是使用 dir() 函数查看模块、类、对象等结构内部所包含的属性列表和方法列表。

        Python 中只有模块(module)、类(class)和函数(def、lambda)才会引入新的作用域,其它的代码块(比如 if/elif/else/、try/except、for/while 等)不会引入新的作用域。
    
        示例:
        #!/usr/bin/python3
        # -*- coding: UTF-8 -*-

        # 全局变量
        s = 'Global'
        def func():

            # nonlocal 变量
            s = 'Enclosing'

            def inner_func():
                # 局部变量
                s = 'Local'
                print(s)    # 输出局部变量 s
                
            inner_func()
            print(s)    # 输出 nonlocal 变量 s

        if __name__ == "__main__":
            func()
            print(s)    # 输出全局变量 s
            print(x)    # 输出未定义变量 x

        输出结果如下:
        Local
        Enclosing
        Global
        Traceback (most recent call last):
        File "d:/pythonDemo/func3.py", line 22, in <module>
            print(x)    # 输出未定义变量 x
        NameError: name 'x' is not defined


            注:在各命名空间都找不到变量 x, 抛出了一个 NameError 异常。
        
        在 fun() 作用域内,给 s 赋值 'Enclosing',没有改变全局变量 s 的值。在 inner_func() 作用域内,给 s 赋值 'Local',没有改变nonlocal 变量 s 的值。在作用域内,想要修改作用域外的变量,需要用到 global 或 nonlocal 关键字。

 

    2) global 和 nonlocal 关键字

        在 Python 中,global 关键字用于标识变量是全局的。如果在函数内部要修改全局变量,需要使用 global 关键字。

        nonlocal 关键字是用于标识变量是外部的(非全局)。如果在函数内部要修改外部函数的变量,需要使用 nonlocal 关键字。

        示例1:

        #!/usr/bin/python3
        # -*- coding: UTF-8 -*-

        # 全局变量
        s = 'Global'
        def func():

            # nonlocal 变量
            s = 'Enclosing'

            def inner_func():
                # 标识 s 是全局变量
                global s
                s = 'Local'
                print(s)    # 输出全局变量 s
                
            inner_func()
            print(s)    # 输出 nonlocal 变量 s

        if __name__ == "__main__":
            func()
            print(s)    # 输出全局变量 s 


        输出结果如下:

            Local
            Enclosing
            Local

        示例2:

        #!/usr/bin/python3
        # -*- coding: UTF-8 -*-

        # 全局变量
        s = 'Global'
        def func():

            # nonlocal 变量
            s = 'Enclosing'

            def inner_func():
                # 标识 s 是 nonlocal 变量
                nonlocal s
                s = 'Local'
                print(s)    # 输出 nonlocal 变量 s
                
            inner_func()
            print(s)    # 输出 nonlocal 变量 s

        if __name__ == "__main__":
            func()
            print(s)    # 输出全局变量 s


        输出结果如下:

            Local
            Local
            Global


    3) 获取作用域范围中的变量

         (1) globals() 函数

             globals() 函数是 Python 的内置函数,在函数内外调用(包括全局作用域),都返回一个全局变量字典。

             示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            # 全局变量
            a = 1
            b = 2
            c = 3
            def func():
                # nonlocal 变量
                i = 11
                j = 12
                
                def inner_func():
                    # 局部变量
                    x = 101
                    y = 102
                    
                inner_func()

            if __name__ == "__main__":
                print(globals())


            输出结果如下:

                {... , 'a': 1, 'b': 2, 'c': 3, ...}

            注: globals() 函数返回的字典中,会默认包含有很多下划线变量,它们是 Python 主程序内置的属性和方法,不用管它们。

        (2) locals() 函数

            locals() 函数也是 Python 的内置函数,在函数内外调用,返回一个当前作用域内所有变量的字典。

            示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            # 全局变量
            a = 1
            b = 2
            c = 3
            def func():
                # nonlocal 变量
                i = 11
                j = 12
                print(locals())
                
                def inner_func():
                    # 局部变量
                    x = 101
                    y = 102
                    print(locals())
                    
                inner_func()

            if __name__ == "__main__":
                func()
                print(locals())


            输出结果如下:

                {'i': 11, 'j': 12}
                {'x': 101, 'y': 102}
                {... , 'a': 1, 'b': 2, 'c': 3, ...}

            注: 在函数内部调用 locals() 函数,会获得包含所有局部变量的字典;在全局作用域调用,locals() 的功能和 globals() 函数相同。

        (3) vars(object) 函数

            vars(object) 函数也是 Python 内置函数,其功能是返回一个指定 object 对象范围内所有变量组成的字典。

            示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            # 全局变量
            a = 1
            b = 2
            c = 3

            class Person:
                name = 'Python'
                age = 20

            if __name__ == "__main__":
                print(vars(Person))
                print(vars())


            输出结果如下:

                {..., 'name': 'Python', 'age': 20, ...}
                { ... 'a': 1, 'b': 2, 'c': 3, ...}

            注:如果不传入 object 参数,vars() 和 locals() 的作用完全相同。

 

 

2. 输入与输出

    1) 控制台输入  

        (1) input() 函数

            input() 函数的主要功能是从标准输入(通常是键盘)读取一行文本。语法格式如下:

                变量 = input(prompt=None)

            函数说明:

                prompt:可选参数,是一个字符串,用于显示提示信息,告诉用户应该输入什么类型的数据。
                变量: 函数返回一个字符串,即用户输入的文本。

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                a = input('Please enter a number:')
                print(type(a), int(a))

                b = input('Please enter 2 numbers seprate with spaces:').split()
                print(type(b), b)

                c,d = input('Please enter 2 numbers seprate with comma:').split(',')
                print(type(c), int(c))
                print(type(d), int(d))


            输出结果如下:

                Please enter a number:2
                <class 'str'> 2
                Please enter 2 numbers seprate with spaces:3 5
                <class 'list'> ['3', '5']
                Please enter 2 numbers seprate with comma:7,8
                <class 'str'> 7
                <class 'str'> 8


        (2) sys.stdin.read() 函数

            sys.stdin.read() 函数用于从标准输入读取数据,直到遇到 EOF(End of File)字符。‌这个函数会阻塞当前程序的执行,直到用户输入数据和回车键,按下 ‌Ctrl+D(在 Unix/Linux 系统中)或 Ctrl+Z(在 Windows 系统中)键并按下回车键,结束输入。

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import sys

                s = sys.stdin.read().split('\n')
                print(type(s), sa)


            输出结果如下:

                3
                4
                5
                ^Z
                <class 'list'> ['3', '4', '5', '']

                注:输入 3 后回车,再输入 4 后回车,再输入 5 后回车,同时按下 Ctrl+Z (Windows下) 键后回车。


    2) 控制台输出

        (1) print() 函数

            在 Python 3.x 中 print 是一个函数,但在 Python2.x 版本不是一个函数,是一个关键字。语法格式如下:

                print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

            函数说明:
                
                objects -- 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
                sep -- 用来间隔多个对象,默认值是一个空格。
                end -- 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
                file -- 要写入的文件对象。
                flush -- 输出是否被缓存通常决定于 file,但如果 flush 关键字参数为 True,流会被强制刷新。

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import time
                import math

                print(1)
                print('1')

                print(1, '2')
                print(1, 2)

                print("python", "3.x")
                print("python", "3.x", sep="_")

                print("python""2.x")

                print("python", end="")    # 以空格替代换行符,
                print("3.x")

                print("--- Loading 效果 ---")
                print("Loading",end = " ")
                for i in range(10):
                    print(".", end = "",flush = True)
                    time.sleep(0.5)
                print('')
                

                # 使用 f-string 语法格式化输出
                s1 = 'python'
                s2 = '2.x'
                print(f'{s1}  {s2}')
                print(F'{s2}  {s1}')        # F 和 f 等效
                print(f'2*2={2*2}, pi={math.pi}')
                print(f'{{s1}} {{{s2}}}')      # 字符串中插入大括号

                # 使用 format() 函数 f-string 语法格式化输出
                print("{0} {1}".format('Python', '3.x'))
                print("{1} {0}".format('Python', '3.x'))
                print("{name} {version}".format(name='Python', version='3.x'))
                print("{name} {0}".format('3.x', name='Python'))

                print('整型值:{:5d}'.format(3))
                print('PI 值:{}'.format(math.pi))
                print('PI 值:{0:.2f}'.format(math.pi))
                print("{0:10} {1:.2f}".format('Python', math.pi))   # 在 : 后的 10, 表示要输出 10 个字符,不够用空格来补

                obj = {'name': 'python', 'age': 20}
                print('{0[age]:d}'.format(obj))     # 使用 [] 访问字典键值,:d 表示整型
                print('{0[age]:x}'.format(obj))     # 使用 [] 访问字典键值,:d 表示十六进制整数
                print('{0[name]:s}'.format(obj))    # 使用 [] 访问字典键值,:s 表示字符串

                # 使用 % 格式化输出
                print('PI 值:%4.2f' % math.pi)


            输出结果如下:

                1
                1
                1 2
                1 2
                python 3.x
                python_3.x
                python2.x
                python3.x
                --- Loading 效果 ---
                Loading ..........
                python  2.x
                2.x  python
                2*2=4, pi=3.141592653589793
                {s1} {2.x}
                Python 3.x
                3.x Python
                Python 3.x
                Python 3.x
                整型值:    3
                PI 值:3.141592653589793
                PI 值:3.14
                Python     3.14
                20
                14
                python
                PI 值:3.14


        (2) sys.stdout.write() 函数

            sys.stdout.write() 函数用于从标准输出流将信息输出到控制台,不会自动输出换行符(\n),参数是字符串.
            
            调用 print() 函数时,默认情况下实际是调用了 sys.stdout.write() 函数。

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import sys

                sys.stdout.write('Python ')
                sys.stdout.write('3.x\n')

            输出结果如下:

                Python 3.x

        (3) pprint() 模块

            pprint (Data pretty printer),顾名思义就是让显示结果更漂亮。

            pprint() 模块打印出来的数据结构更加完整,每行为一个数据结构,更加方便阅读打印输出结果。

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import pprint

                data = [(1,{'a':'A','b':'B','c':'C','d':'D'}),(2,{'e':'E','f':'F','g':'G','h':'H'})]

                from pprint import pprint
                print('depth 1:')
                pprint(data, depth=1)

                print('depth 2:')
                pprint(data, depth=2)

                print('depth 3:')
                pprint(data, depth=3)


            输出结果如下:

                depth 1:
                [(...), (...)]
                depth 2:
                [(1, {...}), (2, {...})]
                depth 3:
                [(1, {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}),
                (2, {'e': 'E', 'f': 'F', 'g': 'G', 'h': 'H'})]


    3) 读写文件

        open() 方法用于打开一个文件,并返回文件对象。语法格式如下:

            open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

        参数说明:

            file: 必需,文件路径(相对或者绝对路径)。
            mode: 可选,文件打开模式,默认为文本模式,如果要以二进制模式打开,加上 b 。
            buffering: 设置缓冲
            encoding: 一般使用utf8
            errors: 报错级别
            newline: 区分换行符
            closefd: 传入的file参数类型
            opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。

        mode 参数:

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(Python 3 不支持)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。


        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-
              
            # Create/write a file
            with open('foo.txt', 'w', encoding='UTF-8', newline='') as f:
                num = f.write("open() 方法用于打开一个文件,并返回文件对象。\n语法格式如下:\nopen(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)\n")
                print('f.write(): ', num)
                f.close()

            # Read()
            with open('foo.txt', 'r', encoding='UTF-8', newline='') as f:
                str = f.read()
                print('f.read(): ')
                print(str)

                # cursor position
                print('f.tell():', f.tell())

                # Seek to start
                f.seek(0, 0)
                print('f.seek(0, 0):', f.tell())

                str = f.readline()
                print('f.readline(): ')
                print(str)

                str = f.readlines()
                print('f.readlines(): ')
                print(str)
                f.close()


        输出结果如下:

            f.write():  139
            f.read():
            open() 方法用于打开一个文件,并返回文件对象。
            语法格式如下:
            open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

            f.tell(): 191
            f.seek(0, 0): 0
            f.readline():
            open() 方法用于打开一个文件,并返回文件对象。

            f.readlines():
            ['语法格式如下:\n', "open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)\n"]


    4) pickle 模块

        pickle 模块用于实现基本的数据序列和反序列化。

        (1) 数据序列化
        
            序列化操作就是将程序中运行的对象信息保存到文件中去,永久存储,函数格式如下:
            
                pickle.dump(obj, file, [,protocol])        

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import pickle

                class A:
                    def display(self, s):
                        print(s)

                data = [(1,{'a':'A','b':'B','c':'C','d':'D'}),(2,{'e':'E','f':'F','g':'G','h':'H'})]

                a = A()

                with open('data.pkl', 'wb') as f:

                    # Pickle dictionary using protocol 0.
                    pickle.dump(data, f)

                    # Pickle the list using the highest protocol available.
                    pickle.dump(a, f, -1)

                    print('pickle.dump() -> OK')

                    f.close()


            输出结果如下:

                pickle.dump() -> OK


        (2) 数据反序列化

            反序列化操作就是从文件中读取序列化数据,转换成数据对象,函数格式如下:

                obj = pickle.load(file)

            示例:

                #!/usr/bin/python3
                # -*- coding: UTF-8 -*-

                import pickle
                import pprint

                with open('data.pkl', 'rb') as f:

                    obj1 = pickle.load(f)
                    pprint.pprint(obj1)

                    obj2 = pickle.load(f)
                    pprint.pprint(obj2)

                    obj2.display('pickle.load() -> OK')

                    f.close()


            输出结果如下:

                [(1, {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}),
                (2, {'e': 'E', 'f': 'F', 'g': 'G', 'h': 'H'})]
                <__main__.A object at 0x000001D5489B7130>
                pickle.load() -> OK

 

posted @ 2024-08-22 19:26  垄山小站  阅读(29)  评论(0编辑  收藏  举报