python-模块与包

目录:1.模块  2.包  3.绝对导入与相对导入  4.time模块  5.random模块  6.os模块   7.sys模块  8.json&pickle模块  9.shelve模块  10.xml模块  11.configparser模块  12. hashlib模块  13.subprocess模块  14.logging模块  15.re模块  16.软件开发规范

模块:

    分类:内置模块,第三方模块,自定义模块

         调用方式:

                   import module

                   from module import xxx

                   from module.xx.xx import xx as rename

                   from module.xx.xx import *

                   模块一旦被调用,相当于执行了其中的代码

                  

         程序在哪执行,sys.path中就默认有当前目录的路径     

         跨模块导入时要添加环境变量,把父级路径添加到sys.path中

         import sys,os

         sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

         sys.path打印一个列表,第一个元素是 ’ ’ 就是当前目录的路径

         __file__就是当前程序的路径,pycharm里是绝对路径,python2中是相对路径

         所以最好使用os.path.abspath(__file__)拿到绝对路径

        

         if __name__==’__main__’ 该文件就当做脚本去执行

        

         __all__=[] 列表里面写字符串形式的内容,这样from … import * 这样操作的时候*不再代表所有的内容了,只代表[]内的所有内容

                     

包:

         一个文件夹管理多个模块文件,这个文件夹就被称为包

         包就是文件夹,该文件夹下有__init__.py文件

         导入包的时候,会先执行包下面的__init__文件

         凡是在导入的时候带 . 的, . 的左边都必须是一个包

         from … import … 这种格式的时候,import后面的不能有.

         from … import *这样导入包的时候,*只会导入包下面__init__文件中的内容,我们可以在这个文件中自定义__all__=[]

绝对导入与相对导入

         在涉及相对导入时,package所对应的文件夹必须正确的被python解释器视为package,而不是普通文件夹

         文件夹被python解释器视作package需要满足的条件:

                   1.文件夹中必须有__init__.py文件,该文件可以为空,但必须存在该文件

                   2.不能作为顶层模块来执行该文件夹中的py文件(即不能作为主函数的入口),

                            即用..的时候包不能跟入口程序在同一层

         .代表__init__当前的目录,就是跟执行的程序入口在同一级目录,..代表__init__上一级目录

         相对导入用的不多,不建议用

        

time模块:

         python中通常有如下方式表示时间

         1.时间戳 time.time() 是从1970年1月1日00:00:00开始计算到现在的秒数

         2格式化的时间字符串,time.strftime(“%Y-%m-%d %X”),得到2018-04-09 17:06:32 Y改成y就显示18

         3元组,即结构化时间 time.localtime() 拿到的是时间每个部分组成的一个元组,可以每一部分都取出来然后重新组合

        

         结构化时间到字符串时间用strftime,字符串时间到结构化时间strptime

         结构化时间到时间戳用mktime,时间戳到结构化时间用localtime或gmtime

         字符串时间与时间戳之间不能直接转化

        

         time.asctime()获取当前时间,格式是周 月 日 时 分 秒 年 time.ctime()

        

         time.mktime(time.strptime('2021-02-01','%Y-%m-%d')) 实现字符串时间到时间戳的转化

         即先用strptime将字符串时间转成结构化时间,再用mktime将结构化时间转成时间戳

         time.strptime(字符串时间)--->结构化时间 time.mktime(结构化时间)--->时间戳

        

         time.strftime('%Y-%m-%d',time.localtime(time.time())) 实现时间戳到字符串时间的转化

         即先用localtime将时间戳转成结构化时间,再用strftime将结构化时间转成字符串时间

         time.localtime(时间戳) or time.gtime(时间戳)--->结构化时间 time.strftime(结构化时间)--->字符串时间

        

        

datetime模块:

         datetime.date.fromtimestamp() 把一个时间戳转成datetime日期类型

         datetime.datetime.now()返回当前时间,格式是年月日时分秒

         时间运算:

                   datetime.datetime.now() - datetime.timedelta(days = 1)

                            减一天,可以写days,hours,minutes,seconds,可加可减

         时间替换:

                   d = datetime.datetime.now()

                   d.replace(year = 1990,month = 10)可以替换出来一个自己指定的时间

random模块:

         random.random() 得到的是0~1之间的小数

         random.randint(1,s) 大于等于1且小于等于s之间的整数

         random.randrange(1,s) 大于等于1且小于s之间的整数,可以再加一个参数(1,8,2)2是步长的意思,从1开始,结果都是奇数

         random.choice([1,’23’,(4,5)]) 1或’23’或(45),随机返回一个,里面可以放列表、字符串,返回一个

         random.sample([1,’23’,(4,5)],2) 因为在最后一个位置设定了参数2,所以结果是从里面选两个组成列表,返回多个组成的列表

         random.uniform(1,s) 大于1小于s的小数

         random.shuffle(item) 打乱次序

         random实例:

         chr()括号里面加数字可以得到ASCII码中对应的字母

         做一个五位数的验证码

                   一:

                   def validate():

                            s=''

                            for i in range(5): 控制验证码的字母或数字个数

                                     rNum=random.randint(0,9)  randint得到一个0-9包括9的随机整数

                                     alpha=chr(random.randint(65,90)) 先得到65-90包括90的随机整数,然后用chr得到对应的ASCII码中的字母

                                     res=random.choice([rNum,alpha]) choice从整数或字母中随机选出一个赋值给res括号里面必须写列表的形式

                                     s+=str(res)

                            return s

                   print(validate())

                  

                   二:

                   num = string.digits 拿到0-9

                   alpha = string.ascii_lowercase 拿到小写的a-z

                   s = alpha + num 把a-z跟0-9组成一个字符串

                   ‘’.join(random.sample(s,5))先用random.sample拿到一个五个元素组成的列表,再用join方法把列表转成字符串

string模块:

         string.digits 返回字符串格式的'0123456789'

         string.ascii_letters 返回所有的小写字母和大写字母组成的字符串

         string.ascii_lowercase 返回所有小写字母组成的字符串

os模块:

         os模块是与操作系统交互的一个接口

         os.getcwd()获取当前工作目录,即当前python脚本所在的目录路径

         os.chdir(“dirname”)改变当前脚本工作目录,相当于shell下的cd,没有返回值

         os.curdir返回当前目录:(’.’)

         os.pardir获取当前目录的父目录字符串名:(‘..’)

         os.remove() 删除一个文件

         os.removedirs(‘dirname1’)若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,以此类推

         os.mkdir(‘dirname’)生成单级目录,相当于shell中mkdir dirname

         os.makedirs(‘dirname1/dirname2’)可生成多层递归目录

         os.rmdir(‘dirname’)删除单级目录,若目录不为空则无法删除,报错 ,相当于shell中remdir dirname

        

         os.listdir(‘dirname’)列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印

   

         os.rename(‘oldname’,’newname’)重命名文件/目录

         os.stat(‘path/filename’)获取文件/目录信息

         os.sep 输出操作系统特定的路径分隔符,win下为”\\”,Linux下为”/”

         os.linesep输出当前平台使用的行终止符,win下为”\r\n”,Linux下为”\n”

         os.pathsep输出用于分割文件路径的字符串,win下为;,Linux下为:

         os.name输出字符串指示当前使用平台win->’nt’ Linux->’posix’

        

         os.system(“bath command”)运行shell命令,直接显示,这个方法是拿不到结果的,就是结果不能赋值给变量保存或传输

        

         os.environ获取系统环境变量

         os.path.abspath(path)返回path规范化的绝对路径

         os.path.split(path)将path分割成目录和文件名二元组返回,(‘目录名’,‘文件名’)

         os.path.dirname(path)返回path的目录,其实就是os.path.split(path)的第一个元素

         os.path.basename(pash)返回path最后的文件名,如果path以/或\结尾,那么返回空值,即os.path.split(path)的第二个元素

         os.path.exists(path)如果path存在,返回True,不存在返回False

         os.path.normpath(path) 标准化路径名,合并多余的分隔符和上层引用,在windows平台上还会把斜线转换成反斜线

         os.path.isabs(path)如果path是绝对路径,返回True

         os.path.isfile(path)如果path是一个存在的文件,返回True

         os.path.isdir(path)如果path是一个存在的目录,返回True,用..的时候会自动往前走三级目录

         os.path.join(path1[,path2[,…]])将多个路径组合后返回,第一个绝对路径之前的参数将被忽略

         os.path.getatime(path)返回path所指向的文件或者目录的最后访问时间

         os.path.getmtime(path)返回path所指向的文件或者目录的最后修改时间

         os.path.getsize(path)返回path的大小

         os.walk的用法:

                   def file_name(file_dir):  

                            for root, dirs, files in os.walk(file_dir): 

                                     print(root) #当前目录路径 

                                     print(dirs) #当前路径下所有子目录 

                                     print(files) #当前路径下所有非目录子文件 

        

sys模块:

         sys.argv 命令行参数List,第一个元素是程序本身路径

         sys.exit(n)退出程序,正常退出时exit()

         sys.version获取python解释程序的版本信息

         sys.maxint获取最大的int值

         sys.path返回模块的搜索路径,是一个列表,初始化时使用pythonpath环境变量的值

         sys.plaform返回操作系统平台名称

         sys.modules 返回内存里面都导入了哪些模块

shutil模块:

         shutil.copyfileobj() 将文件内容拷贝到另一个文件中,该操作需要打开文件

                   shutil.copyfileobj(open('old.xml','r'),open('new.xml','w'))

         shutil.copyfile() 拷贝文件,目标文件无需存在,该操作无需打开文件,就直接写文件名就可以

         shutil.copymode() 拷贝权限,目标文件必须存在

         shutil.copystat() 拷贝状态的信息,目标文件必须存在

         shutil.copy() 拷贝文件和权限

         shutil.copy2() 拷贝文件和状态信息

         shutil.copytree() 递归着去拷贝文件夹,要拷贝生成的新目录不能存在,不然会报错

                   shutil.copytree('package','pack2',ignore=shutil.ignore_patterns("__init__.py"))

                   第一个元素是要拷贝的文件夹,第二个元素师要生成的新目录

                   第三个元素是symlinks=False,一般默认是这样的,就不用写了

                   第四个元素是排除的意思,在拷贝的时候,哪些内容不拷贝,写到这里面

         shutil.rmtree() 递归着去删除文件

         shutil.move() 递归着去移动文件,类似于mv命令,相当于重命名

         shutil.make_archive() 创建压缩包并返回文件路径

                   括号里面可以放的参数:

                            base_name: 压缩包的文件名,也可以是压缩包的路径,只是文件名时,则保存到当前目录,否则保存到指定路径

                            format: 压缩包种类,zip,tar,bztar,gztar

                            root_dir: 要压缩的文件夹路径(默认是当前目录)

                            owner: 用户,默认是当前用户

                            group: 组,默认是当前组

                            logger: 用于记录日志,通常是logging.Logger对象

                   shutil.make_archive('data_bak','gztar',root_dir='/data')

                   将data下的文件打包到data_bak目录下

json&pickle模块:

         什么叫序列化?

                   序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或网络传输到远程,因为硬盘或网络传输只接受bytes

         把字符转成内存数据叫做反序列化

         序列化本身就是一次的,dump一次,load一次,如果dump两次,那load的时候就会报错,dump多次不会报错

        

         json,用于字符串和python数据类型之间进行转换,字典格式的json字符串,第一个key必须用""双引号,文件后缀是.json

                   序列化完了是字符串的格式,就可以用于存储和网络传输了

         pickle,用于python特有的类型和python的数据类型之间进行转换,文件后缀是.pkl,序列化完了就直接是bytes的格式

                   所以用pickle的时候,关于文件的操作要注意用‘rb’/'wb'

         两者用法完全一样

        

         两者都有四个功能,dumps、dump、loads、load

         pickle.dumps()将数据通过特殊的形式转换成只有python语言认识的bytes格式,括号中放数据

         pickle.dump() 将数据通过特殊的形式转换成只有python语言认识的bytes格式,并写入文件,括号中放两个参数,一个是数据,一个是文件句柄

         json.dumps()将数据通过特殊的形式转换成所有程序语言都认识的字符串

         json.dump() 将数据通过特殊的形式转换成所有程序语言都认识的字符串,并写入文件,括号中放两个参数,一个是数据,一个是文件句柄

         文件句柄需要是写模式的

        

         loads是反序列化的过程,与dumps对应

         load与dump对应

        

         d1 = json.dumps(data) 将data序列化成字符串格式并赋值给d1

         d2 = json.loads(d1) 将序列化得到的d1反序列化成原来的数据类型并赋值给d2

        

         f1 = open('test.json','w') 打开要把数据写入的文件,读模式

         json.dump(data,f1) 将data序列化成字符串格式,并写入到文件中

         f2 = open('test.json','r') 打开要读取数据的文件,读模式

         d3 = json.load(f2) 将文件f2中字符串格式的内容反序列化成原来的数据类型并赋值给d3

                   load括号里放文件句柄,loads括号里放bytes格式的对象,也可以放f.read()

        

         json与pickle的比较:

                   json:跨语言、体积小,但是只支持int、str、list、tuple、dict

                   pickle:专为python设计,支持python所有数据类型,但只能在python中使用,存储数据占空间大

        

         json.dumps()与json.loads() 只是把数据类型转成字符串并保存到内存里,其意义在于:

                   把内存数据通过网络共享给远程

                   定义了不同语言之间的交互规则:

                            1.纯文本,坏处是不能共享复杂的数据类型

                            2.xml,坏处是占空间大

                            3.json,简单,可读性好,跨语言

shelve模块:

         为了解决json和pickle只能dump一次的问题

         是对pickle进行了封装,pickle是python独有的,所以shelve只能在python中使用

         import shelve

         f = shelve.open('shelve_test') #打开一个文件

         names = ['alex','rain','test']

         info = {'name':'alex','age':22}

         f['names'] = names #持久化列表

         f['info'] = info #持久化字典

         f.close()

xml模块:

         是实现不同语言或程序之间进行数据交换的协议

         在各个语言中都支持

        

configparser模块:

         用于生成和修改常见配置文档

hashlib模块:

         Hash:一种将任意长度的消息压缩到某一个固定长度的消息摘要的函数

                     用于信息安全领域中加密算法,hash就是找到一种数据内容与数据存放地址之间的映射关系

                    

         MD5:输入任意长度的消息,经过处理,输出为128位的消息,不同的输入得到不同的结果

              用于防止被篡改,防止直接看到明文,防止抵赖

                    特点:

                            压缩性,任意长度的数据算出的MD5值都是固定长度的128位

                            容易计算,从原数据计算出MD5值很容易

                            抗修改性,对于原数据进行任何改动,修改一个字节生成的MD5值区别也会很大

                            强抗碰撞,已知原数据与MD5值,想找到一个具有相同MD5值的数据也非常困难

                   MD5不可逆

                    

         SHA-1:安全哈希算法,对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要

        

         最流行的加密算法是SHA-256

        

         SHA-1比MD5的摘要多32比特,抵御强行攻击更强,但是缓存也要更大,运行更慢

        

         实例:

                   import hashlib

                   m=hashlib.md5() #括号里可以加参数,就是俗称的“加盐”,提高安全性

                   m.update("3714".encode('utf-8'))

                   print(m.hexdigest()) digest是二进制格式,hexdigest是十六进制格式

                   m.update(b"3714") #37143714 因为上面已经update了一个3714,所以这里是37143714

                   print(m.hexdigest())

                   n=hashlib.sha1()

                   n.update(b"3714")

                   print(n.hexdigest())

                  

subprocess模块:

         统一的模块来实现对 系统命令或脚本 的调用

         三种执行命令的方法:

                   1.subprocess.run() 官方推荐

                   2.subprocess.call()

                   3.subprocess.Popen()

                  

         run()标准写法                  错误 直接.stderr查看   标准输出 直接.stdout查看

                   subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)

                   check = True ,默认是False的,这样的话如果加的命令没有也不会报错,写成True命令不存在就会报错

                   涉及到管道|的命令如下写,因为subprocess.PIPE也是一个类似于管道的东西

                   subprocess.run('df -h|grep disk1',shell=True)

                   shell=True的意思是这条命令直接交给系统去执行,不需要python负责解析

        

         call() 方法 用的不多

                   subprocess.call(['ls','-l']) 执行命令,返回命令执行状态

                   subprocess.check_call(['ls','-l']) 执行命令,如果命令结果为0,则正常返回,否则抛异常

                   subprocess.gestatusoutput('ls /bin/ls') 接受字符串格式命令,返回元祖形式,第一个元素是命令执行状态

                            第二个元素是执行结果

                   subprocess.getoutput('ls /bin/ls') 接收字符串格式命令,并返回结果

                           

                  

                  

         Popen() 方法 这个最重要,上面的call跟run底层都是封装的Popen方法

                   args:shell命令,可以是字符串或者序列类型

                   stdin、stdout、stderr:程序的标准输入、输出和错误句柄

                   shell:跟run一样shell = True 就是把命令交给操作系统去执行

                   a = subprocess.Popen('Python3 guess_age.py',

                                                                 stdout = subprocess.PIPE,

                                                                 stdin = subprocess.PIPE,

                                                                 stderr = subprocess.PIPE,

                                                                 shell = True)

                   a.communicate(b'22')

                  

                   Popen方法在发起命令后立刻返回,而不等待命令执行结果

logging模块:

         五个级别,由高到低:

         logging.critical()>logging.error()>logging.warning()>logging.info()>logging.debug()

        

         默认情况下python的logging模块将日志打印到了标准输出中,

         且只显示了大于等于warning级别的日志,这说明默认的日志级别设置为warning

         logging.warning('------warning') 运行就直接打印了,默认输出到屏幕

        

         这个只能输出到文件

         logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

                   filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。

                   filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。

                   datefmt:指定日期时间格式。

                   level:设置rootlogger(后边会讲解具体概念)的日志级别

                   format:指定handler使用的日志显示格式。

                            %(name)s       Logger的名字

                            %(levelno)s    数字形式的日志级别 info是10,debug是20,warning是30,error是40,critical是50

                            %(levelname)s  文本形式的日志级别

                            %(filename)s   调用日志输出函数的模块的文件名

                            %(lineno)d     调用日志输出函数的语句所在的代码行

                            %(asctime)s   字符串形式的当前时间,默认格式是"2018-04-10 11:10:45.896"

                            %(message)s    用户输出的消息

        

         日志同时输出到屏幕与文件

                   logger 提供了应用程序可以直接使用的接口

                   handler 将logger创建的日志记录发送到合适的目的输出

                   filter 提供了细度设备来决定输出哪条日志记录,可以理解为按照某种条件进行筛选过滤

                   formatter 决定日志记录的最终输出格式

                  

                   logger:通常对应了程序的模块名

                   logger = logging.getLogger()

                   还可以绑定handler与filters

                   logger.setLevel() 指定最低日志级别,这里是设置整个logger的最低日志级别,如果handler设置的高于这个,会按照那个输出

                   logger.addFilter() logger.removeFilter() 添加或删除指定的filter

                   logger.addHandler() logger.removeHandler() 添加或删除指定的handler

                   logger.debug() logger.info() logger.warning() logger.error() logger.critical()

                   设置日志级别

                  

                   handler:负责发送相关的信息到指定目的地

                   handler.setLevel() 指定被处理的信息级别,给handler设置级别,可以让输出到文件的跟输出到屏幕的不一样

                            此处设置的日志级别不能低于logger.setlevel() 设置的日志级别,不然不会生效

                   handler.setFormatter() 给这个handler选择一个格式

                   handler.addFilter() handler.removeFilter() 添加或删除一个filter对象

                   每个logger可以附加多个handler

                   常用handler:

                            logging.StreamHandler() 输出到屏幕

                            使用这个handler可以相类似与sys.stdout或sys.stderr的任何文件对象输出信息

                           

                            logging.FileHandler() 输出到文件

                            与上者类似,用于向一个文件输出日志信息,但这个会帮你打开文件

                           

                            logging.handlers.RotatingFileHandler()

                            与FileHandler类似,但是可以管理文件大小,当文件达到一定大小的时候,自动将当前文件改名

                            并生成一个新的同名日志文件继续输出

                           

                            logging.handlers.TimedRotatingFileHandler()

                            与上面类似,但不是判断文件大小,而是间隔一定时间就自动创建新的

                  

                   formatter:

                   日志的formatter是独立组件,可以跟handler组合

                   fh = logging.FileHandler('access.log‘) 拿到一个handler方法

                   formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

                   fh.setFormatter(formatter) 调用handler下面的功能,把formatter绑定到fh

                   实例:

                            import logging         

                            def logger():

                                     logger=logging.getLogger()

                                     fh=logging.FileHandler('logger2')

                                     sh=logging.StreamHandler()

                                     formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

                                     fh.setFormatter(formatter)

                                     sh.setFormatter(formatter)

                                     logger.addHandler(fh)

                                     logger.addHandler(sh)

                                     return logger

                            logger=logger()

                            logger.debug('debug')

                            logger.info('info')

                            logger.warning('warning')

                            logger.error('error')

                            logger.critical('critical')

re模块

         正则表达式就是字符串的匹配规则,本质上正则要实现的是模糊匹配

        

         re.findall()   把所有符合正则条件的内容放到一个列表中返回,有返回值

         re.match()     从头开始匹配,只匹配字符串中的第一个字符,返回对象

         re.search()    匹配包含,只匹配字符串中的一个,返回对象,匹配到了以后用.group()拿到要匹配的内容,分组匹配用.groups()拿到

         re.split()     以匹配到的字符当做列表分隔符,可以在最后加参数限定分割次数,有点跟findall相反的意思

                                               findall是拿到符合条件的放到一个列表中,只要符合条件的,而split是用符合条件的作为分隔符,把其他内容放到列表中

         re.sub()       匹配字符并替换

         re.subn()      会把替换的次数一并返回,以元组的形式

         re.fullmatch() 全部匹配

        

         以上方法,括号内两个参数,第一个是正则规则,规则用‘’引起来,第二个是数据

        

         贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下采用贪婪匹配

         非贪婪匹配:在满足匹配时,匹配尽可能短的字符串,使用?开头来表示非贪婪匹配

        

         元字符是正则最核心的内容

                   . 通配符,可以匹配除换行符\n以外的任意一个符号

                   ^ 匹配字符开头

                   $ 匹配字符结尾

                   * 匹配*前的字符0次或多次

                   + 匹配+前一个字符一次或多次

                   ? 匹配?前一个字符一次或零次

                   {m} 匹配前一个字符m次

                   {n,m} 匹配前一个字符n到m次

                   | 或

                   [] 字符集 如果是a[bd]c 匹配到的是abc和adc       

                            如果字符集里面放* + ?等这种元字符,那它们就失去了原本的功能,变成一个普通字符

                            字符集里面可以放的符号:- 表示范围

                                                                                    ^ 放在字符集里面表示取反,不再是以前的开始匹配

                                                                                    \ 还是以前的功能,是一个转义符

                   () 分组匹配,按照匹配规则,匹配得到的结果优先是括号里面的内容

                            可以在括号开头加?:取消优先级

                            (?P<name>)命名分组

                   \ 转义符,后面跟不同的内容有不同的意思

                            后面跟的是元字符则去除其特殊功能,变成普通字符 如\. \*

                            后面跟特定的普通字符实现特殊功能,如下

                            \d 匹配数字0-9 等于[0-9]  经常用

                            \D 匹配任何非数字字符

                            \s 匹配任何空白字符

                            \S 匹配任何非空白字符

                            \w 匹配任何字母数字字符 [a-zA-Z0-9]  经常用

                            \W 匹配任何非字母数字字符 非[a-zA-Z0-9]

                            \b 匹配一个特殊字符边界,比如空格 & # 等

                            \A 只从字符开头匹配 等同于^

                            \Z 匹配字符结尾,等同于$

                           

软件开发规范

         bin    可执行文件

         conf   配置文件

         core   核心代码 也可以就叫项目名称,项目名称一般是用小写的

       db     数据库文件

         docs   说明文档

       lib    库文件,放自己制作的自定义模块或包

         log    日志文件

         README 文本文件

                            1.软件定位,软件的基本功能

                            2.运行代码的方法:安装环境、启动命令等

                            3.简要的使用说明

                            4.代码目录结构说明,更详细点可以说明软件的基本原理

                            5.常见问题说明

猜你喜欢

转载自www.cnblogs.com/Interstellar-cooper/p/9253248.html