Python(编程思想、模块)

目录

一、编程思想

1、面向过程

2、面向对象

3、猴子补丁 

二、模块

1、定义

2、import导入模块

3、from ... import导入模块

4、模块查找优先级

5、循环导入问题

6、编写模块的规范

7、软件开发的目录规范

三、包(模块的一种形式)

四、常用模块

1、time

2、datetime

3、random

4、os

5、sys

6、shutil(了解)

7、json、pickle

8、configparser 

9、hashlib

10、subprocess

11、logging

12、re


一、编程思想

1、面向过程

# 核心:过程,即做事的步骤(先做什么,再做什么,然后再做什么)

# 优点:复杂的问题过程化,进而简单化
# 缺点:扩展性非常差

# 应用场景解析:不是所有的软件都需要频繁更迭,不是软件的所有组成部分都需要频繁更迭

2、面向对象

# 核心:对象,用于存放数据与功能的容器

# 优点:将程序整合,提高程序的解耦合程度,进而增强程序的可扩展性
# 缺点:设计复杂

# 

3、猴子补丁 

import json             # 第一次导入会执行模块,产生一个json的名称空间
                        # 在当前模块产生一个名字json,指向上述名称空间
import ujson
json.dumps=ujson.dumps  # json.dumps指向新的代码块
json.loads=ujson.loads


import json             # 第二次导入不会执行模块
                        # 在当前模块产生一个名字,指向最初未关闭的json名称空间
json.dumps()            # json.dumps指向的是新的代码块

二、模块

1、定义

'''
模块就是一个python文件(模块=模块名.py),是一系列功能的集合体

两个优点:
Ⅰ:极大地提升编程效率(内置与第三方的模块拿来就用无需定义)
Ⅱ:减少代码冗余(自定义的模块将程序的共性功能提取到一模块中为大家共享使用)

三个分类:
Ⅰ:内置的模块
Ⅱ:第三方的模块
Ⅲ:自定义的模块

四个形式
Ⅰ:使用python编写的.py文件
Ⅱ:把一系列模块组织到一起的文件夹(注:文件夹下有一个__init__.py)
Ⅲ:已被编译为共享库或DLL的C或C++扩展
Ⅳ:使用C编写并链接到python解释器的内置模块
'''

2、import导入模块

# 导入模块会发生的事情:
# 执行foo.py,将执行过程中产生的名字放到foo的名称空间中
# 在当前模块中产生一个名字foo,该名字指向foo的名称空间
import foo

# 如何调用:模块名.名字
foo.x
foo.get()
foo.change()

# 导入模块的顺序:内置>第三方>自定义
# 导入模块的位置:可以在函数内导入
# 在一行导入多个模块:import time,foo
# 将导入的模块取个别名:import 模块名 as 别名
# 自定义模块的命名:纯小写加下划线
# 模块是第一类对象:可以被赋值,作为函数参数、作为函数返回值、作为容器类型的元素
# __name__:在本模块执行时为"__main__",被当作模块导入时为"__模块名__"

3、from ... import导入模块

# 导入模块会发生的事情:
# 执行foo.py,将执行过程中产生的名字放到foo的名称空间中
# 在当前模块中产生一个名字,该名字指向foo的名称空间下的同一名字
from foo import x
from foo import get
from foo import change

# 如何调用:名字
x
get()
change()

# 将导入的名字取个别名:from 模块名 import 名字 as 别名
# 一行导入多个名字(不推荐):from 模块名 import 名字1,名字2
# 导入模块中的所有名字(不推荐):from 模块名 import *
# __all__:装有模块中所有名字的一个列表

4、模块查找优先级

'''
优先从内存找(python解释器在启动时会自动加载一些模块到内存中)
其次从硬盘找(按照sys.path中存放的文件的顺序依次查找)
1、sys.path中的第一个元素是当前执行文件所在的文件夹
2、不管导入的是包还是模块,它的上一级目录一定在sys.path
3、sys.path参照的是执行模块
'''
import sys
print(sys.path)
sys.path.append(r"D:\s38\Day03")    # 将m1的路径临时加到sys.path

import m1               # 第一次导入:内存中没有,从硬盘找
                        # 执行m1.py,申请m1的名称空间存放名字
                        # 在当前模块中产生一个名字m1,m1指向m1的名称空间

print(sys.modules)      # 查看已经加载到内存中的模块
del m1
def func():
    import m2
func()                  # 解除绑定关系,导入的模块的名称空间仍然存在内存中

import m1               # 第二次导入:此时m1已经加载到内存中,从内存找
                        # 不会执行m1.py,不会申请内存空间
                        # 会在当前模块中产生一个名字m1,m1指向m1的名称空间

5、循环导入问题

# func.py
import m1


# m1.py
print("========>>导入m1")
x=111
from m2 import y


# m2.py
print("========>>导入m2")
from m1 import x
y=222
# func.py
import m1
f1()


# m1.py
print("========>>导入m1")
def f1():
    from m2 import y
x=111


# m2.py
print("========>>导入m2")
from m1 import x
y=222

6、编写模块的规范

'''The module is used to ...'''    # 模块的文档描述

import sys                         # 导入模块

x=1                                # 定义全局变量,如非必须最好使用局部变量

class Foo:                         # 定义类,并写好类的注释
    '''Class Foo is used to...'''
    pass

def test():                        # 定义函数,并写好函数的注释
    '''Function is used to ...'''
    pass

if __name__=="__main__":
    test()

7、软件开发的目录规范

'''
ATM
    readme                     # 解释描述
    start.py                   # 程序入口
    core                       # 用户视图层
        src.py
    interface                  # 逻辑接口层
        user_interface.py
    db                         # 数据处理层
        db_handle.py
    log                        # 存放日志
        log.py
        log.txt
    conf                       # 存放配置文件(日志文件的路径)
        settings.py
    lib                        # 存放程序中常用的自定义模块
        common.py
'''

# start.py
import sys
import os
PATH=os.path.dirname(__file__)
sys.path.append(PATH)
from core import src
src.run()


# src.py
from log.log import logger
def registe():
    print("注册功能")
    logger("注册")
def login():
    print("登录功能")
    logger("登录")
def withdrew():
    print("提现功能")
    logger("提现")
def transfer():
    print("转账功能")
    logger("转账")
func_dic = {
    "0": ("退出", None),
    "1": ("注册", registe),
    "2": ("登录", login),
    "3": ("提现", withdrew),
    "4": ("转账", transfer),
}
def run():
    while True:
        for x in func_dic:
            print(x, func_dic[x][0])
        a = input("请输入序号:").strip()
        if not a.isdigit():
            print("请输入数字,二货!")
            continue
        if a not in fun_dic:
            print("请输入已有的序号,二货!")
            continue
        if a == "0":
            break
        else:
            func_dic[a][1]()
            


# log.py
import time
from conf.settings import LOG_PATH
def logger(mes):
    with open(r"{}\log\user.log".format(LOG_PATH),mode="at",encoding="utf-8") as f:
        f.write("{}{}\n".format(time.strftime("%Y-%m-%d %H-%M-%S"),mes))


# settings.py
import os
LOG_PATH=os.path.dirname(os.path.dirname(__file__))

三、包(模块的一种形式)

'''
包是模块的一种形式,是包含__init__.py文件的文件夹
foo
    __init__.py
    m1.py
    m2.py
    bbb
        __init__.py
        m3.py
test.py
'''

# test.py
import os
PATH=os.path.dirname(__file__)
import sys
sys.path.append(PATH)

import foo.m1            # .的左边必须是包
from foo.m1 import f1

import foo               # foo  指向  __init__.py
from foo import x        # x    指向  __init__.py中的x
from foo import m1       # m1   指向  m1.py
from foo import bbb      # bbb  指向  bbb下的__init__.py


# __init__.py
x=1
# 绝对导入
from foo.m1 import f1        # sys.path参照的是被执行文件
from foo.m2 import f2
from foo.bbb.m3 import f3
# 相对导入
from .m1 import f1
from .m2 import f2
from .bbb.m3 import f3


# m1.py
def f1():
    print("====>>f1")


# m2.py
def f2():
    print("====>>f2")


# m3.py
def f3():
    print("====>>f3")

四、常用模块

1、time

import time
# 1、时间戳:从1970到现在经历的秒数,用于时间间隔的计算
print(time.time())

# 2、结构化的时间,用于单独获取时间的某一部分
res=time.localtime()
print(res)
print(res.tm_year)
print(res.tm_yday)

# 3、格式化的时间:2022-05-16 20:20:20,用于展示时间
print(time.strftime("%Y-%m-%d %H:%M:%S %p"))
print(time.strftime("%Y-%m-%d %X"))
'''
          localtime               strftime
    时间戳——————————>结构化的时间————————————>格式化的时间
timestamp<——————————struct_time<————————————format_time
            mktime                strptime
'''
import time
# 时间戳转换成结构化的时间
print(time.localtime(333333333))
print(time.gmtime(333333333))
# 结构化的时间转换成时间戳
s_time=time.localtime()
print(time.mktime(s_time))

# 结构化的时间转换成格式化的时间
print(time.strftime("%Y-%m-%d %H:%M:%S",s_time))
# 格式化的时间转换成结构化的时间
print(time.strptime("2022-05-16 21:03:02","%Y-%m-%d %H:%M:%S"))

2、datetime

import datetime
print(datetime.datetime.now())      # 2022-05-16 20:30:15.539775
print(datetime.datetime.now()+datetime.timedelta(days=10))
print(datetime.datetime.now()+datetime.timedelta(weeks=2))
# 了解
import datetime
print(datetime.datetime.now())
print(datetime.datetime.utcnow())
print(datetime.datetime.fromtimestamp(333333))

3、random

import random
print(random.random())                    # (0,1)中取个小数
print(random.uniform(1,3))                # (1,3)中取个小数

print(random.randint(1,3))                # [1,3]中取个整数
print(random.randrange(1,3))              # [1,3)中取个整数

print(random.choice([1,"33",[4,5]]))      # 随机取列表中的某一个元素
print(random.sample([1,"33",[4,5]],2))    # 随机取列表中的n个元素

item=[1,4,5,"a",3]
random.shuffle(item)                      # 打乱列表中元素的顺序
print(item)
# 验证码
print(chr(65))      # 65,66,...,90
print(ord("A"))     # A, B,..., Z

import random
def make_code(size=4):
    res=""
    for i in range(size):
        s1=str(random.randint(0,9))
        s2=chr(random.randint(65,90))
        res+=random.choice([s1,s2])
    return res
print(make_code(6))

4、os

import os
print(os.listdir("dirname"))                    # 列出指定目录下所有的子文件和子文件夹
print(os.environ)                               # 获取环境变量
os.remove(r"D:\\aaa.txt")                       # 删除一个文件
os.rename(r"D:\\aaa.txt",r"D:\\bbb.txt")        # 重命名文件/目录
os.system("cd D:\\")                            # 运行操作系统命令
print(os.path.split(r"D:\a\b\c"))               # 将path分割成目录和文件名二元组返回
print(os.path.join("a","D:\\b","c"))            # 将多个路径组合后返回,第一个绝对路径之前的参数被忽略
print(os.path.dirname(r"D:\a\b\c"))             # 返回D:\a\b,其实就是os.path.split(path)中的第一个元素
print(os.path.basename(r"D:\a\b\c"))            # 返回c,其实就是os.path.split(path)中的第二个元素
print(os.path.isfile(r"D:\a\b\c"))              # 如果path是一个存在的文件,返回True;否则返回False
print(os.path.isdir(r"D:\a\b\c"))               # 如果path是一个存在的目录,返回True;否
print(os.path.getsize(r"D:\a\b\c"))             # 返回文件的大小(以字节为单位)


# 返回当前文件的上上一级目录
print(os.path.dirname(os.path.dirname(__file__)))

print(__file__)
print(os.path.join(__file__,"..",".."))
print(os.path.normpath(os.path.join(__file__,"..","..")))

# 在python3.5之后,推出了一个新的模块pathlib
from pathlib import Path
res=Path(__file__).parent.parent
print(res)
res=Path("/a/b/c") / "d/e.txt"
print(res)
# 了解
import os
print(os.getcwd())                              # 获取当前工作目录
os.chdir(r"D:\\dirname1\\dirname2")             # 改变当前脚本工作目录;相当于shell下cd
print(os.curdir)                                # 返回当前目录:"."
print(os.pardir)                                # 返回当前目录的父目录字符串名:".."
os.makedirs(r"D:\\dirname1\\dirname2")          # 可生成多层递归目录
os.removedirs(r"D:\\dirname1\\dirname2")        # 若目录为空,则删除并递归到上一级,如若也为空,则删除,依次类推
os.mkdir(r"D:\\dirname1")                       # 生成单级目录;相当于shell中的mkdir dirname1
os.rmdir(r"D:\\dirname1")                       # 删除单级目录,若目录不为空,则无法删除报错;相当于shell下rmdir dirname1
print(os.stat(r"D:\\s38\\ATM"))                 # 获取文件目录信息
print(os.sep)                                   # 输出操作系统特定的路径分隔符,win下为\,Linux下为/
print(os.linesep)                               # 输出操作系统特定的行终止符,win下为\r\n,Linux下为\n
print(os.pathsep)                               # 输出操作系统特定的分割文件路径的字符,win下为;,Linux下为:
print(os.name)                                  # 输出字符串指示当前使用平台,win->nt,linux->posix
print(os.path.abspath(r"D://c//c//c"))          # 返回path规范化的绝对路径
print(os.path.exists(r"D:\s38\ATM"))            # 如果path存在返回True,不存在返回False
print(os.path.isabs(r"D:\s38\ATM"))             # 如果path是绝对路径返回True
print(os.path.getatime(r"D:\s38\ATM"))          # 返回path所指向的文件或者目录的最后存取时间
print(os.path.getmtime(r"D:\s38\ATM"))          # 返回path所指向的文件或者目录的最后修改时间

5、sys

import sys
# sys.argv获取的是解释器后的参数
print(sys.argv)      # python3.8 run.py 1 2 3     ["run.py","1","2","3"]
# sys.path返回模块的搜索路径
print(sys.path)
# 打印进度条
import time
# res=""
# for i in range(50):
#     res+="#"
#     time.sleep(0.1)
#     print("\r[{}]".format(res.ljust(50," ")),end="")

total_size=211111
start_size=0
while start_size<total_size:
    if total_size-start_size>1024:
        start_size+=1024
    else:
        start_size=total_size
    time.sleep(0.01)
    res=int(start_size/total_size*50)*"*"

    print("\r[{}] {}%".format(res.ljust(50," "),int(start_size/total_size*100)),end="")

6、shutil(了解)

import shutil
shutil.copyfileobj(fsrc,fdst)   # 将文件内容拷贝到另外一个文件中
shutil.copyfile(src,dst)        # 拷贝文件(目标文件无需存在)
shutil.copymode(src,dst)        # 仅拷贝权限,内容、用户、组均不变(目标文件必须存在)
shutil.copystat(src,dst)        # 仅拷贝状态的信息,包括:mode bits,atime,mtime,flags(目标文件必须存在)
shutil.copy(src,dst)            # 拷贝文件和权限
shutil.copy2(src,dst)           # 拷贝文件和状态信息
shutil.copytree(src,dst,symlinks,ignore)  # 递归的去拷贝文件夹
shutil.rmtree(path)             # 递归的去删除文件
shutil.move(src,dst)            # 递归的去移动文件
shutil.make_archive(base_name,format,root_dir)        # 打包

7、json、pickle

'''
1、什么是序列化与反序列化
内存中的数据类型———————>序列化———————>特定的格式(json格式或者pickle格式)
内存中的数据类型<——————反序列化<——————特定的格式(json格式或者pickle格式)

2、为何要序列化
pickle是一种专用的格式(只有python可以识别),主要用于存储
json是一种通用的格式(能够被所有语言识别),主要用于跨平台数据交互
'''
import json
with open(r"test.json",mode="wt",encoding="utf-8") as f:
    json_res=json.dumps([1,'aaa',True,False])
    f.write(json_res)
    # json.dump([1,'aaa',True,False],f)
with open(r"test.json",mode="rt",encoding="utf-8") as f:
    json_res=f.read()
    json.loads(json_res)
    # json.load(f)

# json支持的是所有语言通用的类型,不能识别单一语言独有的类型
# 支持python类型:int、float、str、list、tuple、dict、bool、bytes(python3.5之后支持)
json.dumps([1,'aaa',True,False,None])
# json类型:{}  []  123.45  "string"  true/false  null
json.loads('[1,"aaa",true,false,null]')


import pickle
res=pickle.dumps({1,2,3,4})
print(res,type(res))
s=pickle.loads(res)
print(s,type(s))

8、configparser 

import configparser

config=configparser.ConfigParser()
config.read("test.ini")

print(config.sections())
print(config.items("section1"))
print(config.options("section1"))
print(config.get("section1","k1"))
print(config.getint("section1","k1"))
print(config.getfloat("section1","k1"))
print(config.getboolean("section1","k5"))


# 配置文件test.ini
[section1]
k1=1
k2:"aaa"
# k3=4
; k4=4
k5=true
[section2]
k1=1

9、hashlib

'''
1、什么是哈希hash
任意长度的原始数据————————>hash算法————————>固定长度的hash值
特点:
Ⅰ 不能由hash值反解出内容
Ⅱ只要传入的内容一样,hash算法一样,得到的hash值必然一样
Ⅲ无论传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是固定的

2、hash的用途
特点Ⅰ用于密码密文传输与验证
特点Ⅱ、Ⅲ用于文件完整性校验
'''
# 针对密文加密
import hashlib
m=hashlib.md5()
m.update("hello".encode("utf-8"))
m.update("world".encode("utf-8"))
res=m.hexdigest()       # 'helloworld'
print(res)

# 针对文件完整性校验
f=open("a.txt",mode="rb")
m.update(f.read())       # 文件的所有内容太慢了

f=open("a.txt",mode="rb")
f.seek(1000)
m.update(f.read(20))
f.seek(3000)
m.update(f.read(20))     # 选取特定位置的字节进行hash运算

# 撞库
import hashlib
m=hashlib.md5()
m.update("cang0527".encode("utf-8"))
res=m.hexdigest()
print(res)


# 得到明文用户名与密文密码
user="cangyuan"
pwd="903e310503d2c8a615bcefede03a5521"
# 制作密码字典:
l=[
    "cang111",
    "cang123",
    "cang444",
    "cang0527"
]
dic={}
for i in l:
    m=hashlib.md5()
    m.update(i.encode("utf-8"))
    dic[i]=m.hexdigest()
print(dic)

for k,v in dic.items():
    if v==pwd:
        print("撞库成功,密码是{}".format(k))
        break
        
        
# 密码加盐
import hashlib
m=hashlib.md5()
m.update("天王".encode("utf-8"))
m.update("cang".encode("utf-8"))
m.update("盖地虎".encode("utf-8"))
m.update("0527".encode("utf-8"))
res=m.hexdigest()
print(res)

10、subprocess

import subprocess
obj=subprocess.Popen("dir",shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE
                 )                          # 执行系统命令
print(obj)
res=obj.stdout.read()
print(res.decode("gbk"))
res=obj.stderr.read()
print(res)

11、logging

import logging

logging.basicConfig(
    # 1、日志输出位置:终端、文件
    filename='access.log',  # 不指定,默认打印终端

    # 2、日志格式
    # %(name)s          Logger的名字
    # %(levelno)s       数字形式的日志级别
    # %(levelname)s     文本形式的日志级别
    # %(pathname)s      调试日志输出函数的模块的完整路径名,可能没有
    # %(filename)s      调试日志输出函数的模块的文件名
    # %(module)s        调试日志输出函数的模块名
    # %(funcName)s      调试日志输出函数的函数名
    # %(lineno)d        调试日志输出函数的语句所在的代码行
    # %(created)f       当前时间,用UNIX标准的表示时间的浮点数表示
    # %(relativeCreated)d 输出日志信息时的,自logger创建以来的毫秒数
    # %(asctime)s       字符串形式的当前时间,默认格式是"2003-07-09 16:16:16,899"
    # %(thread)d        线程ID,可能没有
    # %(threadName)s    线程名,可能没有
    # %(process)d       进程ID,可能没有
    # %(message)s       用户输出的消息
    format="%(asctime)s - %(name)s - %(levelname)s",

    # 3、时间格式
    datefmt="%Y-%m-%d %H:%M:%S",

    # 4、日志级别(输出level级别之上的日志)
    # debug => 10
    # info => 20
    # warning => 30
    # error => 40
    # critical => 50
    level=20
)

logging.debug("调试")
logging.info("消息")
logging.warning("警告")
logging.error("错误")
logging.critical("严重")
# src.py
import settings
from logging import config,getLogger
config.dictConfig(settings.LOGGING_DIC)

# logger1=getLogger("logger1")
# logger1.info("这是一条info日志")

# logger1=getLogger("logger2")
# logger1.info("这是一条info日志")

logger1=getLogger("用户交易")
logger1.info("这是一条info日志")


# seettings.py
standard_format="%(asctime)s - %(name)s - %(levelname)s"
simple_format="%(asctime)s - %(name)s - %(levelname)s"
test_format="%(asctime)s - %(name)s - %(levelname)s"

LOGGING_DIC={
    "version":1,
    # 日志格式
    "formatters":{
        "formatter1":{
            "format":standard_format
        },
        "formatter2":{
            "format":simple_format
        },
        "formatter3":{
            "format":test_format
        }
    },
    # 日志的处理者,不同的handler会将日志输出到不同的位置
    "handlers":{
        # 打印到终端
        "handler1":{
            "level":"DEBUG",
            "class":"logging.StreamHandler",
            "formatter":"formatter1"
        },
        # 打印到文件
        "handler2":{
            "level":"DEBUG",
            # "class":"logging.FileHandler",
            "class":"logging.handlers.RotatingFileHandler",     # 日志轮转
            "maxBytes":200,                                     # 超出200字节就切出去
            "backupCount":5,                                    # 切的次数
            "filename":"a1.log",
            "encoding":"utf-8",
            "formatter":"formatter2"
        }
    },
    # 日志的产生者,产生的日志会传递给handlers
    "loggers":{
        # 产生者1
        "logger1":{
            "handlers":["handler1","handler2"],
            "level":"DEBUG",
            "propagate":False
        },
        # 产生者2
        "logger2":{
            "handlers":["handler1"],
            "level":"DEBUG",
            "propagate":False
        },
        # 默认生产者
        "":{
            "handlers":["handler2"],
            "level":"DEBUG",
            "propagate":False
        }
    }
}

12、re

import re
# 元字符
print(re.findall("\w","aA\rbc\t\n12\f3_*()-= "))                    # 匹配字母数字下划线
print(re.findall("\W","aA\rbc\t\n12\f3_*()-= "))                    # 匹配非字母数字下划线
print(re.findall("\s","aA\rbc\t\n12\f3_*()-= "))                    # 匹配空白符\n \t\r\f
print(re.findall("\S","aA\rbc\t\n12\f3_*()-= "))                    # 匹配非空白符
print(re.findall("\d","aA\rbc\t\n12\f3_*()-= "))                    # 匹配数字
print(re.findall("\D","aA\rbc\t\n12\f3_*()-= "))                    # 匹配非数字
print(re.findall("^abc","abc is ab"))                               # 匹配行首
print(re.findall("sb$","abc is ab"))                                # 匹配行尾
print(re.findall("a.b","ab a1b a b abbbb a\nb a*b a\tb"))           # 匹配任意字符(除\n)
print(re.findall("a.b","ab a1b a b abbbb a\nb a*b a\tb",re.DOTALL))

# 限定符
print(re.findall("ab*","a ab abb abbbbbbb bbbbbb"))           # * 左测字符出现的次数为{0,}
print(re.findall("ab+","a ab abb abbbbbbb bbbbbb"))           # + 左测字符出现的次数为{1,}
print(re.findall("ab?","a ab abb abbbbbbb bbbbbb"))           # ? 左测字符出现的次数为{0,1}
print(re.findall("ab{2}","a ab abb abbbbbbb bbbbbb"))         # {n} 左测字符出现的次数为n次
print(re.findall("ab{2,4}","a ab abb abbbbbbb bbbbbb"))       # {n,m} 左测字符出现的次数为n到m次
print(re.findall("ab{2,}","a ab abb abbbbbbb bbbbbb"))        # {n,} 左测字符出现的次数为n到无穷次

# 字符类
print(re.findall("a[012]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[0-2]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[a-zA-Z0-9]b","a111b a3b a4b a9b aXb a b a\nb"))
print(re.findall("a[^0-9]b","a111b a3b a4b a9b aXb a b a\nb"))

# 或运算符
# (a|b)        匹配a或者b
# (ab)|(cd)    匹配ab或者cd
# 贪婪/懒惰匹配
# <.+>         默认贪婪匹配“任意字符”
# <.+?>        懒惰匹配“任意字符”
Dijkstra算法是一种用于解决单源最短路径问题的贪心算法,主要基于图的数据结构。它的基本思想是通过不断地扩展当前已经找到的最短路径来找到从源节点到其他所有节点的最短路径。 具体的实现过程可以分为以下几个步骤: 1. 创建一个集合用于存储已经找到最短路径的节点,将源节点添加到集合中,并将源节点的距离设置为0。 2. 创建一个优先队列用于存储未找到最短路径的节点,将所有节点添加到队列中,并将它们的距离设置为正无穷。 3. 从队列中取出距离源节点最近的节点,并将其加入到已找到最短路径的集合中。 4. 遍历当前节点的所有邻居节点,如果当前节点到邻居节点的距离加上当前节点到源节点的距离小于邻居节点的距离,则更新邻居节点的距离。 5. 重复第3步和第4步,直到队列为空或者找到了目标节点。 下面是一个简单的Python实现: ```python import heapq def dijkstra(graph, start): distances = {node: float('inf') for node in graph} distances[start] = 0 queue = [(0, start)] while queue: current_distance, current_node = heapq.heappop(queue) if distances[current_node] < current_distance: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(queue, (distance, neighbor)) return distances ``` 其中,`graph`是一个字典类型的变量,用于存储图的邻接表表示方式,`start`是源节点的标识符。函数返回一个字典类型的变量,存储了源节点到其他所有节点的最短距离。 在代码中,我们使用了`heapq`模块来实现优先队列,这样可以保证每次取出的节点都是距离源节点最近的节点。同时,我们使用一个`distances`字典来记录每个节点到源节点的距离,初始值为正无穷。在遍历图的过程中,如果发现新的距离比已有距离更小,就更新距离,并将邻居节点加入到队列中等待处理。 这就是Dijkstra算法的Python编程思想
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值