第二模块:day2

Day1


 

import的本质

  • 定义: 
    模块:用来从逻辑上组织python代码,本质就是一个以.py结尾的python文件 
    包:本质上就是一个目录,必须带有__init__.py文件

  • 导入模块的本质就是将python文件解释一遍。 
    相当于把被导入模块的代码赋值给以模块名命名的变量,本地直接用这个变量调用里面的方法函数等

 
  1. 导入方法:
  2. 同目录下模块导入方法:
  3. import module_name
  4. import module_namemodule_name2
  5. from module_name import * (相当于将module_na模块里的代码全部拷贝至当前程序里,不建议使用此方法,函数同名时,容易冲突)
  6. from module import m1m2.....
  7. from module import logger as logger_alex #可以避免导入的函数名与自身函数名同名
  8. 调用方法:
  9. 直接导入模块的名加上调用的函数名:module_name.func_name()
  • 导入包的本质就是执行包下的__init__.py文件。 
    所以跨目录导入包下的模块,需要先在包下的__init__.py文件里加入导入当前目录下的模块的信息。使用import方法导入包.

注:跨目录导入另一个包下的函数时,被导入的函数里不能有导入源函数的目录。如A包目录下的B函数导入C包目录下的D函数,D函数中不能有导入A目录下的函数的相关语句 
跨目录导入另一个函数内的变量方法:....

 
  1. 夸目录导入包示例:
  2. 在需要调用夸目录模块的程序开头添加以下信息:
  3. import sys,os
  4. os.path.abspath(\__file__) #获取当前文件的绝对路径,以便获取上级目录名。os.path.dirname() 获取路径的父目录名
  5. x = os.path.dirname(os.path.dirname(os.path.abspath(\__file__))) #获取当前文件的上上级目录
  6. sys.path.append(x) #将文件上上级目录路径添加到模块的环境变量里
  7. sys.path.insert(0,x) 在变量最前面插入新的路径
  8. import pack_name #导入上上级目录下名为pack_name的包
  9. 完整示例:
  10. import os,sys
  11. sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  12. import core
  13. core.logger.logger_tets()
  14. 被调用包内的\__init__.py文件需要添加导入本包内所有模块的命令
  15. (实际环境中直接提前将包内所有的模块信息加载到此文件内,以便跨目录的程序随时调用):
  16. 例:
  17. from . import modube_name1,modube_name2.....
  18. 直接使用 import modube_name1,modube_name....不生效,有待研究原因
  19. 如何调用跨目录下的函数:
  20. 在导入函数里使用:pack_name.module_name.func_name() #包名.模块名.函数名()
  • 模块调用优化:一个程序多次调用一个模块里的函数时使用以下方法: 
    from module_name import func_name as alias_name #给调用的函数去别名
 

模块分类

  • a:标准库,内置模块
  • b:开源模块
  • c:自定义模块
 

time、datetime模块:

时间的表示方式:1、时间戳 2、格式化时间字符串 3、元组(九元素。年、月、日、周、时、分、秒、天、时区) 
- time() 显示时间戳(秒的形式) 
time.time() 
显示结果: 
1498037276.0

  • sleep() 暂停时间(秒)
  • gmtime() 显示UTC+0时区时间
  • localtime() 以元组的形式显示本地时区(中国UTC+8时区)时间。时间戳形式转元组形式 
    print(time.localtime()) 
    显示结果: 
    time.struct_time(tm_year=2017, tm_mon=6, tm_mday=21, tm_hour=17, tm_min=27, tm_sec=56, tm_wday=2, tm_yday=172, tm_isdst=0)

    print(time.localtime(33656884)) 
    显示结果: 
    time.struct_time(tm_year=1971, tm_mon=1, tm_mday=25, tm_hour=21, tm_min=8, tm_sec=4, tm_wday=0, tm_yday=25, tm_isdst=0)

    d = time.localtime() 
    print("月天》",d.tm_mday) 元组中取指定的值

  • mktime() 元组时间形式转成时间戳形式(秒) 
    x=time.localtime() 
    time.mktime(x) 
    显示结果: 
    1498037276.0

  • strftime() 自定义字符串格式输出时间 
    print(time.strftime("%Y/%m/%d %H:%M:%S %A")) 
    2017/06/21 17:31:44 Wednesday

  • strptime() 将字符串格式时间转成元组

  • asctime() 将元组时间形式转成默认字符串形式 
    time.asctime(time.localtime())

  • ctime() 将时间戳(秒)时间形式转成默认字符串形式 
    time.ctime(335656445)

 

random 随机取值(常用于随机验证码生成)

  • random.random() 随机取一个浮点数
  • random.uniform(1,10) 随机在1-10中取一个浮点数
  • random.randint(1,3) 随机在1-3中取一个数
  • random.randrange(1,3) 随机在1-2中取一个数
  • random.choice(“hello”) 在字符串、序列中随机取一个值 
    random.choice([1,2,3,4]) 在字符串、序列中随机取一个值
  • random.sample(“hello world”,2) 随机在hello world中取2个字符
  • random.shuffle() 随机打乱列表顺序 
    x = [1,2,3,4,5,6] 
    random.shuffle(x) 
    print(x) #随机生成一个新顺序的列表

随机验证码程序示例:

 
  1. import random
  2. while True:
  3. check_num = ""
  4. for i in range(4):
  5. cun = random.randint(0,4)
  6. if cun == i :
  7. tmp = chr(random.randint(65,90))
  8. else:
  9. tmp = random.randint(0,9)
  10. check_num+=str(tmp)
  11. print("本次验证码:",check_num)
  12. in_put = input("\033[33;1m请输入验证码:\033[0m")
  13. if str(in_put.upper()) == check_num :
  14. print("\033[31;1m恭喜,输入正确,通过验证!\033[0m")
  15. break
  16. else:
  17. print("\033[41;1m输入错误,重新输入验证!\033[0m")
 

os模块

  • os.getcwd() 返回当前目录路径。等同于os.path.dirname(os.path.abspath(file))
  • os.chdir("dirname") 切换当前目录路径。 
    windows系统环境: 
    os.chdir("d:\dirname\test") 
    或 
    os.chdir(r"d:\dirname\test")
  • os.curdir 获取当前目录
  • os.pardir 获取当前目录的父目录字符串名
  • os.makedirs(r"c:\a\b\c") 递归新建一个c目录
  • os.removedirs(r"c:\a\b\c") 从c目录开始向上删除空目录,只要目录为空既删除,遇到非空目录既停止
  • os.lsitdir("path") 显示目录内容
  • os.remove() 删除文件
  • os.rename() 重命名文件/目录
  • os.stat() 获取文件/目录信息
  • os.sep 输出操作系统特定的路径分隔符。跨系统复制文件时很重要
  • os.linesep 输出当前平台使用的终止符
  • os.pathsep 输出当前平台使用的多路径分隔符
  • os.system("command") 执行window系统下的dos命令
  • os.path.abspath() 返回path规范化的绝对路径
  • os.path.split(path) 将path分割成目录和文件二元组返回。既目录与文件名分开 
    os.path.split(r"D:\Tencent\WeChat\avutil-55.dll") 
    返回值: 
    ('D:\Tencent\WeChat', 'avutil-55.dll')
  • os.path.exists("path") 判断路径是否存在
  • os.path.isabs("path") 判断一个路径是否为绝对路径
  • os.path.isfile("path") 判断一个路径是否为文件
  • os.path.isdir("path") 判断一个路径是否为目录
  • os.path.join("path1","path2","path3") 将多路径组合成一个路径返回
 

hashlib模块

用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

 
  1. import hashlib
  2. m = hashlib.md5()
  3. m.update(b"Hello")
  4. m.update(b"It's me")
  5. print(m.digest())
  6. #因为是update,print显示的是“helloIt's me”加密后的值.
  7. m = hashlib.md5()
  8. m.update("你好,世界".encode(encoding="utf-8"))
  9. #当加密的字符串是中文时,需要先进行编码
  10. print(m.digest()) #2进制格式hash
  11. print(len(m.hexdigest())) #16进制格式hash
  12. '''
  13. import hashlib
  14. # ######## md5 ########
  15. hash = hashlib.md5()
  16. hash.update('admin')
  17. print(hash.hexdigest())
  18. # ######## sha1 ########
  19. hash = hashlib.sha1()
  20. hash.update('admin')
  21. print(hash.hexdigest())
  22. # ######## sha512 ########
  23. hash = hashlib.sha512()
  24. hash.update('admin')
  25. print(hash.hexdigest())
 

logging模块

logging的日志从低到高可以分为 debug(), info(), warning(), error() and critical() 5个级别。 
日志的输出级别低于默认的级别时,不输出日志内容。 
例:

 
  1. import logging
  2. logger_info = logging.getLogger("info_LOG")
  3. logger_kernel = logging.getLogger("kernel_LOG")
  4. #创建不同日志名的日志,可以根据需求,调用不同的日志变量(logger_info或logger_kernel),写入不同的日志里。可以单独给不同的日志设置想要的格式标准等
  5. logger_info.setLevel(logging.DEBUG)
  6. logger_kernel.setLevel(logging.ERROR)
  7. #设置各日志的默认级别
  8. logger_kernel.warning("kernel_test")
  9. logger_info.warning("info_test")
  10. 只输出:info_test
  11. #因logger_kernel的默认级别ERROR高于输出warning级别,故屏幕不输出logger_kernel的warning级别信息

格式化输出日志:

 
  1. import logging
  2. logging.basicConfig(filename='example.log',level=logging.INFO)
  3. logging.debug('This message should go to the log file')
  4. logging.info('So should this')
  5. logging.warning('And this, too')
  6. logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
  7. logging.warning('is when this event was logged.')
  8. #输出
  9. 07/24/2017 11:01:00 AM WARNING is when this event was logged.
 

日志格式:

%(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-08 16:49:45,896”。逗号后面的是毫秒 
%(thread)d 线程ID。可能没有 
%(threadName)s 线程名。可能没有 
%(process)d 进程ID。可能没有 
%(message)s 用户输出的消息

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

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

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

 
  1. logging.StreamHandler() #日志屏幕输出
  2. logging.FileHandler() #日志输出至文件
  3. fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3) #以时间分割日志文件
  4. fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3) #以日志文件大小分割日志文件

filter提供了细度设备来决定输出哪条日志记录;

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

 

屏幕、文件同时输出示例:

 
  1. import logging
  2. from logging import handlers
  3. #创建日志名及默认日志级别
  4. logger_info = logging.getLogger("info_LOG")
  5. logger_info.setLevel(logging.DEBUG)
  6. logger_kernel = logging.getLogger("kernel_LOG")
  7. logger_kernel.setLevel(logging.ERROR)
  8. #实例化屏幕输出、文件输出的变量名。文件输出时,以文件大小进行分割日志
  9. ch = logging.StreamHandler()
  10. fh = handlers.RotatingFileHandler(filename="test_log",maxBytes=1000000,backupCount=30,encoding="utf8")
  11. fh.setLevel(logging.DEBUG)
  12. #定义两种输出格式,以便不同输出方向的日志选择合适的格式
  13. formatter_fh = logging.Formatter('%(asctime)s %(levelname)s %(filename)s %(name)s %(lineno)d %(message)s')
  14. formatter_ch = logging.Formatter('%(asctime)s %(message)s')
  15. ch.setFormatter(formatter_ch)
  16. fh.setFormatter(formatter_fh)
  17. #添加不同的输出方向。想同时多方向输出,这步一定要有
  18. logger_kernel.addHandler(ch)
  19. logger_kernel.addHandler(fh)
  20. logger_info.addHandler(ch)
  21. logger_info.addHandler(fh)
  22. logger_info.info("名为info_log的日志,屏幕、文件同时输出此信息")
  23. logger_kernel.error("名为kernel_log的屏幕、文件同时输出此信息")
  24. 结果:屏幕,文件同时输出上述日志信息
 

re 正在表达式匹配

 
    1. '.' 默认匹配除\n之外的任意一个字符
    2. '^' 匹配字符的开头 #在中括号里是表示非的意思:'[^\d]' 非数字开头。'^\d' 数字开头
    3. '$' 匹配字符的结尾,或e.search("foo$","bfoo\nsdfsf",flags=re.MULTILINE).group()也可以
    4. '*' 匹配*号前的字符0次或多次,re.findall("ab*","cabb3abcbbac") 结果为['abb', 'ab', 'a']
    5. '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb']。必须至少匹配到一个,否则匹配不到时报错
    6. '?' 匹配前一个字符1次或0次。最多匹配一次,匹配不到不报错
    7. '{m}' 匹配前一个字符m
    8. '{n,m}' 匹配前一个字符nm次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb']
    9. '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC'
    10. '(...)' 分组匹配
    11. 例:
    12. re.search("(abc){2}a(123|456)c", "abcabca456c").group()
    13. 结果: abcabca456c
    14. re.search("(abc){2}a(123|456)c", "abcabca456c").groups()
    15. 结果:('abc', '456') #以()内的规则进行搜索,结果返回为列表
    16. '\A' 只从字符开头匹配,re.search("\Aabc","alexabc") 是匹配不到的
    17. '\Z' 匹配字符结尾,同$
    18. '\d' 匹配数字0-9
    19. '\D' 匹配非数字
    20. '\w' 匹配[A-Za-z0-9]
    21. '\W' 匹配非[A-Za-z0-9]
    22. '\s' 匹配空白字符、\t\n\r , re.search("\s","ab\tc1\n3").group() 结果 '\t'
    23. '(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
    24. re.serach()
    25. re.findall()使用场景总结:
    26. re.serach() 只搜索指定字符一次,遇到不符合条件时既停止搜索。搜索到的结果为对象
    27. 例:
    28. print(re.search('\d+','ab3cd45fe3as33d6').group())
    29. 返回结果为 3
    30. re.findall() 按指定的字符或条件搜索整行全部符合条件(1行),搜索到的结果为列表。多行搜索时re.findall('\d+','ab3c\nd45\nfeasd6',flags=re.MULTILINE
    31. print(re.findall('\d+','ab3cd45fe3as33d6'))
    32. 结果: ['3', '45', '3', '33', '6']
    33. print(re.findall('\d','ab3cd45fe3as33d6'))
    34. 结果:['3', '4', '5', '3', '3', '3', '6']

## 作业:计算器

作业要求:

模拟计算器开发:

实现加减乘除及拓号优先级解析

用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致

 

流程图:

 

readme:

1、运行程序,输入计算公式,回车确认,得出计算结果

 

代码:

import re

#特殊字符处理return chars
def symbol_handler(chars):
    '''处理特殊符号'''
    chars = chars.replace("++", "+")
    chars = chars.replace("+-", "-")
    chars = chars.replace("-+", "-")
    chars = chars.replace("--", "+")
    return chars

# 乘除运算return nu_list[0]
def multiply_handler(chars_list):
    chars_list = symbol_handler(chars_list)
    nu_list = re.split("[*/]", chars_list)
    if len(nu_list) == 1:
        nu_list[0] = nu_list[0]
    elif len(nu_list) == 2 and "*" in chars_list:
        nu_list[0] = float(nu_list[0]) * float(nu_list[1])
    elif len(nu_list) == 2 and "/" in chars_list:
        nu_list[0] = float(nu_list[0]) / float(nu_list[1])
    elif len(nu_list) > 2:
        nu_list = re.split("\*", chars_list)
        nu_list_new = []
        for i in nu_list:
            if "/" in i:
                i_list = re.split("/", i)
                for k in range(len(i_list) - 1):
                    k_value = float(i_list[0]) / float(i_list[1])
                    del (i_list[:2])
                    i_list.insert(0, k_value)
                nu_list_new.append(i_list[0])
            else:
                nu_list_new.append(i)
        nu_list = nu_list_new
        for i in range(len(nu_list) - 1):
            k_value = float(nu_list[0]) * float(nu_list[1])
            del (nu_list[:2])
            nu_list.append(k_value)
    return str(nu_list[0])

# 加减运算return nu_list[0]
def add_subtract_handler(add_char_list):
    """
    :param add_char_list:计算只有+-运算符的字符串 
    :return:打印计算结果 
    """
    add_char_list = symbol_handler(add_char_list)  # 处理特殊符号
    nu_list = re.split("[\+-]", add_char_list)
    if len(nu_list) == 1:
        nu_list[0] = nu_list[0]
    elif len(nu_list) == 2:
        if nu_list[0] == "":
            nu_list[0] = "-" + nu_list[1]
        elif nu_list[0] != "" and "-" in add_char_list:
            nu_list[0] = float(nu_list[0]) - float(nu_list[1])
        elif nu_list[0] != "" and "+" in add_char_list:
            nu_list[0] = float(nu_list[0]) + float(nu_list[1])
    elif len(nu_list) > 2:
        nu_list = re.split("\+", add_char_list)  # +分割后的列表
        nu_list_new = []  # 转储用空列表
        for i in nu_list:  # 循环处理分割后的列表
            if "-" in i:
                i_list = re.split("-", i)  # 将有-号的值再分割成列表
                for k in range(len(i_list) - 1):  # 循环计算列表前两个数相减的值,直到只剩一个数
                    if i_list[0] == "":
                        k_new = - float(i_list[1])
                        del (i_list[:2])
                        i_list.insert(0, str(k_new))
                    else:
                        k_new = float(i_list[0]) - float(i_list[1])
                        del (i_list[:2])
                        i_list.insert(0, str(k_new))  # 在列表开头插入新计算出的值继续计算
                nu_list_new.append(i_list[0])  # 将 i处理后的值添加至列表
            else:
                nu_list_new.append(i)  # i不含-号,直接添加至新列表
        nu_list = nu_list_new  # 将nu_list_new的值直接赋值给nu_list
        for i in range(len(nu_list) - 1):
            a = float(nu_list[0]) + float(nu_list[1])
            del (nu_list[:2])
            nu_list.append(a)
    return str(nu_list[0])

# 加减乘除混合运算
def mixture_handler(mixture_char):
    """
    :param mixture_list:混合运算 
    :return: 返回计算结果
    """
    mixture_char = symbol_handler(mixture_char)  # 处理特殊符号
    mixture_char = re.sub("[()]", "", mixture_char)  # 去除()
    num_len = re.split("[\+-]", mixture_char)
    if len(num_len) == 1 and re.search("[*/]", num_len[0]):  # 只有乘除的正数
        mixture_char = multiply_handler(num_len[0])
    elif len(num_len) == 1 and "*" not in num_len[0] and "/" not in num_len[0]:  # 只有一个正数
        mixture_char = mixture_char
    if len(num_len) == 2:
        if num_len[0] == "" and re.search("[*/]", mixture_char):  # 负数开头的乘除
            mixture_char = "-" + multiply_handler(num_len[1])
        elif num_len[0] == "" and '*' not in mixture_char and "/" not in mixture_char:  # 只有负数
            mixture_char = "-" + num_len[1]
        elif num_len[0] != "" and '*' not in mixture_char and "/" not in mixture_char:  # 只有加减的数
            mixture_char = add_subtract_handler(mixture_char)
        elif num_len[0] != "":
            if num_len[0].endswith("/") or num_len[0].endswith("*"):
                # 有乘除和/- 的数
                mixture_char = multiply_handler(mixture_char)
            elif "-" in mixture_char and re.search("[*/]", mixture_char):
                # 有乘除和-的数
                mixture_char = float(multiply_handler(num_len[0])) - float(multiply_handler(num_len[1]))
            elif "+" in mixture_char and re.search("[*/]", mixture_char):
                # 有乘除和+的数
                mixture_char = float(multiply_handler(num_len[0])) + float(multiply_handler(num_len[1]))
    elif len(num_len) > 2 and re.search("[*/]", mixture_char):
        mixture_list = re.split("[+-]", mixture_char)
        if "*" or "/" in mixture_list:  # 判断列表值含有*/或者/- *-特殊运算符
            for i in mixture_list:
                if i.endswith("/") or i.endswith("*"):  # 先判断/- *-特殊运算符
                    i_next_index = mixture_list.index(i) + 1  # i下一位数的下标
                    i_new = i + "-" + mixture_list[i_next_index]
                    i_new_value = multiply_handler(i_new)
                    mixture_char = mixture_char.replace(i_new, i_new_value)  # 替换/-或者*-特殊组合
                    mixture_char = symbol_handler(mixture_char)
                    continue
                elif "*" in i or "/" in i:
                    i_value = multiply_handler(i)
                    mixture_char = mixture_char.replace(i, i_value)  # 替换/或者*组合
                    mixture_char = symbol_handler(mixture_char)
        else:
            mixture_char = add_subtract_handler(mixture_char)
        mixture_char = add_subtract_handler(mixture_char)
    return str(mixture_char)

#去除()计算字符串
def calc(a):
    """
    :param a:去除最底层括号 
    :return: 括号内的值替换原括号的内容
    """
    while True:
        if "(" in a :
            b_list = re.findall(r'\([^()]+\)', a)  # 提取最底层()列表
            for i in b_list:
                i_new = mixture_handler(i)
                a = a.replace(i,i_new)
                a = symbol_handler(a)
        else:
            break
    print("\033[31;1m %s\033[0m " %mixture_handler(a))

# a = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
while True:
    a = input("输入需要计算的公式,或输入“b”退出:\n>>")
    a = re.sub(" ","",a)
    if a.upper() == "B" :
        break
    else:
        calc(a)

 

posted @ 2017-07-13 11:31  海子口  阅读(226)  评论(0编辑  收藏  举报