模块基础

定义模块

基本概念

  • 模块是从逻辑上组织python代码的形式
  • 当代码量变得相当大的时候,最好把代码分成一些有组织的代码段,前提是保证它们的 彼此交互
  • 这些代码片段相互间有一定的联系,可能是一个包含数据成员和方法的类,也可能是一组相关但彼此独立的操作函数
  • 人话:一个 .py文件 就是一个python模块

导入模块 (import)

  • 使用 import 导入模块
  • 模块属性通过 “模块名.属性” 的方式调用
  • 模块函数通过 “模块名.函数名” 的方式调用
  • 如果仅需要模块中的某些属性,也可以单独导入

为什么需要导入模块?

可以提升开发效率,简化代码

图例

1660052980503

正确使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# test.py,将 file_copy.py 放在同级目录下
# 需求:要将/etc/passwd复制到/tmp/passwd
src_path = "/etc/passwd"
dst_path = "/tmp/passwd"
# 如何复制?
# 调用已有模块中的方法
# - 很推荐,简单粗暴不动脑
# - 直接使用 file_copy.py的方法即可

# 导入方法一:直接导入模块
import file_copy # 要注意路径问题
file_copy.copy(src_path, dst_path)

# 导入方法二:只导入 file_copy 模块的 copy 方法
from file_copy import copy # 如果相同时导入多个模块 from file_copy import *
copy(src_path, dst_path)

# 导入方法三:导入模块起别名 as
import file_copy as fc # alias
fc.copy(src_path, dst_path)

常用的导入模块的方法

  • 一行指导入一个模块,可以导入多行, 例如:import random
  • 也可一行导入多个模块,例如:import random, sys
  • 只导入模块中的某些方法,例如:from random import choice, randint

模块加载 (load)

  • 一个模块只被 加载一次,无论它被导入多少次
  • 只加载一次可以 阻止多重导入时,代码被多次执行
  • 如果两个文件相互导入,防止了无限的相互加载
  • 模块加载时,顶层代码会自动执行,所以只将函数放入模块的顶层是最好的编程习惯

模块特性及案例

模块特性

模块在被导入时,会先完整的执行一次模块中的 所有程序

案例

1
2
3
4
5
# foo.py
print(__name__)

# bar.py
import foo # 导入foo.py,会将 foo.py 中的代码完成的执行一次,所以会执行 foo 中 print(__name__)

结果:

1
2
# foo.py   ->   __main__   当模块文件直接执行时,__name__的值为‘__main__’
# bar.py -> foo 当模块被另一个文件导入时,__name__的值就是该模块的名字

所以我们以后在 Python 模块中执行代码的标准格式:

1
2
3
4
def test():
......
if __name__ == "__main__":
test()

练习:生成随机密码

创建 randpass.py 脚本,要求如下:

  1. 编写一个能生成 8 位随机密码的程序
  2. 使用 random 的 choice 函数随机取出字符(大小写字母数字)
  3. 改进程序,用户可以自己决定生成多少位的密码

版本一:

1
2
3
4
5
6
7
8
9
10
import random  # 调用随机数模块random
# 定义变量all_chs,存储密码的所有选择;
# 定义变量result,存储8位随机数,初值为''
all_chs = '1234567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQLMNUVWXYZ'
result = ''
#使用for循环,循环8次,每次从all_chs中随机产生一个字符,拼接到result中
for i in range(8):
ch = random.choice(all_chs)
result += ch
print(result) # 输出结果,右键执行【Run 'randpass'】,查看结果

版本二(优化):函数化程序,并可以指定密码长度,在randpass.py文件中操作

1
2
3
4
5
6
7
8
9
10
11
12
import random  # 调用随机数模块random
# 定义变量all_chs,存储密码的所有选择;
all_chs = '1234567890abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQLMNUVWXYZ'
def randpass(n=8): # 使用def定义函数randpass(), 生成随机8位密码
result = ''
for i in range(n):
ch = random.choice(all_chs)
result += ch
return result # return给函数返回密码
if __name__ == '__main__': # 测试代码块,__name__作为python文件调用时,执行代码块
print(randpass(8))
print(randpass(4))

版本三:随机密码的字符选择可以调用模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 调用随机数模块random
# string模块中的变量ascii_letters和digits中,定义了大小写字母和所有数字
import random
from string import ascii_letters, digits
# 定义变量all_chs,存储密码的所有选择;
all_chs = ascii_letters + digits
# 使用def定义函数randpass(), 生成随机8位密码
def randpass(n=8):
result = ''
for i in range(n):
ch = random.choice(all_chs)
result += ch
return result # return给函数返回密码
# 测试代码块,__name__作为python文件调用时,执行代码块
if __name__ == '__main__':
print(randpass(8))
print(randpass(4))

时间模块

time 模块

时间表示方式

  • 时间戳 timestamp:表示的是从 1970 年1月1日 00:00:00 开始按秒计算的偏移量
  • UTC(Coordinated Universal Time, 世界协调时)亦即格林威治天文时间,世界标准时间。在中国为 UTC+8 DST(Daylight Saving Time) 即夏令时;
  • 结构化时间(struct_time): 由 9 个元素组成

结构化时间(struct_time)

使用 time.localtime() 等方法可以获得一个结构化时间

1
2
3
>>> import time
>>> time.localtime()
time.struct_time(tm_year=2021, tm_mon=9, tm_mday=1, tm_hour=14, tm_min=23, tm_sec=29, tm_wday=2, tm_yday=244, tm_isdst=0)

结构化时间共有9个元素,按顺序排列如下表:

索引 属性 取值范围
0 tm_year(年) 比如 2021
1 tm_mon(月) 1 - 12
2 tm_mday(日) 1 - 31
3 tm_hour(时) 0 - 23
4 tm_min(分) 0 - 59
5 tm_sec(秒) 0 - 59
6 tm_wday(weekday) 0 - 6(0表示周一,6表示周日)
7 tm_yday(一年中的第几天) 1 - 366
8 tm_isdst(是否是夏令时) 默认为-1

然结构化时间是一个序列,那么就可以通过索引进行取值,也可以进行分片,或者通过属性名获取对应的值。

1
2
3
4
5
6
7
8
9
10
>>> import time
>>> t = time.localtime()
>>> t
time.struct_time(tm_year=2021, tm_mon=9, tm_mday=1, tm_hour=14, tm_min=23, tm_sec=29, tm_wday=2, tm_yday=244, tm_isdst=0)
>>> t[3]
14
>>> t[1:3]
(9, 1)
>>> t.tm_mon
9

注意

但是要记住,Python的time类型是不可变类型,所有的时间值都只读,不能改

1
2
3
4
>>> t.tm_mon = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute

格式化时间字符串

利用 time.strftime('%Y-%m-%d %H:%M:%S') 等方法可以获得一个格式化时间字符串

1
2
3
>>> import time
>>> time.strftime('%Y-%m-%d %H:%M:%S')
'2021-09-01 02:39:23'

注意其中的空格、短横线和冒号都是美观修饰符号,真正起控制作用的是百分符

对于格式化控制字符串 "%Y-%m-%d %H:%M:%S,其中每一个字母所代表的意思如下表所示,注意大小写的区别:

格式 含义 格式 含义
%a 本地简化星期名称 %m 月份(01 - 12)
%A 本地完整星期名称 %M 分钟数(00 - 59)
%b 本地简化月份名称 %p 本地am或者pm的相应符
%B 本地完整月份名称 %S 秒(01 - 59)
%c 本地相应的日期和时间 %U 一年中的星期数(00 – 53,星期日是一个星期的开始)
%d 一个月中的第几天(01 - 31) %w 一个星期中的第几天(0 - 6,0是星期天)
%H 一天中的第几个小时(24小时制,00 - 23) %x 本地相应日期
%I 第几个小时(12小时制,01 - 12) %X 本地相应时间
%j 一年中的第几天(001 - 366) %y 去掉世纪的年份(00 - 99)
%Z 时区的名字 %Y 完整的年份

time 模块主要方法

1. time.sleep(t)

time 模块最常用的方法之一,用来睡眠或者暂停程序t秒,t可以是浮点数或整数。

1
2
3
4
5
6
7
import time
# 1. time.sleep(t): 用来睡眠或者暂停程序t秒
def banzhuan():
print("start...")
time.sleep(3) # 3s
print("end...")
banzhuan() # 调用函数

2. time.time()

返回当前系统时间戳。时间戳可以做算术运算。

1
2
3
4
5
6
7
8
9
10
11
12
import time
# 1. time.sleep(t): 用来睡眠或者暂停程序t秒
def banzhuan():
print("start...")
time.sleep(3) # 3s
print("end...")
# 2. time.time(): 返回当前系统时间戳,可以做算术运算
# print(time.time()) # 1656314125.2967942
start_time = time.time() # 记录开始的时间
banzhuan() # 调用函数
end_time = time.time() # 记录结束的时间
print("耗时:", end_time-start_time)

3. time.gmtime([secs])

将一个时间戳转换为 UTC时区的结构化时间。可选参数secs的默认值为 time.time()

1
2
3
4
5
6
import time
t1 = time.gmtime() # time.gmtime(time.time())
print(t1)
print(t1[0], t1[1], t1[2]) # 年份 月份 日
print(t1[:3]) # (年份 月份 日)
print(t1.tm_hour, t1.tm_min, t1.tm_sec) # 时 分 秒

4. time.localtime([secs])

将一个时间戳转换为 当前时区 的结构化时间。如果secs参数未提供,则以当前时间为准,即time.time()

1
2
3
4
5
6
import time
t2 = time.localtime(time.time()+60*60)
print(t2)
print(t2[0], t2[1], t2[2]) # 年份 月份 日
print(t2[:3]) # (年份 月份 日)
print(t2.tm_hour, t2.tm_min, t2.tm_sec) # 时 分 秒

5. time.mktime(t)

结构化时间转换为时间戳,t(结构化时间)

1
2
3
import time
t3 = time.mktime(time.localtime())
print(t3) # 1656316578.0

6. time.strftime(format [, t])

返回格式化字符串表示的当地时间。把一个struct_time(如time.localtime()time.gmtime()的返回值)转化为格式化的时间字符串,显示的格式由参数format决定。如果未指定t,默认传入time.localtime()

1
2
3
4
import time
# %Y:年 %m:月 %d:日 %H:小时 %M:分钟 %S:秒
t4 = time.strftime("%Y-%m-%d %H:%M:%S")
print("t4:", t4) # 2022-06-27 16:20:27

7. time.strptime(string[,format])

将格式化时间字符串转化成结构化时间

  • 该方法是 time.strftime()方法的逆操作。
  • time.strptime() 方法根据指定的格式把一个时间字符串解析为结构化时间。
  • 提供的字符串要和 format参数 的格式一一对应
    • 如果string中日期间使用 “-” 分隔,format中也必须使用“-”分隔
    • 时间中使用冒号 “:” 分隔,后面也必须使用冒号分隔
  • 并且值也要在合法的区间范围内
1
2
3
4
5
6
import time
t5 = time.strptime("2099-06-09 13:13:13","%Y-%m-%d %H:%M:%S")
print(t5)
t6 = time.strptime("2011-12-12", "%Y-%m-%d")
print(t6)
print(t5 > t6) # True 结构化时间越靠后的越大

时间格式之间的转换

Python的三种类型时间格式,可以互相进行转换

方法
时间戳 UTC结构化时间 gmtime()
时间戳 本地结构化时间 localtime()
本地结构化时间 时间戳 mktime()
结构化时间 格式化字符串 strftime()
格式化字符串 结构化时间 strptime()

练习:取出指定时间段的日志

需求

  1. 有一日志文件,按时间先后顺序记录日志

  2. 给定 时间范围,取出该范围内的日志

  3. 自定义日志文件 myweb.log

    1
    2
    3
    4
    5
    6
    7
    [root@localhost ~]# vim /opt/myweb.log
    2030-01-02 08:01:43 aaaaaaaaaaaaaaaaa
    2030-01-02 08:34:23 bbbbbbbbbbbbbbbbbbbb
    2030-01-02 09:23:12 ccccccccccccccccccccc
    2030-01-02 10:56:13 ddddddddddddddddddddddddddd
    2030-01-02 11:38:19 eeeeeeeeeeeeeeee
    2030-01-02 12:02:28 ffffffffffffffff

    【方案一】

1
2
3
4
5
6
7
8
9
10
11
12
13
# 取出指定时间段 [9点~12点] 的行
import time
# strptime(), 将字符时间'2030-01-02 09:00:00',转换成时间对象
t9 = time.strptime('2030-01-02 09:00:00', '%Y-%m-%d %H:%M:%S')
t12 = time.strptime('2030-01-02 12:00:00', '%Y-%m-%d %H:%M:%S')

# 读取日志文件myweb.log中的数据
with open('myweb.log', mode="r") as fobj:
for line in fobj.readlines():
# strptime(), 将line[:19]截取的字符时间,转换成时间对象
t = time.strptime(line[:19], '%Y-%m-%d %H:%M:%S')
if t9 <= t <= t12: # 此种判断会遍历日志文件中的每一行,有可能执行大量无效操作,效率低下
print(line, end='')

【方案二】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 日志文件中,时间点是从前往后不断增加的,所以只要遍历到有一行时间超过预计,则后面的所有行均是不满足条件的
import time
# strptime(), 将字符时间'2030-01-02 09:00:00',转换成时间对象
t9 = time.strptime('2030-01-02 09:00:00', '%Y-%m-%d %H:%M:%S')
t12 = time.strptime('2030-01-02 12:00:00', '%Y-%m-%d %H:%M:%S')

with open('myweb.log', mode="r") as fobj: # 读取日志文件myweb.log中的数据,逐行进行遍历
for line in fobj.readlines():
# strptime(), 将line[:19]截取的字符时间,转换成时间对象
t = time.strptime(line[:19], '%Y-%m-%d %H:%M:%S')
if t > t12: # 当时间大于12点时,退出循环
break
if t >= t9: # 当时间大于9点时,打印对应行
print(line, end='')

python 语法风格和模块布局

变量赋值

1. python支持链式多重赋值

1
2
3
4
5
>>> x = y = 10  # 将10赋值给x和y
>>> x # 查看x的值
10
>>> y # 查看y的值
10

2. 给列表使用多重赋值时,两个列表同时指向同一个列表空间,任何一个列表改变,另外一个随着改变

1
2
3
4
5
6
7
8
>>> alist = blist = [1, 2]
>>> alist # 查看列表alist的值
[1, 2]
>>> blist # 查看列表blist的值
[1, 2]
>>> blist[-1] = 100 # 修改列表blist中的最后一个元素为100
>>> alist # 当列表blist改变时,alist也会改变
[1, 100]

3. python 的多元赋值方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> a, b = 10, 20  # 将10和20, 分别赋值给a和b
>>> a # 查看变量a的值
10
>>> b # 查看变量a的值
20
>>> c, d = 'mn' # 将m和n, 分别赋值给c和d
>>> c # 查看变量c的值
'm'
>>> d # 查看变量d的值
'n'
>>> e,f = (100, 200) # 将元组中的元素, 分别赋值给e和f
>>> e # 查看变量e的值
100
>>> f # 查看变量f的值
200
>>> m, n = ['bob', 'alice'] # 将列表中的元素,分别赋值给变量m和变量n
>>> m # 查看变量m的值
'bob'
>>> n # 查看变量n的值
'alice'

4. 在python中,完成两个变量值的互换

1
2
3
4
5
6
>>> a, b = 100, 200  # 将100和200,分别赋值给变量a和变量b
>>> a, b = b, a # 将变量a和变量b的值,进行交换
>>> a # 查看变量a的值
200
>>> b # 查看变量b的值
100

合法标识符

  • Python 标识符,字符串规则和其他大部分用 C 编写的高级语言相似
  • 第一个字符必须是 字母或下划线 _
  • 剩下的字符可以是字母和数字或下划线
  • 大小写敏感

关键字

  • 和其他的高级语言一样,python 也拥有一些被称作关键字的保留字符
  • 任何语言的关键字应该保持相对的稳定,但是因为 python 是一门不断成长和进化的语言,其关键字偶尔会更新
  • 关键字列表和 iskeyword() 函数都放入了 keyword 模块以便查阅

案例:查看,判断python中的关键字

1
2
3
4
5
6
>>> import keyword  # 导入模块keyword
>>> keyword.kwlist # 查看keyword模块中,包含的关键字
>>> 'pass' in keyword.kwlist # 判断 'pass' 是否是python中的关键字,是
True
>>> keyword.iskeyword('abc') # 判断 'abc' 是否是python中的关键字,否
False

内建

  • Python 为什么可以直接使用一些内建函数,而不用显式的导入它们?
  • 比如 str()、int()、id()、type(),len() 等,许多许多非常好用,快捷方便的函数。
  • 这些函数都是一个叫做 builtins 模块中定义的函数,而 builtins 模块默认 在Python环境启动的时候就自动导入,所以可以直接使用这些函数

字符串

格式化详解

  • 百分号:可以使用格式化符号来表示特定含义
格式化字符 转换方式
%s 优先用str()函数进行字符串转换
  • f 字符串:是 Python3.6 之后加入的标准库
1
2
3
4
5
6
7
8
9
10
11
name, age, list01 = "benben", 25, [1, 2]
# name: benben, age: 25
# 拼接
str01 = "name: " + name + ", age: " + str(age)
print(str01)
# 1. %s
str02 = "name: %s, age: %s, %s" % (name, age, list01)
print(str02)
# 2. f字符串
str03 = f"name: {name}, age: {age}, {list01}"
print(str02)

注意

  • 可以传入任意类型的数据,如 整数、浮点数、列表、元组甚至字典,都会自动转成字符串类型

字符串函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
>>> s1 = "hello world"
>>> s1.startswith('abc') #判断字符串s2,是否是以'abc'开头的,False
>>> s1.startswith('h') #判断字符串s2,是否是以'h'开头的,True
>>> s1.startswith('he') #判断字符串s2,是否是以'he'开头的,True
>>> s1.endswith('abc') #判断字符串s2,是否是以'abc'结尾的,False
>>> s1.endswith('rld') #判断字符串s2,是否是以'rld'结尾的,True

# 判断字符串,经常使用is..进行判断
>>> s2 = 'hello world' #定义一个变量s2
>>> s3 = 'HELLO WORLD' #定义一个变量s3
>>> s2.islower() #判断变量s2,是否都是小写字母,True
>>> s3.isupper() #判断变量s3,是否都是大写字母,True

# string.strip(): 删除 string 字符串两端的空白
# string.upper(): 转换string 中的小写字母为大写
# string.split("xxxx"): 以指定字符串为分隔符切分string
# 删除 string 字符串两端的空白
>>> s4 = ' hello world '
>>> print(s4) #打印s4
>>> s4.strip() #去掉变量s4,左右两边的空白字符
>>> s4.lstrip() #去掉变量s4,左边的空白字符,右边空白字符保留
>>> s4.rstrip() #去掉变量s4,右边的空白字符,左边空白字符保留

# 切割字符串,拼接字符串
>>> s2 = 'hello world' #定义一个字符串变量s2
>>> s3 = 'hello.tar.gz' #定义一个变量s3
>>> s2.split() #切割字符串s2, 存入列表中,默认以空格作为分隔符进行切割
>>> s3.split('.') #切割字符串s3, 存入列表中,这里以'.'作为分隔符进行切割
>>> alist = ['tom', 'bob', 'alice'] #定义一个列表alist
>>> '_'.join(alist) #以'_'作为连接符,将列表alist中的元素拼接在一起
>>> ' '.join(alist) #以'.'作为连接符,将列表alist中的元素拼接在一起
更新于

请我喝[茶]~( ̄▽ ̄)~*

Chen 微信支付

微信支付

Chen 支付宝

支付宝

Chen 贝宝

贝宝