python模块


一.模块初识

  • 模块的分类
    • 内置模块
      • 安装python解释器的时候跟着装上的那些方法
    • 第三方模块
      • 没在安装怕python解释器的时候安装的那些功能
    • 自定义功能
      • 自己写的功能是一个通用的功能,可以当作是一个模块
  • 模块的定义
    • 有的功能开发者自己无法完成,这样的话需要借助已经实现的函数/类来完成这些功能
    • 自己实现不了的功能由别人代替了
      • 比如:和操作系统打交道
      • 和时间
      • 随机数
      • 压缩一个文件
      • 和网络通信
    • 别人写好的一组功能–> 文件夹/py文件/c语言编译好的一些编译文件
  • 模块的好处
    • 分类 管理方法
    • 节省内存
    • 提供更多的功能
  • 为什么要有模块?
    • 分类, 管理方法
    • 节省内存
    • 提供更多的功能
  • 模块的创建和导入
# 自定义模块,模块的创建
# py文件名-->my_module
print('这是我的模块')

name = 'alex'


def login():
    print('这是一个登录函数')


# 模块的导入
import my_module  # 要导入一个py文件的名字,但是不加.py后缀名
                    # 模块的名字必须要满足变量的命名规范
                    # 一般情况下,模块都是小写字母开头的名字
# import这个模块相当于执行了这个模块所在的py文件
# 模块不会被多次导入

# 模块的使用
my_module.login()
print(my_module.name)  # 直接调用导入进来模块的方法以及属性等等


# 模块的重命名
import my_module as m  # 语法  import 模块名 as 新名字
m.login()
print(m.name)


# 导入多个模块
import os
import my_module
# PEP8规范
# 所有的模块导入都应该尽量放在这个文件的开头
# 模块的导入也是有顺序的
    # 先导入内置模块
    # 再导入第三方模块
    # 最后导入自定义模块
  • from_import
    • from import的时候执行了什么??
      • 想当于执行了整个py文件
    • 导入了什么,就能是有什么, 不导入的变量, 不能使用
    • 不导入并不意味着不存, 而是没有建立文件到模块中其他名字的引用
    • 当模块中的方法或者变量 和 文件重名时, 那么这个名字只代表最后一次对他赋值的那个
    • 在本文件中对全局变量的修改是完全不影响模块中的变量引用的
  • 模块的重命名
from module1 import login as l1
  • 导入多个重命名
from module1 import login as l1, name as l2
  • from 模块 import *
__all__ = ['age']  #可以控制*导入的东西,这里只表示导入age

name = 'alex'
age = 19


def login():
    print('in my login')


def asd():
    print('in my asd')


if __name__ == '__main__':  # 所有测试语句方法在里面,在导入模块之后,执行脚本的时候就不会自动执行
    login()
    asd()


from module1 import *  # *表示导入模块中所有的变量和方法

print(age)
# print(name)
# asd()
# login()
  • pyc编译文件

    1. python的执行 —> 解释-编译
    2. 当一个文件作为一个脚本被导入的时候
    3. 就会在这个文件所在的目录的_ _ pycache _ _下生成一个编译好的文件
    4. 为了之后导入这个文件的时候直接读这个编译好的pyc文件
    5. 可以节省一些导入的时间
  • 运行一个py 文件的两中方式

    1. 以模块的形式运行
import my_module
if __name__ == '__main__':
    my_module.login()
  1. 直接pycharm运行 cmd运行

              1. 就是以脚本的方式运行
                       2. 那么需要在本文件中直接打印的代码上加上
                                3. if _ _ name _ _ = ['_ _ main _ _']
                                         4. 在编写py文件的时候
                                           1. 所有不在函数和类中封装的内容都应该写在
                                                       2. if _ _ name _ _ = ['_ _ main _ _'] : 下面
    import sys
    import module1
    
    print(sys.modules)  # 结果是: 存储了所有导入的文件的名字和这个文件的内存地址
    
    {sys : 文件的内存地址,'__main__' : 当前执行文件所在的地址}
    
    # 再次使用反射反射自己模块中的内容的时候
    import sys
    print(getattr(sys.modules[__name__], 'name'))

  • 模块搜索路径

    1. 模块没导入之前是在硬盘上的
    2. 模块的搜索路径全部存储在sys.path列表中
    3. 导入模块的顺序,是从前到后找到一个符合条件的模块就立即停止不再向后寻找
    4. 如果要导入的模块和当前执行文件是同级目录
      1. 直接导入即可
    5. 如果要导入的模块和当前执行的文件不是同级
      1. 需要吧导入的模块的绝对路径添加到sys.path 列表中
  • 重新加载模块

    • 在import之后 再修改这个被导入的模块, 程序是感知不到的
    • reload这种方法可以强制程序再重新导入这个模块一次(非常不推荐使用)
import module1
import time
import importlib
module1.login()
time.sleep(20)
importlib.reload(module1)  # 表示重新加载
module1.login()
  • 模块的循环使用
    1. 在模块的导入中, 不要产生循环引用问题
    2. 如果发生循环导入了, 就会发现明明写在这个模块中的方法, 显示找不到

二.包

  • 导入包相当于执行了这个包下面的 _ _ init _ _ 方法
  • 可以设 _ _ init _ _方法来完成一些模块的导入
  • 如果直接导入一个包, 那么相当于执行了这个包中的_ _ init _ _文件,并不会帮你把这个包下面的其他包以及py文件自动的导入到内存
# import bbb.api.policy
# bbb.api.policy.get()

import bbb.api.policy as a1
a1.get()
  1. 绝对导入和相对导入

    在glance/api/version.py
    
    #绝对导入
    from glance.cmd import manage
    manage.main()
    
    #相对导入
    from ..cmd import manage
    manage.main()

三.正则表达式

  • 定义: 就是一种匹配字符串的规则

  • 应用: 登录注册的表单验证,爬虫,自动化开发, 日志分析

  • 正则表达式是一种独特的语法,和python没有关系

  • 帮助学习工具 http://tool.chinaz.com/regex/

  1. 字符组 []
    1. 在一个字符的位置上能出现的内容
    2. [1abc] 是一个范围
    3. [0-9] [A-Z] [a-z] 表示匹配三个字符
    4. [abc0-9] 表示匹配一个字符
    5. [0-9a-zA-Z] 表示匹配一个字符
    6. [^] 非字符组
  2. 元字符
    1. \d == [0-9] 也表示匹配一个字符, 匹配的是一个数字
    2. \w == [0-9a-zA-Z] 也表示匹配一个数字字母下划线
    3. \s == [\n \t] 包括回车 空格 和 制表符tab \n匹配回车 \t 匹配制表符
    4. \D 匹配非数字
    5. \W 匹配非数字字母下划线
    6. \S 匹配非空白
    7. \b 匹配单词的开始或结束
    8. | 或者的意思
    9. () 分组的意思
    10. ^ 匹配字符串的开始
    11. & 匹配字符串的结束
    12. . 除了换行符的所有
    13. [\d\D] [\w\W] [\s\S] 匹配所有
  3. 量词
    1. ? 重复0次或者一次(也就是可有可无)
    2. +重复1次或者更多次(1~多次)
    3. *重复0次或者更多次(0~多次)
    4. {n} 重复n次
    5. {n,} 重复至少n次
    6. {n,m} 重复n到m次
  4. 其他
    1. 贪婪匹配(回溯算法) 尽可能的匹配多的
    2. 量词? 表示惰性匹配也就是取消贪婪匹配
      1. ?? *? +? {n}?
      2. 最常用 .*?x 表示任意字符找到一个x
  5. 正则表达式的例子
1.匹配任意长度的正整数
    [1-9]\d*
2.匹配小数
    -?\d+\.\d+
3.匹配整数或者小数
    -?\d+\.?\d*  有缺陷 1. 2. 这样的内容也会匹配上
    -?\d+\.?\d+  有缺陷 1 2 这样的一位数就匹配不上了
    -?\d+(\.\d+)? 准确的
4.匹配负数
    -0\.\d+|-[1-9]\d*(\.\d+)?
5.匹配qq号
    [1-9]\d{5,11}
6.匹配长度为11位的电话号码
    1[3-9]\d{9}
7.匹配长度为8-10位的用户密码 包含数字字母下划线和?@
    [\w?@]{8,10}
8.匹配验证码,4位数字字母组成的
    [\da-zA-Z]{4}
9.1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
匹配出最内层的小括号
    \([\d\.+\-*/]+\)
    \([^()]+\)

6.转义符

​ 1.正则表达式中的转义

​ ‘\ (‘ 表示转义小括号

     # [()+*?/$.]   在字符组中一些特殊的字符会现出原形
# 所有的 \w \d \s(\n,\t, )  \W \D \S都表示它原本的意义
# [-]只有写在字符组的首位的时候表示普通的减号
#    写在其他位置的时候表示范围[1-9]
#    如果就是想匹配减号 [1\-9]

​ 2.python中的转义

# 分析过程
'\n'  # \转义符 赋予这个n一个特殊的意义 表示一个换行符
# print('\\n')
# print\\n('C:\\next')
# print(r'C:\next')
# '\\\\n' '\\n'
# 结论
# r'\\n' r'\n'  在python中

四.re模块

​ 1.匹配

​ findall 和 search match

import re

# findall
# print(re.findall('\d', 'asdf23'))
# 参数 返回值类型(列表),返回值个数(1) 返回值内容:所有匹配上的内容

# search
ret = re.search('\d+', "afasdf1231adf212")  # 返回值类型: 正则匹配结果的对象  返回值个数:1 如果匹配上了就返回对象
print(ret.group())  # 返回的对象是通过group 来获取匹配到的第一个结果
如果没有匹配上,结果就是None

# match
ret1 = re.match('\d+', '*&1231afasdf1231adf212')  # 只匹配前面出现的,不然会报错
print(ret1.group())

​ 2.替换

​ sub 和 subn

# sub 和 replace是一样的
print(re.sub('\d+', 'H', '123FSDF52FSF1'))

# subn  会打印你替换了的次数
print(re.subn('\d+', 'H', '123FSDF52FSF1'))
结果:('HFSDFHFSFH', 3)
 3.切割

​ split

print(re.split('\d+', '123faaf23'))
# 会把数字不打印
# 结果是个列表 ['', 'faaf', '']

​ 4.进阶方法

​ compile(时间效率) 和 finditer(空间效率)

# compile 起到一个预编译的作用,只有多次使用某一个相同的正则表达式的时候,compile才会提高我们程序的效率
ret = re.compile('-0\.\d+|-[1-9]+(\.\d+)?')
res = ret.search('asdf-0.01-99')
print(res.group())

# finditer
ret = re.finditer('\d', 'adfad12fasdf123')  # 返回的是一个迭代器
print(ret)
for i in ret:
    print(i.group())

​ 5.python中的正则表达式

​ 1.findall 会优先显示分组中的内容,要想取消分组优先,(?:正则表达式)

​ 2.split 遇到分组 会保留分组内被切掉的内容

​ 3.search 如果search中有分组的话,通过group(n)就能够拿到group中的匹配的内容

ret = re.findall('-0\.\d+|-[1-9]\d*(?:\.\d+)?', '-1asdada-200')
print(ret)

ret = re.split('(\d+)','alex83egon20taibai40')
print(ret)

# 分组遇见search
ret = re.search('\d+(.\d+)(.\d+)(.\d+)?','1.2.3.4-2*(60+(-40.35/5)-(-4*3))')
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(3))
 6. 分组命名
      1. (?P< name > 正则表达式)  表示给分组起名字
      2. (?P=name) 表示使用这个分组,这里匹配到的内容应该和分组中的内容完全相同
7. 通过索引使用分组
        1. \1 表示使用第一组, 匹配到的内容和分组中的内容完全相同
import re
# ret=re.findall(r"\d+(?:\.\d+)?","1-2*(60+(-40.35/5)-(-4*3))")
# print(ret)

# ret=re.findall(r"\d+(?:\.\d+)|(\d+)","1-2*(60+(-40.35/5)-(-4*3))")
# print(ret)
# ret.remove('')
# print(ret)

import re
# ret = re.findall('>(\w+)<',r'<a>wahaha<\a>')
# print(ret)

# ret = re.search(r'<(\w+)>(\w+)</(\w+)>',r'<a>wahaha</b>')
# print(ret.group())
# print(ret.group(1))
# print(ret.group(2))



分组命名
ret = re.search("<(?P<name>\w+)>\w+</(?P=name)>","<h1>hello</h1>")
print(ret.group('name'))  #结果 :h1
# print(ret.group())  #结果 :<h1>hello</h1>

ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
print(ret.group(1))
# print(ret.group())  #结果 :<h1>hello</h1>

ret = re.search(r'<(?P<tag>\w+)>(?P<c>\w+)</(\w+)>',r'<a>wahaha</b>')
print(ret.group())
print(ret.group('tag'))
print(ret.group('c'))

五.爬虫练习

import re
from urllib.request import urlopen


# 内置的包,来获取网页的源代码 字符串

def getPage(url):
    reponse = urlopen(url)
    return reponse.read().decode('utf-8')


def parsePage(s):
    ret = com.finditer(s)
    for i in ret:
        ret = {
            "id": i.group("id"),
            "title": i.group("title"),
            "rating_num": i.group("rating_num"),
            "comment_num": i.group("comment_num")
        }
        yield ret


def main(num):
    url = 'https://movie.douban.com/top250?start=%s&filter=' % num
    reponse_html = getPage(url)
    ret = parsePage(reponse_html)
    print(ret)
    f = open('info1',encoding='utf-8')
    for obj in ret:
        print(obj)
        data = str(obj)
        f.write(data, '\n')

    f.close()

com = re.compile(
    '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
    '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)

count = 0
for i in range(10):
    main(count)
    count += 25

六.验证码代码

# 验证码
import random


def rand_code(n=6, flag=True):
    code = ''
    for i in range(n):
        rand_num = str(random.randint(0, 9))
        if flag == True:
            rand_alph = chr(random.randint(97, 122))  # 是根据ASCLL 表 获取小写字母,97-127(a-z)
            rand_alph_upper = chr(random.randint(65, 90))  # 是根据ASCLL表 获取大写字母 65-90(A-Z)
            rand_num = random.choice([rand_num, rand_alph, rand_alph_upper])
        code += rand_num
    return code


ret = rand_code(flag=False)
print(ret)

Author: 二哈君
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 二哈君 !
 Previous
网络编程 网络编程
一.网络基础​ 1.网络基础相关的知识 ​ (1) 架构 ​ a. C/S 架构 : client 客户端 和 server 服务器端 ​ 优势: 能充分发挥PC机的
2020-11-25 二哈君
Next 
Python Python
一.面向对象1.写代码的时候,什么时候用面向对象 代码量大,功能多的时候 处理比较复杂的角色之间的关系(面试可以这么说) qq 好友 陌生人 群 组 复杂的电商程序 公司/学校的人事管理/功能的系统 面向对象的好处 代码的清晰度更高了
2020-11-07 二哈君
  TOC