zoukankan      html  css  js  c++  java
  • 第十八篇 模块与包--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())
  • 相关阅读:
    poj 2528 Mayor's posters (线段树+离散化)
    poj 1201 Intervals (差分约束)
    hdu 4109 Instrction Arrangement (差分约束)
    poj 1195 Mobile phones (二维 树状数组)
    poj 2983 Is the Information Reliable? (差分约束)
    树状数组 讲解
    poj 2828 Buy Tickets (线段树)
    hdu 1166 敌兵布阵 (树状数组)
    Ubuntu网络配置
    Button控制窗体变量(开关控制灯的状态)
  • 原文地址:https://www.cnblogs.com/victorm/p/9218974.html
Copyright © 2011-2022 走看看