03 模块

模块

模块介绍

"""
什么是模块: 一系列功能的结合体
模块的三种来源: 
	1.内置的(python解释器自带)
	2.第三方的(别人写的)
	3.自定义的(自己写的)
模块的四种表现形式: 
	1.使用python编写的py文件(也就意味着py文件也可以称之为模块)
	2.已被编译为共享库或DLL的C或C++扩展(了解)
	3.把一系列模块组织到一起的文件夹(文件夹下有一个__init__.py文件,该文件夹称之为包,即一系列py文件的结合体)
	4.使用C编写并连接到python解释器的内置模块

为什么要用模块: 
    1.用别人写好的模块(内置的,第三方的): 典型的拿来主义,极大的提高开发效率
    2.用自己写的模块(自定义的): 当程序比较庞大时,项目不可能只在一个py文件中,当多个文件中都需要使用相同的方法时,可以将该公共的方法写到一个py文件中,其他文件中以模块的形式导过去直接调用即可
"""

模块导入

import 导入模块

"""
# run.py文件中导入md.py
import md
    运行run.py文件首先会创建一个run.py的名称空间
        首次导入模块(md.py)(******)
            1.执行md.py文件
            2.运行md.py文件中的代码将产生的名字与值存放到md.py名称空间中
            3.在执行文件(run.py)中产生一个指向md.py名称空间的名字md
        多次导入不会再执行模块文件,会用第一次导入的成果(******)

使用import导入模块,访问模块的名称空间中的名字: 模块名.名字,不加模块名前缀则会报错

只有当几个模块有相同部分或者属于用一个模块,才可以导入时写在同一行,import os,time,md
当几个模块没有联系的情况下,应分多次导入
    import os
    import time
    import md

当模块名字比较复杂的情况下,可以给该模块名取别名
    import testttttt as t
"""

from...import...

"""
# run1.py文件中导入md1.py
from md1 import money
    会先创建run1.py的名称空间
        首次导入md1.py模块
            1.运行md1.py
            2.将产生的名字存放到md1.py名称空间中
            3.拿到指向模块md1.py名称空间中名字money
        多次导入不会再执行模块文件,会用第一次导入的成果
# from md1 import *
在md1.py尾部加个__all__ = ['money','read1','read2'],不写change,则导入的时候拿不到拿不到,不写默认所有名字
              
from...import...句式缺点: 
	1.访问模块中的名字不需要加模块名前缀,加了会报错
	2.访问模块中的名字可能会与当前执行文件中的名字冲突

补充
__all__可以指定当所在py文件被当做模块导入的时候,可以限制导入者能够拿到的名字个数,不写默认所有名字
from md1 import *  # 一次性将md1模块中的__all__中的所以名字导入过来,不推荐使用,并且你根本不知道到底有哪些名字可以用

"""

解决循环导入问题

# m1.py
print('正在导入m1')
from m2 import y  # 首次导入m2
x = 'm1'

# 方式1
print('正在导入m1')
x = 'm1'
from m2 import y  # 首次导入m2

# 方式2
print('正在导入m1')
def f1(): 
  from m2 import y,f2
  print('m1.f1>>>y: ',y)
  f2()
x = 'm1'



# m2.py
print('正在导入m2')
from m1 import x  # 第二次导m1
y = 'm2'

# 方式1
print('正在导入m2')
y = 'm2'
from m1 import x  # 第二次导m1

# 方式2
print('正在导入m2')
def f2(): 
  from m1 import x
  print('m2.f2>>>x: ',x)
y = 'm2'



# run.py
import m1  # 首次导入m1
m1.f1()



"""
如果出现循环导入问题,那么一定是你的程序设计的不合理,循环导入问题在程序设计阶段就应该避免

解决循环导入问题的方式: 
    1.方式1: 将循环导入句式写在文件最下方
    2.方式2: 函数内导入模块
"""

模块的绝对导入与相对导入

"""
绝对导入: 依据执行文件所在的文件夹路径为准,绝对导入无论在执行文件中还是在被导入文件中都适用
    
相对导入
    .代表当前路径
    ..代表上一级路径
    ...代表上上一级路径
	注意: 
    相对导入不能在执行文件中使用,只能在被导入的模块中使用
    使用相对导入,就不需要考虑执行文件到底是谁,只需要知道模块与模块之间路径关系
"""

__name__用法

# 当文件被当做执行文件执行时,__name__打印的结果是__main__
# 当文件被当做模块导入时,__name__打印的结果是模块名(没有py后缀)
print(__name__)


# 当py文件被执行时调用函数,被导入时不操作
if __name__ == '__main__':   # 快捷写法: 输入main直接tab键
    index1()

模块查找顺序

"""
模块的查找顺序
    1.内存
    2.内置
    3.sys.path(环境变量): 是一个动态变化的大列表,里面放了一堆文件路径,第一个路径永远是执行文件所在的文件夹
    	 import sys
		 print(sys.path)  # ['E: \\python学习\\python视频教程\\day14\\代码\\day14\\07 模块查找顺序',...]

注意: py文件名不应该与模块名(内置的,第三方的)冲突
"""


# 导入dir1/dir下的md文件
# 方法一: 
from dir1.dir import md  # import前的A.B,A一定是文件夹,B可以是文件夹也可以是文件,import后面可以是文件也可以是文件里的名字
# 方法二: 
import sys
sys.path.append(r'E: \\python学习\\python视频教程\\day14\\代码\\day14\\07 模块的查找顺序\\dir1')
print(sys.path)  # [...,'E: \\\\python学习\\\\python视频教程\\\\day14\\\\代码\\\\day14\\\\07 模块的查找顺序\\\\dir1']
from dir import md

"""
什么是包?
    一系列模块文件的结合体,表示形式就是一个文件夹
    该文件夹内通常会有一个__init__.py文件
    包的本质还是模块

首次导入包: 
    1.先创建执行文件的名称空间
    2.创建包下面的__init__.py文件的名称空间
    3.执行包下面的__init__.py文件中的代码,将产生的名字放在包下面的__init__.py文件的名称空间中
    4.在执行文件中拿到一个指向包下面的__init__.py文件的名称空间的名字

在导入语句中,.号的左边肯定是包(文件夹)

作为包的设计者来说: 
    1.当模块的功能特别多的情况下,应该分文件管理
    2.模块之间可以使用相对导入(包里面的文件都应该是被导入的模块)

站在包的开发者,如果使用相对路径来管理的自己的模块,那么只需要以包的路径为基准依次导入模块
站在包的使用者,必须将包所在的文件夹路径添加到system path中(******)

python2如果要导入包,包下面必须要有__init__.py文件
python3如果要导入包,包下面没有__init__.py文件也不会报错

包导入示例见day17
"""
"""
目录结构:
    p目录
        __init__.py
        m1.py
        m2.py
        dir目录
            __init__.py
            m3.py
    start.py
"""

# m1.py
def f1():
    print("from m1 f1")
    
# m2.py
def f2():
    print('from m2 f2')    
    
# m3.py
def f3():
    print('from m3 f3')    
    
# p/dir/__init__.py
# from p.dir.m3 import f3  # 绝对导入
from .m3 import f3  # 相对导入

# p/__init__.py
# from p.m1 import f1  # 绝对导入
# from p.m2 import f2
# from p.dir import f3
from .m1 import f1  # 相对导入
from .m2 import f2
from .dir import f3

# start.py
from p import f1
from p import f2
from p import f3
f1()
f2()
f3()    

# start.py执行结果
"""
from m1 f1
from m2 f2
from m3 f3
"""     

常用模块

re模块

正则表达式

"""
在python中使用正则表达式,就必须依赖于re模块
正则的应用场景: 
    1.爬虫
    2.数据分析
"""



# 正则表达式
"""
[]
.
^
$
|    一定要将长的放在前面,如: abc|ab
[^]
*
+
?
{n}
{n+}
{n,m}
()    当多个正则符号需要重复多次或者当做一个整体进行其他操作,那么可以分组的形式
\     转义符,如匹配字符'\d': \\d,配置'\\d': \\\\d
r     转义符(python独有),如匹配字符'\d': r'\\d'
\w    字母数字下划线
\s    任意空白符
\d    数字
\W    非字母数字下划线
\S    非任意空白符
\D    非数字
\n    换行符
\t    制表符
\b    一个单词的结尾,如l\b: 以l结尾的单词

通过在量词(* + ? {n} {n+} {n,m}等)后面加上?就可以将贪婪匹配变成非贪婪匹配(惰性匹配)
"""

re模块findall、search、match方法

"""
findall
    re.findall('正则表达式','需匹配的字符串')
    找出字符串中符合正则表达式的全部内容,返回的是一个列表 
search
    re.search('正则表达式','需匹配的字符串')
    search不会直接返回匹配到的结果,而是返回一个对象,必须调用group才能看到匹配到的结果
    search只会依据正则查一次,只要查到了结果,就不会再往后查找
    当查找的结果不存在的情况下,调用group直接报错(因为不存在返回的是None,None没有group方法) 
match
    re.match('正则表达式','需匹配的字符串')
    match不会直接返回匹配到的结果,而是返回一个对象,必须调用group才能看到匹配到的结果
    match只会匹配字符串的开头部分
    当字符串的开头不符合匹配规则的情况下,返回的也是None,调用group也会报错
"""

import re

res = re.findall('[a-z]+','eva egon jason')
print(res)  # ['eva', 'egon', 'jason']

res = re.search('a','eva egon jason')
print(res)  # <re.Match object; span=(2, 3), match='a'>
print(res.group())  # a
# 解决search查找不存在返回None调用group报错
res1 = re.search('b','eva egon jason')
if res1: 
    print(res1.group())

res = re.match('eva','eva egon jason')
print(res)  # <re.Match object; span=(0, 3), match='eva'>
print(res.group())  # eva


# findall、search、match分组

# search、match分组用法一样
res = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199812067023')
# 给某一个正则表达式起别名
res1 = re.search('^[1-9](?P<password>\d{14})(?P<username>\d{2}[0-9x])?$','110105199812067023')
print(res.group())  # 110105199812067023
print(res1.group('password'))  # 10105199812067
print(res1.group(1))  # 10105199812067
print(res1.group('username'))  # 023
print(res1.group(2))  # 023

# findall的分组
ret1 = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
ret2 = re.findall('www.(?: baidu|oldboy).com', 'www.oldboy.com')  # 取消分组优先的机制
print(ret1,ret2)  # ['oldboy'] ['www.oldboy.com'] findall会优先把分组匹配结果返回,如果想要匹配所有,取消分组优先的机制

re模块其他方法

# re.split() 分割
ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
print(ret)  # ['', '', 'cd'] 返回的是列表
ret1=re.split("\d+","eva3egon4yuan")
print(ret1)  # ['eva', 'egon', 'yuan']
ret2=re.split("(\d+)","eva3egon4yuan")
print(ret2)  # ['eva', '3', 'egon', '4', 'yuan']


# re.sub() 替换,返回替换后的字符串
ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)  # 将数字替换成'H',参数1表示只替换1个
print(ret)  # evaHegon4yuan4
re.sub('正则表达式','新的内容','待替换的字符串',要替换的个数)


# re.subn() 替换,返回元组
ret = re.subn('\d', 'H', 'eva3egon4yuan4')  # 将数字替换成'H',返回元组(替换的结果,替换了多少个)
ret1 = re.subn('\d', 'H', 'eva3egon4yuan4',1)  # 指定替换的个数
print(ret)  # ('evaHegonHyuanH', 3),返回的是元组,元组的第二个元素代表替换的个数
print(ret1)  # ('evaHegon4yuan4', 1)


# re.compile() 将正则表达式编译成一个正则表达式对象
obj = re.compile('\d{3}')  
ret = obj.search('12a345bb6789ccc')  #正则表达式对象调用search,参数为待匹配的字符串
res1 = obj.findall('12a345bb6789ccc')
print(ret.group())  # 345
print(res1)  # ['345', '678']


# re.finditer() 返回一个存放匹配结果的迭代器
ret = re.finditer('\d', 'jll98')
print(ret)  # <callable_iterator object at 0x000001EB33C174F0>
print(ret.__next__().group())  # 9
print(next(ret).group())  # 8 等价于ret.__next__()
print(next(ret).group())  # 报错StopIteration
print([i.group() for i in ret])  # ['9', '8'] 查看所有结果

正则在爬虫中的应用

"""
拿到豆瓣电影TOP250的电影的排名、电影名、评分、评价人数
{'id':  '1', 'title':  '肖申克的救赎', 'rating_num':  '9.6', 'comment_num':  '1489907人'}

一共十页,每页25个电影: 
第一页url:  https: //movie.douban.com/top250?start=0&filter=
第一页url:  https: //movie.douban.com/top250?start=25&filter=
第一页url:  https: //movie.douban.com/top250?start=50&filter=
第一页url:  https: //movie.douban.com/top250?start=75&filter=


<li>
            <div class="item">
                <div class="pic">
                    <em class="">1</em>
                    <a href="https: //movie.douban.com/subject/1292052/">
                        <img width="100" alt="肖申克的救赎" src="https: //img2.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" class="">
                    </a>
                </div>
                <div class="info">
                    <div class="hd">
                        <a href="https: //movie.douban.com/subject/1292052/" class="">
                            <span class="title">肖申克的救赎</span>
                                    <span class="title">&nbsp;/&nbsp;The Shawshank Redemption</span>
                                <span class="other">&nbsp;/&nbsp;月黑高飞(港)  /  刺激1995(台)</span>
                        </a>


                            <span class="playable">[可播放]</span>
                    </div>
                    <div class="bd">
                        <p class="">
                            导演:  弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演:  蒂姆·罗宾斯 Tim Robbins /...<br>
                            1994&nbsp;/&nbsp;美国&nbsp;/&nbsp;犯罪 剧情
                        </p>

                        
                        <div class="star">
                                <span class="rating5-t"></span>
                                <span class="rating_num" property="v: average">9.7</span>
                                <span property="v: best" content="10.0"></span>
                                <span>2582438人评价</span>
                        </div>

                            <p class="quote">
                                <span class="inq">希望让人自由。</span>
                            </p>
                    </div>
                </div>
            </div>
        </li>
"""


import re
import json
from urllib.request import urlopen

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

def parsePage(s): 
    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)

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

def main(num): 
    url = 'https: //movie.douban.com/top250?start=%s&filter=' % num
    response_html = getPage(url)
    ret = parsePage(response_html)
    print(ret)
    f = open("move_info7", "a", encoding="utf8")

    for obj in ret: 
        print(obj)
        data = str(obj)
        f.write(data + "\n")

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

collections模块

"""
基本数据类型: 
    整型
    浮点型
    字符串
    列表
    布尔
    元组
    字典
    集合
    
conllections模块提供了几个额外的数据类型: 
	namedtuble 具名元组
	deque 双端队列(queue 队列)
	OrderedDict 有序字典
	defaultdict 默认值字典
	Counter 计数,统计字符串中每个字符出现的次数
"""


# namedtuble 具名元组,可以使用名字来访问元素内容的tuple
# 表示坐标点x为1 y为2 z为5的坐标
from collections import namedtuple
point = namedtuple('坐标',['x','y','z'])  # 第二个参数既可以传可迭代对象
point1 = namedtuple('坐标','x y z')  # 也可以传字符串,但是字符串之间以空格隔开
p = point(1,2,5)  # 元素的个数必须跟namedtuple第二个参数个数一致
p1 = point(1,2,5)
print(p)  # 坐标(x=1, y=2, z=5)
print(p1)  # 坐标(x=1, y=2, z=5)
print(p.x)  # 1
print(p.y)  # 2
print(p.z)  # 5



# queue 队列: 先进先出
import queue
q = queue.Queue()  # 生成队列对象
q.put('first')  # 往队列中添加值
q.put('second')
q.put('third')
print(q.get())  # first 队列取值
print(q.get())  # second
print(q.get())  # third
print(q.get())  # 如果队列中的值取完了,程序会在原地等待,直到从队列中拿到值才停止

# deque 双端队列,两端都能进值两端都能取值
"""
append 右追加
appendleft 左追加
pop 右取值
popleft 左取值
insert 特殊点: 双端队列可以根据索引在任意位置插值
    队列不应该支持任意位置插值
    只能在首尾插值(不能插队)
"""
from collections import deque
q = deque(['a','b','c'])
q.append(1)
q.appendleft(2)
q.insert(1,'哈哈哈')
print(q.pop())  # 1
print(q.popleft())  # 2
print(q.popleft())  # 哈哈哈



# OrderedDict 有序字典
from collections import OrderedDict
order_d = OrderedDict([('a',1),('b',2),('c',3)])
print(order_d)  # OrderedDict([('a', 1), ('b', 2), ('c', 3)])
order_d1 = OrderedDict()
print(order_d1)  # OrderedDict()
order_d1['x'] = 1
order_d1['y'] = 2
order_d1['z'] = 3
print(order_d1)  # OrderedDict([('x', 1), ('y', 2), ('z', 3)])



# defaultdict 默认值字典
from collections import defaultdict
values = [11, 22, 33, 44, 55, 66, 77, 88, 99]
my_dict = defaultdict(list)  # 后续该字典中新建的key对应的value默认就是列表
for value in values: 
    if value>66: 
        my_dict['k1'].append(value)
    else: 
        my_dict['k2'].append(value)
print(my_dict)  # defaultdict(<class 'list'>, {'k2':  [11, 22, 33, 44, 55, 66], 'k1':  [77, 88, 99]})

my_dict1 = defaultdict(int)
print(my_dict1['xxx'])  # 0

my_dict2 = defaultdict(bool)
print(my_dict2['kkk'])  # False

my_dict3 = defaultdict(tuple)
rint(my_dict3['mmm'])  # ()



# Counter 计数,统计字符串中每个字符出现的次数
m collections import Counter
s = 'jll990108jll'
print(Counter(s

时间模块

time模块

"""
三种表现形式: 
    1.时间戳
    2.格式化时间(用来展示给人看)
    3.结构化时间
"""

import time

# 时间戳
print(time.time())  # 1640647415.0789206

# 格式化时间
print(time.strftime('%Y-%m-%d'))  # 2021-12-28
print(time.strftime('%Y-%m-%d %H: %M: %S'))  # 2021-12-28 07: 25: 04
print(time.strftime('%Y-%m-%d %X'))  # 2021-12-28 07: 26: 07 %X等价于%H: %M: %S

# 结构化时间
print(time.localtime())  # time.struct_time(tm_year=2021, tm_mon=12, tm_mday=28, tm_hour=7, tm_min=28, tm_sec=12, tm_wday=1, tm_yday=362, tm_isdst=0)

# 形式转换
res = time.localtime(time.time())  # 时间戳转为结构化时间
print(res)  # time.struct_time(tm_year=2021, tm_mon=12, tm_mday=28, tm_hour=7, tm_min=45, tm_sec=17, tm_wday=1, tm_yday=362, tm_isdst=0)
print(time.mktime(res))  # 结构化时间转为时间戳
res1 = (time.strftime('%Y-%m-%d',time.localtime()))  # 结构化时间转为格式化时间
print(time.strptime(res1,'%Y-%m-%d'))  # 格式化时间转为结构化时间

# 暂停几秒
time.sleep(3)

datetime模块

import datetime

print(datetime.date.today())  # 2021-12-28 date->: 年月日
print(datetime.datetime.today())  # 2021-12-28 17: 40: 57.392492 datetime->: 年月日 时分秒
res = datetime.date.today()
res1 = datetime.datetime.today()
res2 = res1.strftime('%Y-%m-%d %X')  # 对datetime对象进行格式化
res3 = datetime.datetime.strftime(res2, '%Y-%m-%d %X')  # 对格式化后的时间再生成datetime对象

print(res1, type(res1))  # 2022-05-06 16:28:39.856233 <class 'datetime.datetime'>
print(res2, type(res2))  # 2022-05-06 16:28:39 <class 'str'>
print(res3, type(res3))  # 2022-05-06 16:28:39 <class 'datetime.datetime'>

print(res.year)
print(res.month)
print(res.day)
print(res.weekday())  # 1 0-6表示星期,0表示周一
print(res.isoweekday())  # 2 1-7表示星期,7表示周日

print(res1.year)
print(res1.month)
print(res1.day)
print(res1.weekday())
print(res1.isoweekday())
print(res1.hour)
print(res1.minute)
print(res1.second)



"""
(******)
日期对象 = 日期对象 +/- timedelta对象
timedelta对象 = 日期对象 +/- 日期对象
"""
current_t = datetime.date.today()  # 日期对象
timetel_t = datetime.timedelta(days=7)  # timedelta对象
print(current_t)  # 2022-03-28
print(timetel_t)  # 7 days, 0: 00: 00
print(current_t + timetel_t)  # 日期对象=日期对象+/-timedelta对象
print(res)  # 2022-04-04
print(current_t - res)  # -7 days, 0: 00: 00 timedelta对象=日期对象+/-日期对象

# UTC时间
print(datetime.datetime.today())  # 2021-12-28 10: 21: 32.045834
print(datetime.datetime.now())  # 2021-12-28 18: 21: 32.045834 UTC时间
print(datetime.datetime.utcnow())  # 2021-12-28 18: 21: 32.045835 UTC时间

random模块

import random

print(random.randint(1,6))  # 随机取1-6之间的整数,包含首尾
print(random.random())  # 随机取0-1之间的小数
print(random.choice([1,2,3,4,5,6]))  # 随机从列表中取一个元素

res = [1,2,3,4,5,6]
random.shuffle(res)  # 打乱列表
print(res)


# 生成随机验证码(大小写字母、数字)
def get_code(n): 
    code = ''
    for i in range(n): 
        # 先生成随机的大写字母、小写字母、数字
        upper_str = chr(random.randint(65,90))
        lower_str = chr(random.randint(97,122))
        random_int = str(random.randint(0,9))
        # 从上面三个中随机选择一个作为随机验证码的某一位
        code += random.choice([upper_str,lower_str,random_int])
    return code
print(get_code(6))  # 76Ff0L

os模块

# os模块: 跟操作系统打交道的模块

import os



"""
os.path.dirname(__file__) 脚本以完整路径被运行则返回该脚本所在完整路径(不包含文件名),脚本以相对路径被运行则返回空目录
os.path.abspath(__file__) 返回该脚本所在绝对路径(包含文件名)
os.path.join() 连接两个或更多的路径名组件
os.listdir() 将传入的文件夹下的所有文件展示出来
"""

BASE_DIR = os.path.dirname(__file__)  # E: \python学习\python视频教程\day16\代码\day16
MOVIE_DIR = os.path.join(BASE_DIR,'老师们的作品')  # E: \python学习\python视频教程\day16\代码\day16\老师们的作品
MOVIE_DIR = os.path.join(BASE_DIR,'老师们的作品','优秀')  # E: \python学习\python视频教程\day16\代码\day16\老师们的作品\优秀
movie_list = os.listdir(MOVIE_DIR)  # ['tank老师.txt', '冲老师.txt', '明老师.txt', '田老师.txt']
while True: 
    for i,j in enumerate(movie_list,1): 
        print(i,j)
    choice = input('你想看谁的: ').strip()
    if choice.isdigit():   # 判断用户输入的是否为纯数字
        choice = int(choice)  # 传成int类型
        if choice in range(1,len(movie_list)+1):   # 判断是否在列表元素个数范围内
            # 获取用户想要看的文件名
            target_file = movie_list[choice-1]
            # 拼接文件绝对路径
            target_path = os.path.join(MOVIE_DIR,target_file)
            with open(target_path,'r',encoding='utf-8') as f: 
                print(f.read())

                

"""
os.mkdir() 一级一级创建目录
os.makedirs() 一次创建多级创建目录
os.rmdir()
os.path.exists()
os.path.isfile()
os.path.isdir()
os.getcwd()
os.chdir()
os.path.getsize()
os.remove() 删文件
os.rename() 改文件名
"""

os.mkdir('tank老师精选')  # 创建文件夹,已存在会报错
os.rmdir(r'E: \python学习\python视频教程\day16\代码\day16\tank老师精选')  # 删除文件夹,只能删空文件夹

print(os.path.exists(r'E: \python学习\python视频教程\day16\代码\day16\老师们的作品'))  # 判断文件夹是否存在
print(os.path.exists(r'E: \python学习\python视频教程\day16\代码\day16\老师们的作品\tank老师.txt'))  # 判断文件是否存在
print(os.path.isfile(r'E: \python学习\python视频教程\day16\代码\day16\老师们的作品\tank老师.txt'))  # 只能判断文件,不能判断文件夹

print(os.getcwd())  # E: \python学习\python视频教程\day16\代码\day16 返回当前工作目录
os.chdir(r'E: \python学习\python视频教程\day16\代码\day16\老师们的作品')  # 切换当前所在的目录
print(os.getcwd())  # E: \python学习\python视频教程\day16\代码\day16\老师们的作品

print(os.path.getsize(r'E: \python学习\python视频教程\day16\代码\day16\老师们的作品\tank老师.txt'))  # 获取文件字节大小

sys模块

# sys模块: 跟python解释器打交道的模块

import sys

"""
sys.path:  是python搜索模块的路径集,是一个list,里面包含了已经添加到系统环境变量的路径
sys.path.append(PATH):  向sys.path中添加自己的引用模块搜索目录
print(sys.platform) 获取当前系统平台
print(sys.version)  获取python版本
print(sys.argv)  获取命令行参数,实现从程序外部向程序传递参数,是一个list,第一个元素是程序本身,随后才依次是外部给予的参数
"""

if len(sys.argv) <= 1: 
    print('请输入用户名和密码')
else: 
    username = sys.argv[1]
    password = sys.argv[2]
    if username == 'jason' and password == '123': 
        print('欢迎使用')
    else: 
        print('用户或密码错误,无法执行当前文件')
"""
>python3 test.py jason 123
"""


# sys.getsizeof() 获取对象占用的内存空间
class Person: 
    def __init__(self,name): 
        self.name = name
p = Person("jack")
print(sys.getsizeof(p))

序列化模块

json模块

"""
写入文件的数据必须是字符串
基于网络传输的数据必须是二进制

序列化: 其他数据类型转成字符串
反序列化: 字符串转成其他数据类型

json模块: 
    所有语言都支持json格式
    支持的数据类型很少: 整型、浮点型、字符串、列表、布尔、元组(转成列表)、字典
"""


"""
dumps: 序列化,将其他数据类型转成json格式的字符串(json格式的字符串是双引号)
loads: 反序列化,将json格式的字符串转换成其他数据类型
dump: 序列化并写入文件
load: 从文件取出并反序列化
"""

import json
# json.JSONEncoder 可进JSONEncoder类查看json能转化的python数据类型

d = {"name":  "jason"}
res = json.dumps(d)
print(res, type(res))  # {"name":  "jason"} <class 'str'>
res1 = json.loads(res)
print(res1, type(res1))  # {'name':  'jason'} <class 'dict'>

d = {"name": "jason"}
with open('userinfo','w',encoding='utf-8') as f: 
    json.dump(d,f)  # 序列化并写入文件
with open('userinfo','r',encoding='utf-8') as f: 
    res = json.load(f)  # 从文件取出并反序列化
    print(res,type(res))  # {'name':  'jason'} <class 'dict'>

# 多行文件序列化与反序列化
d = {"name": "jason"}
with open('userinfo','w',encoding='utf-8') as f: 
    json_str = json.dumps(d)
    json_str1 = json.dumps(d)
    f.write('%s\n'%json_str)
    f.write('%s\n'%json_str1)
with open('userinfo','r',encoding='utf-8') as f: 
    for line in f: 
        res = json.loads(line)
        print(res,type(res))

# 元组序列化是转成列表
t = (1,2,3,4)
print(json.dumps(t))  # [1, 2, 3, 4]


# 中文序列化
d = {'name': '朱志坚'}
print(json.dumps(d))  # {"name":  "\u6731\u5fd7\u575a"}
print(json.dumps(d, ensure_ascii=False))  # {"name":  "朱志坚"}






# 重写json.JSONEncoder的default方法,解决json不能序列化python的datetime和date类型

import json
from datetime import datetime,date

class MyJson(json.JSONEncoder):
    def default(self, o):
        if isinstance(o,datetime):
            return o.strftime('%Y-%m-%d %X')
        elif isinstance(o,date):
            return o.strftime('%Y-%m-%d')
        else:
            return super().default(self,o)
            
res = {'c1':datetime.today(),'c2':date.today()}
print(json.dumps(res, cls=MyJson))  # {"c1": "2022-05-06 18:22:08", "c2": "2022-05-06"}

pickle模块

"""
pickle模块: 
    只支持python
    python所有的数据类型都支持
pickle序列化的结果是一个二进制数据(bytes类型),用pickle操作文件时,文件的打开模式必须是b模式
"""

import pickle

d = {'name':  'jason'}
res = pickle.dumps(d)  # 将对象直接转成二进制
print(res,type(res))  # b'\x80\x04\x95\x13\x00\x00\x00\x00\x00\x00\x00}\x94\x8c\x04name\x94\x8c\x05jason\x94s.' <class 'bytes'>
res1 = pickle.loads(res)  # 将二进制转成对象
print(res1,type(res1))  # {'name':  'jason'} <class 'dict'>

d = {'name':  'jason'}
with open('userinfo','wb') as f: 
    pickle.dump(d,f)
with open('userinfo_1','rb') as f: 
    res = pickle.load(f)
    print(res,type(res))  # {'name':  'jason'} <class 'dict'>

subprocess模块

"""
1.用户通过网络连接上了你的电脑
2.用户输入命令,基于网络发送给了你的电脑上某个程序
3.获取用户命令,利用subprocess执行用户命令
4.将执行结果基于网络发送给用户
实现了用户远程操作你的电脑
"""

while True: 
    cmd = input('cmd>>>: ').strip()
    import subprocess
    obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    print('正确命令返回的结果stdout',obj.stdout.read().decode('gbk'))
    print('错误命令返回的提示信息stderr',obj.stderr.read().decode('gbk'))

typing模块

"""
typing模块的作用: 
1.类型检查,防止运行时出现参数和返回值类型不符合。
2.作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
3.该模块加入后并不会影响程序的运行,不会报正式的错误,只有提醒。
注意: typing模块只有在python3.5以上的版本中才可以使用
"""

from typing import List, Tuple, Union

def test1(name:  str,
          age:  int,
          balance:  float,
          user_info:  List) -> Tuple[str, int, float, List]: 
          # user_info:  List) -> Union[int, None]:   # 返回int类型或None
          # user_info:  List) -> List[int or str]:   # 返回列表类型并且列表内元素为int或str类型

    print(name, age, balance, user_info)
    return name, age, balance, user_info
    # return 18
    # return None
    # return [1, 'a']

res = test1('赵铁柱', 18, 18000.0, ['a', 'b', 'c'])
print(res)

"""
说明: 
1.在传入参数时通过"参数名: 类型"的形式声明参数的类型;
2.返回结果通过"-> 结果类型"的形式声明结果的类型。
3.在调用的时候如果参数的类型不正确pycharm会有提醒,但不会影响程序的运行。
4.对于如list列表等,还可以规定得更加具体一些,如: "-> List[str]",规定返回的是列表,并且元素是字符串。
"""

"""
typing常用的类型: 
1.int,long,float:  整型,长整形,浮点型;
2.bool,str:  布尔型,字符串类型;
3.List,Tuple,Dict,Set:  列表,元组,字典,集合;
4.Iterable,Iterator:  可迭代类型,迭代器类型;
5.Generator:  生成器类型;
"""

logging模块

logging基本使用

logging模块: 日志模块

import logging

logging.basicConfig(filename='access.log',
                    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:   %(message)s',
                    datefmt='%Y-%m-%d %H: %M: %S %p',
                    level=10)

# 日志分为五个等级
logging.debug('debug日志')  # 10
logging.info('info日志')  # 20
logging.warning('warning日志')  # 30
logging.error('error日志')  # 40
logging.critical('critical日志')  # 50



"""
1.logger对象: 产生日志
2.filter对象: 过滤日志(了解)
3.handler对象: 控制日志输出位置(文件/终端)
4.formater对象: 规定日志格式
"""

# 1.logger对象: 产生日志
logger = logging.getLogger('转账记录')

# 2.filter对象: 过滤日志(了解)

# 3.handler对象: 控制日志输出位置(文件/终端)
hd1 = logging.FileHandler('a1.log',encoding='utf-8')  # 输出到文件中
hd2 = logging.FileHandler('a2.log',encoding='utf-8')  # 输出到文件中
hd3 = logging.StreamHandler()  # 输出到终端

# 4.formmater对象: 规定日志格式
fm1 = logging.Formatter(
        fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s:   %(message)s',
        datefmt='%Y-%m-%d %H: %M: %S %p',
)
fm2 = logging.Formatter(
        fmt='%(asctime)s - %(name)s:   %(message)s',
        datefmt='%Y-%m-%d',
)

# 5.logger对象绑定handler对象
logger.addHandler(hd1)
logger.addHandler(hd2)
logger.addHandler(hd3)

# 6.handler对象绑定formmate对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)

# 7.设置日志等级
logger.setLevel(20)
	
# 8.记录日志
logger.debug('写了半天 好累啊')

logging字典配置

import os
import logging.config


# 定义两种日志输出格式
standard_format = '[%(asctime)s][%(threadName)s: %(thread)d][task_id: %(name)s][%(filename)s: %(lineno)d]' \
                  '[%(levelname)s][%(message)s]'  # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s: %(lineno)d]%(message)s'


# 定义日志文件目录和日志文件名(需要手动修改)
logfile_dir = os.path.dirname(__file__)  # log文件的目录
logfile_name = 'a3.log'  # log文件名


# 如果定义的日志目录不存在就创建
if not os.path.isdir(logfile_dir): 
    os.mkdir(logfile_dir)

    
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)


# log配置字典
LOGGING_DIC = {
    'version':  1,
    'disable_existing_loggers':  False,
    'formatters':  {
        'standard':  {
            'format':  standard_format
        },
        'simple':  {
            'format':  simple_format
        },
    },
    'filters':  {},  # 过滤日志
    'handlers':  {
        #打印到终端
        'console':  {
            'level':  'DEBUG',
            'class':  'logging.StreamHandler',  # 打印到屏幕
            'formatter':  'simple'
        },
        #打印到文件,收集DEBUG及以上级别的日志
        'default':  {
            'level':  'DEBUG',
            'class':  'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter':  'standard',
            'filename':  logfile_path,  # 日志文件
            'maxBytes':  1024*1024*5,  # 日志大小 5M
            'backupCount':  5,  # 日志个数 5个
            'encoding':  'utf-8',  # 日志文件的编码
        },
    },
    'loggers':  {
        #logging.getLogger(__name__)拿到的logger配置
        '':  {
            'handlers':  ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log既写入文件又打印到屏幕
            'level':  'DEBUG',
            'propagate':  True,  # 向上(更高level的logger)传递
        },  # 当键不存在的情况下,默认会使用该k: v配置
    },
}


# 使用日志字典配置
logging.config.dictConfig(LOGGING_DIC)  # 自动加载字典中的配置
logger1 = logging.getLogger('jll_log')
logger1.debug('不要浮躁 努力就有收获')

hashlib模块

"""
hashlib模块: 加密模块,加密的过程是无法解密的

1.不同的算法,使用方法是相同的
2.密文的长度越长,内部对应的算法越复杂,但是
    1.时间消耗越长
    2.占用空间更大
    通常情况下使用md5算法,就足够了
    
hashlib模块应用场景: 
    1.密码的密文存储
    2.校验文件内容是否一致
"""

import hashlib

md = hashlib.md5()  # 生成造密文的对象
# md.update('hello'.encode('utf-8'))  # 往对象里传明文数据,update只能接受bytes类型的数据
md.update(b'hello')  # 和上面一行等价
print(md.hexdigest())  # 5d41402abc4b2a76b9719d911017c592 获取明文数据对应的密文

# 传入的内容可以分多次传入,只要传入的内容相同生成的密文肯定相同
md = hashlib.md5()
md1 = hashlib.md5()
md.update(b'areyouok?')
md1.update(b'are')
md1.update(b'you')
md1.update(b'ok?')
print(md.hexdigest())  # 408ac8c66b1e988ee8e2862edea06cc7
print(md1.hexdigest())  # 408ac8c66b1e988ee8e2862edea06cc7


# 加盐处理,在每一个需要加密的数据之前添加一些内容
md = hashlib.md5()
md.update(b'oldboy.com')  # 加盐处理
md.update(b'hello')  # 真正的内容
print(md.hexdigest())

# 动态加盐
def get_md5(data): 
    md = hashlib.md5()
    md.update('加盐'.encode('utf-8'))
    md.update(data.encode('utf-8'))
    return md.hexdigest()
password = input('password>>>: ')
res = get_md5(password)
print(res)

openpyxl模块

# openpyxl模块: 比较火的操作excel表格的模块

"""
03版本之前excel文件的后缀名叫xls
03版本之后excel文件的后缀名叫xlsx

之前用的模块: 
    xlwd  写excel
    xlrt  读excel

xlwd和xlrt既支持03版本之前的excel文件也支持03版本之后的excel文件
openpyxl只支持03版本之后的xlsx
"""


from openpyxl import Workbook  # 写

wb = Workbook()  # 生成一个工作簿
wb1 = wb.create_sheet('index', 0)  # 创建表单页,可以通过数字控制位置
wb2 = wb.create_sheet('index1')
wb1.title = 'login'  # 修改表单页名称

wb1['A3'] = 666
wb1['A4'] = 444
wb1['A5'] = '=sum(A3: A4)'  # A3到A4求和写到A5
wb1.cell(row=6,column=3,value=888)  # 第6行第三列插入888

wb2.append(['username','age','hobby'])  # 表头
wb2.append(['jason',18,'study'])
wb2.append(['egon',28,])
wb2.append(['nick','','秃头'])

wb.save('test.xlsx')  # 保存并命名新建的excel文件



from openpyxl import load_workbook  # 读

wb = load_workbook('test.xlsx',read_only=True,data_only=True)
print(wb.sheetnames)  # ['login', 'Sheet', 'index1'] 查看所有表单
print(wb['login']['A3'].value)   # 666
print(wb['login']['A5'].value)  # None 通过代码产生的excel表格必须经过人为操作之后才能读取出函数计算出的结果值

res = wb['login']
ge1 = res.rows
print(ge1)  # <generator object ReadOnlyWorksheet._cells_by_row at 0x0000023BE2AD2740> 生成器
for i in ge1: 
    for j in i: 
        print(j.value)

copy模块深浅拷贝

# 浅拷贝
l = [1,2,[1,2]]
l1 = copy.copy(l)
print(id(l),id(l1))  # 2133591739584 2133591744704
l[0] = 222
print(l,l1)  # [222, 2, [1, 2]] [1, 2, [1, 2]]
l[2].append(666)
print(l,l1)  # [222, 2, [1, 2, 666]] [1, 2, [1, 2, 666]]


# 深拷贝
l = [1,2,[1,2]]
l1 = copy.deepcopy(l)
l[2].append(666)
print(l,l1)  # [1, 2, [1, 2, 666]] [1, 

uuid模块

# uuid可以产生一个世界上唯一的字符串

import uuid 
import hashlib

print(uuid.uuid4())  # 6623e8ee-6b8d-494c-8a60-d3a92f392df9
print(type(uuid.uuid4()))  # <class 'uuid.UUID'>

md5 = hashlib.md5()
md5.update(str(uuid.uuid4()).encode('utf-8'))
print(md5.hexdigest())  # c3f95f416c7688f90e470aa0c1ba4926

pymysql模块

pymysql基本使用

# python代码连接mysql的模块


import pymysql

conn = pymysql.connect(  # 连接mysql
    host='localhost',
    port=3306,
    user='root',
    password='123456',
    database='db1',
    charset='utf8',
    autocommit = True)  # 增删改操作需在execute后conn.commit(),配置此参数后自动commit)

# cursor = conn.cursor()  # 产生一个游标对象,默认以元组方式显示数据
cursor=conn.cursor(pymysql.cursors.DictCursor)  # 以字典方式显示数据,键是表字段,值是表字段对应数据

user = input("user>>>:").strip()
pwd = input("password>>>:").strip()
# sql = 'select * from userinfo where name="%s" and passwd="%s"' %(user,pwd)  # %s需要加引号,存在sql注入问题
sql = 'select * from userinfo where name=%s and passwd=%s'  # execute解决sql注入问题,此时%s不能加引号
# sql1 = 'insert into userinfo(name,passwd,age) values(%s,%s,%s)'

rows = cursor.execute(sql,(user,pwd))  # execute解决sql注入问题
# rows1 = cursor.executemany(sql1,[('ddd','123',18),('eee','123',18)])  # 一次插入多行记录
# conn.commit()
print(rows)  # 执行语句返回的数据条数

if rows:
    print(cursor.fetchone())  # 获取一条数据
    print(cursor.fetchall())  # 获取所有数据,返回的是一个元组或列表(当以字典方式显示数据)
    print(cursor.fetchmany(2))  # 拿指定条数据
    cursor.scroll(2,'absolute')  # 控制光标移动,absolute绝对移动(相对起始位置向后移动2位)
    cursor.scroll(1,'relative')  # relative相对移动(相对当前位置向后移动1位)
else:
    print('用户名或密码错误')

cursor.close()  # 释放游标对象
conn.close()  # 关闭mysql连接


"""
sql注入问题:利用特殊符号(MySQL中的引号、注释--)巧妙的修改sql语句
解决方法:sql语句不要手动拼接,交给execute,execute能够识别sql语句中的%s并且过滤特殊符号,能完成sql语句的拼接	

# 用户名错误(select * from userinfo where name = "jll" -- abcdefg)
username >>>: jll" -- abcdefg
# 用户名密码都错误(select * from userinfo where name = "xxx" or 1=1 -- abcdefg)
username >>>: xxx" or 1=1 --abcdefg
password >>>: xxx
"""

pymysql调用存储过程

import pymysql

conn = pymysql.connect(
    host = '127.0.0.1',
    port = 3306,
    user = 'root',
    password = '123',
    database = 'day39',
    charset = 'utf8',
    autocommit = True
)

cursor = conn.cursor(pymysql.cursors.DictCursor)
cursor.callproc('p1',(1,5,10))  # pymysql调用存储器p1并传参,内部原理(@_存储器名_索引值):@_p1_0=1,@_p1_1=5,@_p1_2=10;
print(cursor.fetchall())

cursor.execute('select @_p1_0')
print(cursor.fetchall())  # 1
cursor.execute('select @_p1_1')
print(cursor.fetchall())  # 5
cursor.execute('select @_p1_2')
print(cursor.fetchall())  # 10

posted @   生姜J  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
返回顶端
点击右上角即可分享
微信分享提示