• 第十八篇 模块与包--time&random模块&模块导入import(os.path.dirname(os.path.abspath(__file__)))


    模块

    在Python中, 一个.py文件就称为一个模块。

    使用模块的好处:

    1. 最大的好处就是大大提高了代码的可维护性

    2. 编写代码不必从零开始。一个模块编写完毕,就可以被其他地方引用。在写其他程序时,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。

    3. 使用模块还可以避免函数名与变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,在编写模块时,不必考虑名字会与其他模块冲突。但是,要注意尽量不要与内置函数名字冲突。

    所以,模块一共有三种:

    1. Python标准库

    2. 第三方模块

    3. 应用程序自定义模块

    模块的导入

    1. 使用import语句

    # 两种不同的导入方式
    
    # 多个模块分多行导入
    import module1
    import module2
    ...
    
    # 多个模块可以写在一行里导入
    import module1, module2, module3, .....

    当使用import语句的时候,Python解释器怎样找到对应的文件呢?

    就是解释器有自己的搜索路径,存在sys.path里。

    因此,若当前目录下存在要与要引入模块同名的文件,就会把要引入的模块屏蔽掉。

    2. from... import....语句

    from module import name1[, name2[,nameN]]

    这个声明不会把整个modulename模块导入到当前的命名空间中,只会将它里面的name1 或者name2单个引入到执行这个声明的模块的全局符号表。

    3. from ... import * 语句

    from module import *

    该语句提供了一个简单的方法来导入一个模块中的所有项目。

    然而,这种方式并不推荐使用,因为可能存在引入的模块里某个变量名与自己定义的变量名相同,而导致执行错误。

    4. 被导入模块与当前文件不在同一个目录

    import sys
    print(sys.path)  # 放的路径,就是执行文件所在路径
    
    cal文件里有个add功能
    # 需求:传入个参数,可以执行add功能
    
    # 跨文件引入的方式
    # 1. 首先:要在main里引入cal
    
    # 2. 其次:要在bin里引入main


     

    备注:

    bin文件:一般是程序的入口

    main文件:与逻辑相关的程序都放在main文件里

    但是,通常情况下,bin都是写在包下面的,不会暴露在最外面。

    记住下面的路径的写法,然后你的文件不管在哪个机器上使用都可以正常执行了。

    看Day21 和 Day22(03-python-全栈三期-day22 BASEDIR的介绍 )

    import sys
    import os
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)
    总的原理就是通过当前文件,一步步的往外找,找到你需要的文件目录,然后加入path
    
    解析:
    1. 首先要知道 __file__,就代表的是当前文件,此例子里就是bin.py文件
    2. os.path.abspath(__file__):是__file__ 这个当前文件的绝对路径,找到bin目录
    3. os.path.dirname(os.path.abspath(__file__)):就是通过2获取它的绝对路径的上一级绝对路径,到day21_lesson目录了
    4. os.path.dirname(os.path.dirname(os.path.abspath(__file__))):再往上一层找,找到day21目录了
    
    5. sys.path.append(BASE_DIR):把4找到的绝对路径加入到path里,之后,模块导入的时候,就会在day21目录下面找了
    
    但是,也要知道,sys.path.append()也只是临时加入路径,不是永久加入的哦

    5. 导入模块做的两件事

    无论是上面1,2,3哪种导入方式,导入模块运行的本质都没有变,都做了2件事:
    
    1. 首先通过sys.path找到被导入的模块(.py文件)
    2. 然后执行全部被导入的模块。
    
    区别是:
    import module 会将module这个变量名加载到名字空间
    from module import name 只会将 name这个变量名加载进

     模块的动态导入

    上面介绍了模块的正常导入,但是如果给的是一个字符串,那怎么导入呢?目录结构如下:

    需求是:要将m1下的t.py导入到01.动态导入模块.py文件里

    # 1. 正常的导入及调用执行
    from m1 import t
    t.test1()
    # 2. 现在有个新问题,要求你不能按照上面的方式到导入,给的是个字符串  'm1.t'
    # 通过字符串方式导入模块
    module_t = __import__('m1.t')
    print(module_t)
    # <module 'm1' (namespace)>
    # 为什么导入的模块是m1,而不是t呢?而我们要导入的就是t模块啊?
    '''
    这种导入方式,不管你下面套多少层,返回的都是最顶层的模块
    '''
    # 调用:都需要通过最顶层的模块以.的方式,一层一层的往下找,直到调用你需要引用的模块
    module_t.t.test1()
    # 3. 利用importlib模块导入字符串形式的模块
    import importlib
    m = importlib.import_module("m1.t")
    print(m)
    # <module 'm1.t' from 'F:\workspace\Try2\m1\t.py'>
    # 以这种方式导入,直接就定位到你想要调用的t模块了
    
    # 调用
    m.test1()

    总结:

    __import__(‘m1.t') 与 import.importLib(’m1.t') 导入的都是 字符串'm1.t'模块,为啥定位的模块不一样呢?也就是两者的区别?

    1. __import__(‘m1.t') :是python内部的调用方式,它只能定位到最顶层的模块,调用的时候需要以点的方式,一级级往下找,直到找到你需要的模块

    2.importLib('m1.5'):是面向用户的模块导入方式,它能直接定位到你需要导入的模块,所以,如果传入的是字符串形式的模块名,推荐用这种方式导入。

     可以将不同类型、功能的文件放到不同的包里,方便管理

    引用包

    # 引用包有两种方式,包与包之间通过.号连接
    在图中 module-lesson.py里执行cal.py文件
    
    # 第一种:导入模块
    from web.web1.web2 import cal
    
    cal.add(3,4)
    
    
    # 第二种:把模块和包写在一起,导入方法
    from web.web1.22.cal import add
    
    add(3,5)

     __name__:

    # 1. 在执行文件里(当前正在被执行的文件就是执行文件)
    
    print(__name__)
    #结果
    __main__
    
    # 2. 在调用文件里执行
    A文件里导入了B模块,A文件就是调用文件,B模块文件是被调用文件
    print(__name__)
    # 结果
    是B模块的文件名   (Pycharm会自作主张给出文件路径)
    
    知道了这个原理,那if __name__=="__main__" 有什么作用呢?
    
    # 1. 如果放在被调用文件里,用于被调用文件的测试
    if __name__=="__main__":
        print("ok")
        a=add(5,8)
        print(a)
    
    解释:
    一般写好了一个被调用文件,肯定是要先进行测试的,测试通过了,才能让别人调用。那么测试一般也是在被调用文件里进行的:
    如果不加
    if __name__=="__main__",那么,该文件被调用后,测试代码就会被执行;
    如果加上了if __name__=="__main__",Python就会知道该语句下面的代码是测试代码,其他人引入该文件,就自动忽略了(忽略了这写测试代码,不会被执行),而不去执行了。 # 2. if __name__=="__main__"如果放到执行文件里,就一点,意思是这个执行文件不想被其他人调用。(就是禁止别人调用我的文件)。 比如bin.py一般作为程序的入口,不希望别人调用,那也可以加上 if __name__=="__main__":

    所以,写代码要养成习惯,在文件里要加上 if __name__=="__main__", 主动避免一些坑。

     Python内置模块

    1. time模块

    文件名与内置模块同名,是可以的。

    time模块里需要掌握的三种时间表达式。

    关于时间模块,记住两张图

    # 1. 时间戳:是一堆秒数
    # 作用:做计算来用的
    print(time.time())    
    #1481321748.481654秒   1970.1.1 00:00:00开始计算到当前为止总归的秒数
    # 1970年是unix诞生的日子
    
    # 2. #结构化时间---当地时间
    
    print(time.localtime())
    
    # 结果
    time.struct_time(tm_year=2018, tm_mon=6, tm_mday=26, tm_hour=13, tm_min=7, tm_sec=29, tm_wday=1, tm_yday=177, tm_isdst=0)
    
    # tm_wday :表示这个星期的第几天,默认是从0开始的,1代表星期二
    # tm_yday: 表示当前是第多少天
    
    print(time.localtime(1529989999.4332166))
    # 结果
    time.struct_time(tm_year=2018, tm_mon=6, tm_mday=26, tm_hour=13, tm_min=13, tm_sec=19, tm_wday=1, tm_yday=177, tm_isdst=0)
    
    t=time.localtime()
    print(t.tm_year)   # 2018
    print(t.tm_wday)   # 1   # 星期二,做显示的时候,需要手动 +1,转换为人类意识能接受的之后再显示
    
    #-----#结构化时间---UTC市区,世界标准时间
    print(time.gmtime())
    
    # 结果
    time.struct_time(tm_year=2018, tm_mon=6, tm_mday=26, tm_hour=5, tm_min=15, tm_sec=47, tm_wday=1, tm_yday=177, tm_isdst=0)
    
    print(time.gmtime(time.time()))
    # 结果
    time.struct_time(tm_year=2018, tm_mon=6, tm_mday=26, tm_hour=5, tm_min=22, tm_sec=51, tm_wday=1, tm_yday=177, tm_isdst=0)
    
    
    # 将结构化时间转换成时间戳
    print(time.mktime(time.localtime()))
    # 1529990485.0
    
    # 将结构化时间转换成字符串时间(******) strftime()
    # 第一个参数:转换后的显示格式
    # 第二个参数:要转换的时间
    print(time.strftime("%Y---%m-%d %X",time.localtime()))
    # 结果
    2018---06-26 13:25:27
    # 年: %Y  月:%m   日:%d   时分秒:%X
    # 年月日之间的分隔符完全是自己定义的
    
    # 将字符串时间转换为结构化时间  strptime()
    # 第一个参数:字符串时间,要转换的时间
    # 第二个参数:结构化时间的格式与第一个字符串时间进行对应
    print(time.strptime("2016:12:24:17:50:36","%Y:%m:%d:%X"))
    
    
    # 重点记住下面两种转换,因为不需要自己再自定义时间格式了
    asctime()
    # 把一个表示时间的元组或者结构化时间 表示为:Tue Jun 26 13:35:21 2018 这种固定的形式
    # 如果没有传参数,会默认将time.localtime()作为参数传入
    print(time.asctime(time.localtime()))   # Tue Jun 26 13:35:21 2018
    
    ctime()
    # 把一个时间戳(按秒计算的浮点数)转换为time.asctime()的形式。
    # 如果参数未给或者为None的时候,会默认将time.time()作为参数。
    # 他的作用相当于time.asctime(time.localtime())
    print(time.ctime())     # Tue Jun 26 13:36:26 2018

    2. datetime 模块

    import datetime
    print(datetime.datetime.now())
    # 结果
    2018-06-26 13:43:04.853231

     3. random 模块

    random模块提供各种用于生产伪随机数的函数,以及根据不同的实数分布来随机生产值的函数。

    # random() :
    生成(0,1)内的随机浮点数
    ret = random.random()
    
    #  uniform(a,b):
    生成[a,b) 内的大于1的随机浮点数
    ret=random.uniform(1,4)
    
    # randint(a,b) : 
    生成[a,b]内的随机整型数字,闭区间
    ret=random.randint(1,3)
    
    # randrange(a,b [,step]) : 
    生成[a,b)内的随机整型数字,左闭右开区间, step表示步长
    ret=random.randrange(1,10,2)        # 只能在 1,3,5,7, 9里随机生成
    
    随机序列:
    # choice(seq): 
    从非空序列seq中返回一个随机元素
    ret=random.choice([11,22,33,44,55])
    
    # sample(seq, len) : 
    返回长度为len的序列,包含从序列 seq中随机选择的元素。结果序列中的元素按照选择他们时的顺序排列
    ret=random.sample([11,22,33,44,55],3)   
    
    # shuffle(x, [random]): 
    随机原地打乱列表x中的项,random是可选参数,它指定随机生成函数。如果提供该参数,则该参数不能是包含参数并且返回范围在[0.0, 1.0)内的浮点数的函数。
    ret=[1,2,3,4,5]
    random.shuffle(ret)
    print(ret)    # [2, 1, 5, 4, 3]-->随机乱序的

    生成一个数字和字母并存的4位数的随机验证码

    def vCode():
        ret = ""
        for i in range(4):
            num = random.randint(0,9)
            alf = chr(random.randint(65,122))   # A~Z 和 a~z
            finalVocd = str(random.choice([num, alf]))
            ret += finalVocd  # 字符串拼接
        return ret
    
    print(vCode())
  • 相关阅读:
    第七周CorelDRAW课总结
    第七周CorelDRAW课总结
    hive基本操作与应用
    hive基本操作与应用
    hive基本操作与应用
    hive基本操作与应用
    Linux运维面试题:请简要说明Linux系统在目标板上的启动过程?
    Linux运维面试题:请简要说明Linux系统在目标板上的启动过程?
    arcserver开发小结(一)
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/victorm/p/9218974.html
Copyright © 2020-2023  润新知