出现这种情况的时候,如果想要在bin.py中调用my_module包中的模块,可以首先通过sys.path查看文件模块搜索路径(pycharm会添加day21_lesson的路径),在其他环境中不一定添加有该路径,所以可能需要在bin中添加day21_lesson的路径,使用sys.path.append(r'路径\day21_lesson')
但这样不易于移植,使用os.path.dirname(basename则是获取文件名)来获取当前文件的上级目录的绝对路径。
__file__在python解释器中只获得当前文件名,如test.py,而在Pycharm中会得到完整的绝对路径,如C:\Users\Desktop\test.py,所以需要使用os.path.abspath(__file__)来获取到完整路径
一. os模块
os.getcwd():获取当前工作目录
os.chdir():改变当前工作目录,等于cd
os.makedirs():可生成多层递归目录
os.removedirs():若目录为空,则删除,递归到上一层目录,若也为空则删除,依次递归
os.mkdir():生成单机目录
os.rmdir():删除单机空目录,若目录不为空则无法删除,报错
os.remove():删除一个文件
os.listdir():列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印,不会标注文件信息
os.rename():改名
os.stat():文件基本信息,创建时间,uid,修改时间等
os.system(bash command):如‘dir’显示当前目录下所有文件的详细信息,等于shell中LL
os.path.split():将path分割成目录和文件名二元组
os.path.exists()、os.path.isfile()、os.path.isdir()、os.path.isabs():存在(是)则返回True
os.path.join():拼接路径
os.path.getatime():获取文件或目录最后存取时间
os.path.getmtime():获取文件或目录最后修改时间
二. sys模块
sys.argv:获取用户在命令行写入的参数List,第一个元素是程序本身路径
sys.exit(n):退出程序
sys.version:获取Python解释程序的版本信息
sys.path:返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.stdout.write():显示输出内容,但会在缓冲区等待足够量才会输出
sys.stdout.flush():刷新缓冲区,把缓冲区内容直接输出
pycharm会自动把项目路径添加到sys.path当中,如果切换到别的环境下,需要在导入前进行sys.path.append('路径')
三. 序列化工具
把对象(变量)从内存中编程可存储或传输的过程称之为序列化。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器。反过来,把变量内容从序列化的对象重新读取到内存里称之为反序列化。
3.1 json模块⭐⭐
json可以进行任何语言之间的数据交换
【注!eval也可以进行普通数据类型的交换,但有局限性,很多特殊数据类型都不支持】
JSON表示的对象就是标准的JavaScript语言的对象
JSON类型 | Python类型 |
{} | dict |
[] | list |
*string* | str |
1234.56 | int or float |
true/false | True/False |
null | None |
两个操作并不是逆操作
json.dumps():把所有单引号,双引号字符串和任意类型数据都转换为双引号字符串
json.loads():还原回原来的类型,只支持json规范,双引号的字符串
只限于文件操作
json.dump(dic, f):等于先dumps,然后在f.write
json.load(f):等价于json.loads(f.read())
3.2 pickle 模块
pickle.dumps(dic):转换为字节bytes,文件写入不可读
pickle.loads(data):读取还原
3.3 Shelve模块
将一个字典存入文本中
f = shelve.open(r'filename')
# 会生成三个不可读文件,.bak, .dat, .dir
f['a'] = {'name':'alex', 'age':'18'}
print(f.get('a')['age'])
f.close()
3.4 XML模块
比json使用简单,更早出现,标签化语言【文档树】
import xml.etree.ElementTree as ET
parse():读取数据
getroot():获取根节点,通过属性tag来显示
xml一个节点有三个属性:tag、text、attrib
- tag代表节点名字,country节点的tag就是它的名字:country
- text代表节点文本内容,rank节点的text就是2
- attrib代表节点包含的属性,以{属性:值}这样的字典形式存放
iter():只查看某个节点
set():设置属性
修改完之后需要重新写到文件中,因为只是在内存中进行修改,使用write()
findall()、find():查找标签
remove():删除,还需要重新写到文件中
Element():创建根节点
SubElement:创建子节点
四. re模块
正则表达式,字符串匹配
1.普通字符串:大多数字符和字母都会和自身匹配
2.元字符:. ^ $ * + ? {} [] | () \
re.findall(子串, 字符串):查找子串
元字符 . :通配符,占一位,可代表大多数字符、字母,除了换行符
元字符 ^ : 只能放在开头部分,以这个子串为开头
元字符 $ : 只能放在结尾部分,以这个子串为结尾
【贪婪匹配,总是匹配最长串】
元字符 * : 重复,0到无穷次,前面可以没有子串
元字符 + : 重复,1到无穷次,前面必须要有子串
元字符 [] : 字符集,起到或作用,里面只有四个元字符起作用,-表示范围;^表非;\表示转义符
元字符 \ : 转义符,反斜杠后边跟元字符去除特殊功能,后跟普通字符实现特殊功能
- \d 匹配任何十进制数;它相当于类[0-9]
- \D 匹配任何非数字字符;它相当于类[^0-9]
- \s 匹配任何空白字符;它相当于类[\t\n\r\f\v]
- \S 匹配任何非空白字符;它相当于类[^\t\n\r\f\v]
- \w 匹配任何字母数字字符;它相当于类[a-zA-Z0-9_]
- \W 匹配任何非字母数字字符;它相当于类[^a-zA-Z0-9_]
- \b 匹配一个特殊字符边界,比如空格,&,#等
元字符 | : 或,左右表达式任意一个
元字符 () : 分组表及,内部只能使用 | 元字符,(abc | edf)表示abc、edf
re.search(): 返回第一个满足的对象
>>> re.search('\d+', 'asofhi1241aosihfoanf098')
<re.Match object; span=(6, 10), match='1241'>
分组:分组命名, 用(?P<组名>正则表达式)表示
re.search(): 函数会在字符串内查找模式匹配,直到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
>>> ret = re.search('(?P<id>\d{2})/(?P<name>\w{3})', '23/com')
>>> print(ret.group())
23/com
>>> print(ret.group('id'))
23
group方法返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,整个匹配都被返回。
如果一个参数值为 0,即是group(0),相应的返回值就是整个匹配字符串;如果它是一个范围 [1..99],结果就是相应的括号组字符串。
如果一个组号是负数,或者大于样式中定义的组数,一个 IndexError 索引错误就 raise。如果一个组包含在样式的一部分,并被匹配多次,就返回最后一个匹配。
re.match():同search,不过仅在字符串开始处进行匹配
>>> re.match('a', 'abc').group()
'a'
ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret) #['', '', 'cd']
ret = re.sub('\d', 'abc', 'alvin5yuan6', 1) #替换,1表示替换次数
re.compile():提前设定规则
re.finditer():提取的结果存储到迭代器里,面对数据量非常大的时候实用【findall是list】。通过.group提取结果
>>> ret=re.finditer('\d','ds3sy4784a')
>>> print(ret) #<callable_iterator object at 0x10195f940>
<callable_iterator object at 0x00000154A7BF1EB0>
>>> print(next(ret).group())
3
>>> print(next(ret).group())
4
ret = re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret) # ['oldboy']
# 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret) # ['www.oldboy.com']
re.findall("(abc)+", "abcabcabc")
['abc'] # 优先匹配
re.findall("(?:abc)+", "abcabcabc")
['abcabcabc'] # 取消特性
re.findall("abc+", "abcabcabc")
['abc', 'abc', 'abc']
五. logging模块
将日志打印到标准输出中,且只显示大于等于WARNING级别的日志
日志级别CRITICAL>ERROR>WARNING>INFO>DEBUG>NOTEST
默认的日志格式为日志级别:Logger名称:用户输出消息
basicConfig:通过具体参数来更改logging模块默认行为
level=logging.DEBUG, #设置显示高于或等于DEBUG的日志可以显示
filename='filename.log', #存储文件名,创建FiledHandler
filemode='w', #文件打开方式,默认为a,可以指定为w
datefmt="", #时间格式
format="" #显示格式
format参数中可能用到的格式化串 | |
%(name)s | Logger的名字 |
%(levelno)s | 数字形式的日志级别 |
%(levelname)s | 文本形式的日志级别 |
%(filename)s | 调用日志输出函数的模块的完整路径名,可能没有 |
%(module)s | 调用日志输出函数的模块名 |
%(funcName)s | 调用日志输出函数的函数名 |
%(lineno)d | 调用日志输出函数的语句所在的代码行 |
%(created)f | 当前时间,用UNIX标准的表示时间的浮 点数表示 |
%(relativeCreated)d | 输出日志信息时的,自Logger创建以 来的毫秒数 |
%(asctime)s | 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
%(thread)d | 线程ID,可能没有 |
%(threadName)s | 线程名。可能没有 |
%(process)d | 进程ID。可能没有 |
%(message)s | 用户输出的消息 |
logger对象【树形层级结构】
logging.getLogger():返回一个logger对象,如果没有指定名字将返回root logger
import logging
logger = logging.getLogger(name)
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('test.log')
# 再创建一个handler,用于输出到控制台
ch = logging.StreamHandler()
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
logger.addHandler(fh) # logger对象可以添加多个fh和ch对象
logger.addHandler(ch)
logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')
# 输出【按照默认级别WARNING】
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式
输出信息之前都需要获得一个Logger,如果没有显式获取则自动创建使用root Logger
【设置的name唯一】
孩子,孙子,重孙……可逐层继承来自祖先的日志级别、Handler、Filter设置,也可以通过Logger.setLevel(lel)
Logger.addHandler(hdlr)
Logger.removeHandler(hdlr)
Logger.addFilter(filt)
Logger.removeFilter(filt)。
设置自己特别的日志级别、Handler、Filter。若不设置则使用继承来的值
Filter:只有满足过滤规则的日志才会输出
比如我们定义了filter = logging.Filter('a.b.c'),并将这个Filter添加到了一个Handler上,则使用该Handler的Logger中只有名字带a.b.c前缀的Logger才能输出其日志。
filter = logging.Filter('mylogger')
logger.addFilter(filter) # 这是只对logger这个对象进行筛选
如果想对所有的对象进行筛选,则:
filter = logging.Filter('mylogger')
fh.addFilter(filter)
ch.addFilter(filter)
# 所有添加fh或者ch的logger对象都会进行筛选
六. configparse模块
对配置文件进行操作
ConfigParser():相当于生成一个空字典confg={}
读取文件:config.read('filename')
config.sections():查看所有标题 #['default', 'bitbucket.org'...]
config.options('标题'):查看标题下的key=value的key
config.items('标题'):查看标题下key=value的键值对
config.get('标题',key):对应标题对应key的值(字符串)
【遍历的时候也会把DEFAULT里的信息也遍历出来】
config.add_section(''):生成新标题
config.set(标题,key, value):添加内容
config.remove_section(标题):删除整个标题内容
config.remove_option(key):删除键值对
#修改了之后一定要写到文件里
config.write(open(filename, mode))
七. hashlib模块
用于加密操作,主要提高SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法
import hashlib
obj = hashlib.md5() #加盐
obj.update("hello".encode("utf-8"))
print(obj.hexdigest()) # 5d41402abc4b2a76b9719d911017c592
# 如果在后面继续update则会在hello后面添加信息再MD5