美文网首页
python 脚本编写

python 脚本编写

作者: 喔蕾喔蕾喔蕾蕾蕾 | 来源:发表于2018-06-10 00:46 被阅读454次

    一、在脚本中接受原始输入

    使用内置函数 input 获取用户的原始输入, input() 函数接受一个标准输入数据,返回为 string 类型。如果希望接收的数字是它原始的类型,可以使用eval(input())来接收原始输入,甚至能直接解析表达式。
    举栗子:

    name = input("Enter your name: ")
    print("Hello there, {}!".format(name.title()))
    #输入lei,会输出Hello there, Lei!
    result = eval(input("Enter an expression: "))
    print(result)
    #输入2*3,会得出6
    

    input到此结束,那么我们来看看eval是什么呢?
    eval的功能其实已经知道了,功能是将string变成算术表达式来执行,比如eval("2*3")的结果是6这种。但是eval的功能不仅限于此,让我们来看下eval函数原型:

    eval(expression, globals=None, locals=None)
    

    能看到里面有两个默认参数,globals和locals,这两个参数如果要配合的话,都要配置成字典的形式,那么,为什么呢?
    大家还记得之前我们所讲过的命名空间global全局命名空间和local局部命名空间对吧,其实python的全局名字空间存储在一个叫globals()的dict对象中;局部名字空间存储在一个叫locals()的dict对象中。我们可以用print (locals())来查看该函数体内的所有变量名和变量值。
    绕回eval,那么这两个参数,也就类似命名空间globals和locals了,让我们分开来说:

    • 当后两个参数都为空时,很好理解,就是一个string类型的算术表达式,计算出结果即可。等价于eval(expression)。
    • 当locals参数为空,globals参数不为空时,先查找globals参数中是否存在变量,并计算。
    • 当两个参数都不为空时,先查找locals参数,再查找globals参数。

    举栗子:
    1、在前两个参数省略的情况下,eval在globals的内建模块__builtins__内执行( 可以通过print(dir(__builtins__)) 来看有什么):

    a=10;  
    print(eval("a+1"))
    

    执行结果为:11
    在这种情况下,后两个参数省略了,所以eval中的a是前面的10。对于eval,它会将第一个expression字符串参数的引号去掉,然后对引号中的式子进行解析和计算。
    2、在globals指定的情况下,在指定的globals域中执行(记住是字典):

    a=10;  
    g={'a':4}  
    print(eval("a+1",g))  
    

    执行结果为:5
    在这次的代码中,我们在 eval中提供了globals参数,这时候eval的作用域就是g指定的这个字典了,也就是外面的a=10被屏蔽掉了,eval是看不见的,所以使用了a为4的值。
    3、在 locals指定的情况下,在指定的locals域中执行(记住是字典) :

    a=10  
    b=20  
    c=30  
    g={'a':6,'b':8}  
    t={'b':100,'c':10}  
    print(eval('a+b+c',g,t))
    

    执行的结果为:116
    a是6,b是100,c是10。我们首先来看一下,对于a为6我们是没有疑问的,因为在上个例子中已经说了,g会屏蔽程序中的全局变量的,而这里最主要的是为什么b是100呢?还记得我们在参数介绍的时候说过,当locals和globals起冲突时,locals是起决定作用的,这在很多编程语言里都是一样的,是作用域的覆盖问题,当前指定的小的作用域会覆盖以前大的作用域,这可以理解为一张小的纸盖在了一张大的纸上,纸是透明的,上面写的东西是不透明的,而它们重合的地方就可以理解成两个作用域冲突的地方,自然是小的显现出来了。

    二、异常处理

    Try 语句
    我们可以使用 try 语句处理异常。你可以使用 4 个子句(除了视频中显示的子句之外还有一个子句)。

    • try:这是 try 语句中的唯一必需子句。该块中的代码是 Python 在 try 语句中首先运行的代码。
    • except:如果 Python 在运行 try 块时遇到异常,它将跳到处理该异常的 except 块。
    • else:如果 Python 在运行 try 块时没有遇到异常,它将在运行 try 块后运行该块中的代码。
    • finally:在 Python 离开此 try 语句之前,在任何情形下它都将运行此 finally 块中的代码,即使要结束程序,例如:如果 Python 在运行 except 或 else 块中的代码时遇到错误,在停止程序之前,依然会执行此finally 块。

    指定异常
    我们实际上可以指定要在 except 块中处理哪个错误,如下所示:

    try:
        # some code
    except ValueError:
        # some code
    

    现在它会捕获 ValueError 异常,但是不会捕获其他异常。如果我们希望该处理程序处理多种异常,我们可以在 except 后面添加异常元组。

    try:
        # some code
    except (ValueError, KeyboardInterrupt):
        # some code
    

    或者,如果我们希望根据异常执行不同的代码块,可以添加多个 except 块。

    try:
        # some code
    except ValueError:
        # some code
    except KeyboardInterrupt:
        # some code
    

    在处理异常时,依然可以如下所示地访问其错误消息:

    try:
        # some code
    except ZeroDivisionError as e:
       # some code
       print("ZeroDivisionError occurred: {}".format(e))
    

    应该会输出如下所示的结果:

    ZeroDivisionError occurred: division by zero
    

    如果没有要处理的具体错误,依然可以如下所示地访问消息:

    try:
        # some code
    except Exception as e:
       # some code
       print("Exception occurred: {}".format(e))
    

    Exception 是所有内置异常的基础类,还想知道其他类错误可以看这里

    触发异常
    我们可以使用raise语句自己触发异常

    raise语法格式如下:

    raise [Exception [, args [, traceback]]]
    

    语句中 Exception 是异常的类型(例如,NameError)参数标准异常中任一种,args 是自已提供的异常参数。

    最后一个参数是可选的(在实践中很少使用)。

    def functionName( level ):
        if level < 1:
            raise Exception("Invalid level!", level)# 触发异常后,后面的代码就不会再执行
    

    注意:为了能够捕获异常,"except"语句必须有用相同的异常来抛出类对象或者字符串。

    例如我们捕获以上异常,"except"语句如下所示:

    try:
        正常逻辑
    except Exception as err:
        触发自定义异常    
    else:
        其余代码
    

    结合后完整的例子

    # 定义函数
    def mye( level ):
        if level < 1:
            raise Exception("Invalid level!")
            # 触发异常后,后面的代码就不会再执行
    try:
        mye(0)            # 触发异常
    except Exception as err:
        print(1, err)
    else:
        print(2)
    

    三、读写文件

    读取文件

    f = open('my_path/my_file.txt', 'r')
    file_data = f.read()
    f.close()
    
    • 用open 打开文件,参数是文件路径字符串。open 函数会返回文件对象,Python 通过该对象与文件本身交互。
    • 你可以在 open 函数中指定可选参数。参数之一是打开文件时采用的模式。 r,即只读模式。这实际上是模式参数的默认值。
    • 使用 read 访问文件对象的内容。该 read 方法会接受文件中包含的文本并放入字符串中。在此示例中,我们将该方法返回的字符串赋值给变量 file_data。
    • 当我们处理完文件后,使用 close 方法释放该文件占用的系统资源。

    写入文件

    f = open('my_path/my_file.txt', 'w')
    f.write("Hello there!")
    f.close()
    
    • 以写入 ('w') 模式打开文件。如果文件不存在,Python 将为你创建一个文件。如果以写入模式打开现有文件,该文件中之前包含的所有内容将被删除。如果你打算向现有文件添加内容,但是不删除其中的内容,可以使用附加 ('a') 模式,而不是写入模式。
    • 使用 write 方法向文件中添加文本。
    • 操作完毕后,关闭文件。

    With
    with会在你使用完文件后自动关闭该文件。

    with open('my_path/my_file.txt', 'r') as f:
        file_data = f.read()
    

    该 with 关键字使你能够打开文件,对文件执行操作,并在缩进代码(在此示例中是读取文件)执行之后自动关闭文件。现在,我们不需要调用 f.close() 了!你只能在此缩进块中访问文件对象 f。

    四、导入模块或者包

    模块module其实就是py文件(即使是库文件其实也是py文件),要导入模块荷包,需要关键字import。
    包就是一个容器,用来存放其他的模块和包,包内必须含有__init__.py文件,下面我们来看一个包的结构:

        PkgA/                         # 顶层包  
            __init__.py               # 初始化 PkgA  
            PkgB/                     # PkgA 的子包 PkgB  
                __init__.py           # 初始化 PkgB  
                module1.py  
                module2.py  
            PkgC/                     # PkgA 的子包 PkgC  
                __init__.py               # 初始化 PkgC  
                module1.py  
                module2.py  
    

    在包PkgA下面出现了同名的模块 module1.py和 module2.py ,通过添加子包 PkgB和 PkgC将其区分。

    #语法:
    import 模块名(库名)
    import 模块名(库名) as 别名
    import 包名.子包名.模块名
    import 包名.子包名.模块名 as 别名
    from 模块名 import 函数名
    from 包名.子包名.模块名 import 函数名
    
    #以上面的包为例,另外假设module1模块内有一个say函数,负责输出hello语句
    
        # 方式一:导入函数所在模块  
        >>> import PkgA.PkgB.module1  
        >>> PkgA.PkgB.module1.say()  
        hello  
        # 方式二:从包 PkgA.PkgB 中导入函数所在模块  
        >>> from PkgA.PkgB import module1  
        >>> module1.say()  
        hello  
        # 方式三:从模块中导入函数  
        >>> from PkgA.PkgB.module1 import say  
        >>> say()  
        hello  
    

    导入自定义模块的3种方式

    • 第一种,直接 import
      (1)要导入的py文件(模块),直接放到跟要运行的py文件的当前目录下,import文件名即可
      (2)你的包和模块同属于同个目录(父级目录),如下图:
    01

    (1)main.py 和 pwcong模块同在python目录
    (2) 执行文件为main.py
    (3) pwcong文件夹为一个模块,该模块有个hi函数

    执行文件main.py直接import模块:

    # main.py
    # -*- coding: utf-8 -*-
    
    import pwcong
    pwcong.hi()
    
    • 第二种 如果执行文件和模块不在同一目录,这时候直接import是找不到自定义模块的。如下图:
    02

    (1) 执行文件main.py在main目录下
    (2)pwcong模块在python目录下

    sys模块是python内置的,因此我们导入自定义模块的步骤如下:

    1. 先导入sys模块
    2. 然后通过sys.path.append(path) 函数来导入自定义模块所在的目录
    3. 导入自定义模块。

    这时候 main.py 这样写:

    import sys
    sys.path.append(r"C:\Users\Pwcong\Desktop\python")
    import pwcong
    pwcong.hi()
    
    • 第三种,通过pth文件找到自定义模块

    这个方法原理就是利用了系统变量,python会扫描path变量的路径来导入模块,可以在系统path里面添加。但是我还是推荐使用pth文件添加。

    模块和执行文件目录结构跟上图一样:

    02

    (1) 执行文件main.py在main目录下
    (2)pwcong模块在python目录下

    我们创建一个 module_pwcong.pth 文件,里面内容就是 pwcong模块所在的目录:

    C:\Users\Pwcong\Desktop\python
    

    将该 module_pwcong.pth 文件放到这里:

    python安装目录\Python36\Lib\site-packages
    

    例如我的:


    03

    然后 main.py 导入并使用自定义模块:

    # -*- coding: utf-8 -*-
    
    import pwcong
    
    pwcong.hi()
    

    以上来自链接分享

    五、__name____main__含义详解

    为了避免运行从其他脚本中作为模块导入的脚本中的可执行语句,将这些行包含在 if __name__ == "__main__" 块中。或者,将它们包含在函数 main() 中并在 if __name__ == "__main__" 块中调用该函数。
    每当我们运行此类脚本时,Python 实际上会为所有模块设置一个特殊的内置变量 name。当我们运行脚本时,Python 会将此模块识别为主程序,并将此模块的 name 变量设为字符串 "main"。对于该脚本中导入的任何模块,这个内置 name 变量会设为该模块的名称。因此,条件if __name__ == "__main__"会检查该模块是否为主程序。
    以上是课程内的描述,但是关于if __name__ == "__main__",其实并不是描述的特别清楚,这里我推荐这个网址,来对这个问题学习的更深。

    以下为引用:
    python并没有一个固定的函数入口,而if __name__ == '__main__' 相当于是 Python 模拟的程序入口。Python 本身并没有规定这么写,这只是一种编码习惯。由于模块之间相互引用,不同模块可能都有这样的定义,而入口程序只能有一个。到底哪个入口程序被选中,这取决于__name__ 的值。
    __name__ 是内置变量,用于表示当前模块的名字,同时还能反映一个包的结构。来举个例子,假设有如下一个包:

    a
    ├── b
    │   ├── c.py
    │   └── __init__.py
    └── __init__.py
    

    目录中所有 py 文件的内容都为:
    print(__name__)
    我们执行 python -c "import a.b.c",输出结果:

    a
    a.b
    a.b.c
    

    由此可见,name 可以清晰的反映一个模块在包中的层次。

    如果一个模块被直接运行,则其没有包结构,其 __name__值为 __main__。例如在上例中,我们直接运行 c.py 文件(python a/b/c.py),输出结果如下:

    __main__
    

    所以,if __name__ == '__main__' 我们简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。

    另外,在知乎上看到一个很有趣的比喻,可以理解一下:


    image.png

    六、标准库和第三方库

    没啥讲的,要用啥谷歌搜索!标准库去查阅api文档!

    相关文章

      网友评论

          本文标题:python 脚本编写

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