第六章:Python基础の反射与常用模块解密

Posted 代码艺术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第六章:Python基础の反射与常用模块解密相关的知识,希望对你有一定的参考价值。

本课主题

  • 反射 Mapping 介绍和操作实战
  • 模块介绍和操作实战
  • random 模块
  • time 和 datetime 模块
  • logging 模块
  • sys 模块
  • os 模块
  • hashlib 模块
  • re 模块
  • 本周作业

 

反射 Mapping 介绍和操作实战

反射是利用字符串的形式去对象 (模块) 中操作 (寻找/检查/删除/设置) 成员,以後看其他源碼的時候會經常看到反射,最有代表性的就是 Tornado 和 Django 框架

案例例子

假设创建了一个common.py,程序里有3个功能,比如网站里的登录页面、主页页面和登出页面都是不同的页面,要显示的内容都不一样。

def login():
    print("Login Page")

def logout():
    print("Logout Page")

def home():
    print("HomePage")
common.py

再创建一个py程序:index.py,程序一般是写一个判断然后会基于调用不同的功能返回不同的结果(参考调用方法一的代码)。

import common

#根据用户不同的输入而返回不同的信息
def run():
    inp = input("请输入要访问的 url: ")
    if inp == "login": # 当用户输入 login,还看到 login 页面
        common.login() 
    elif inp == "logout": # 当用户输入 logout,还看到 logout 页​​面
        common.logout() 
    elif inp == "home": # 当用户输入 home,还看到 home 页面
        common.home()
    else:
        print("404")

if __name__ == "__main__":
    run()
index.py 调用方法一

这个时候,就可以运用反射的方法(参考调用方法二的代码),直接基于用户输入,返回需要執行的功能,这样就可以减少判断逻辑代码需要的时间。

# 利用字符串的形式去对象 (模块) 中操作 (寻找/检查) 成员

import common

def run():
    inp = input("请输入要访问的 url: ")
    is_exists = hasattr(common,inp) # 检查用户输入是否在common模块里存在的一个成员
    if is_exists:
        func = getattr(common, inp) # 到common模块寻找用户输入的一个成员
        func()
    else:
        print("404")


if __name__ == "__main__":
    run()
index.py 调用方法二

运用 hasattr( ) 、 getattr( )、delattr( )、setattr( ) 函数来实现,這几個反射函数分別接收兩個参数(参数一可以是模块, 参数二是参数一的成員 - 它接受一个字符串类型的成员名称),比如说:如果 common 模块里有 login( ) 函数,在调用反射时,基本代码语法是 hasattr(s2,"login")

#s2.py
def login():
    print("login....")

#s1.py
import s2

if hasattr(s2,"login"):
    func = getattr(s2, "login") #接受字符串类型的成员名称
    func()

"""
login....
"""
反射基本代码语法
hasattr(参数一,参数二) # 到模块里检查成员
#参数一可以是模块, 参数二是参数一的成员
getattr(参数一,参数二) # 到模块里寻找成员
#参数一可以是模块, 参数二是参数一的成员
delattr(参数一,参数二) # 到模块裡把這個成員删掉
#参数一可以是模块, 参数二是参数一的成员
setattr(参数一,参数二) # 到模块裡再设置一個成員
#参数一可以是模块, 参数二是参数一的成员

在这里我们需要了解一下导入模块的方法,有以下两個方法:

  1. 第一是 import package_name / import package_name as alias_name
    import common
    import common as obj
    
    obj.f1( )
    import "package_name"
  2. 第二是 obj = __import__("package_name"),然后基于对象名称去调用它的方法,可以通过字符串的形式导入模块。
    obj = __import__("common")
    obj.f1( )
    __import__( )方式一

    这里调用的__import__(“common”),默认只能导入第一层的模块,也就是说如果你需要传入lib.account.xxxxx的话,此时你需要加入一个参数,意思说你写入的路径是什么我就导入什么。

    obj = __import__("lib. " + m, fromlist = True)
    obj.f1( )
    __import__( )方式二

    你可以调用 split( ) 方法把模块的路径进行分割,然后传入__import__(m),这样你就可以把正确的模块导入到程序里。

    >>> inp = "account/login"
    >>> inp.split("/")
    [\'account\', \'login\']
    
    >>> m,f = inp.split("/")
    
    >>> m
    \'account\'
    
    >>> f
    \'login\'
    split("/")
    def run():
        inp = input("请输入要访问的 url: ")
        m,f = inp.split("/")
        obj = __import__(m)
    
        if hasattr(obj,f):
            func = getattr(obj, f)
            func()
        else:
            print("404")
    
    if __name__ == "__main__":
        run()
    
    """
    account/login
    >> Login Page...
    """
    index.py 调用方法三

     

模块介绍和操作实战

random 模块

random( ) 函数是用来随机生成数字

fruits = [\'apple\',\'banana\',\'orange\',\'coconuts\',\'straweberry\',\'lemon\',\'kumquat\',\'blueberry\',\'melon\']
random.randint(1,10) #随机获取1到10的数字
>>> 10
random.randrange(1,10) #随机获取1到10的数字
>>> 5
random.sample(fruits, k=5) #从集合中随机获取k个元素
>>> [\'orange\', \'apple\', \'blueberry\', \'banana\', \'lemon\']
random.choice(fruits) #从集合中随机获取其中一个元素
>>> \'orange\'
random.shuffle(fruits) #把集合中的元素打乱
#[\'straweberry\', \'apple\', \'melon\', \'blueberry\', \'orange\', \'lemon\', \'kumquat\', \'banana\', \'coconuts\']
random 常用函数
import random

word_list = []
for i in range(6):
    random_num = random.randrange(0, 5)
    if random_num == 2 or random_num == 4:
        num = random.randrange(0, 10)
        word_list.append(str(num))
    else:
        temp = random.randrange(65, 91)
        word = chr(temp) # 把数字变字母
        word_list.append(word)

words = "".join(word_list)
print(words)

"""
F69Y2G
"""
random( )函数

 

time 模块

0   tm_year     年
1   tm_mon      月
2   tm_mday     日
3   tm_hour     时
4   tm_min      分
5   tm_sec      秒
6   tm_wday     一周中的第几天
7   tm_yday     一年中的第几天
8   tm_isdst    夏令时
时间元组各项含义
  1. 从1970年1月1号12:00am 开始计算的一个时间戳 Unix timestamp
    import time
    
    >>> print(time.time())
    1473427097.89171
    time.time()
  2. 返回当前系统时间转换成 字符串类型
    import time
    
    >>> print(time.ctime()) 
    Fri Sep  9 21:28:13 2016
    
    >>> print(time.ctime(time.time()-86400))
    Thu Sep  8 21:29:06 2016
    time.ctime( )
  3. 返回当前系统时间转换成 struct_time类型
    >>> import time
    
    >>> time_obj = time.gmtime() 
    
    >>> print(time_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=13, tm_min=29, tm_sec=41, tm_wday=4, tm_yday=253, tm_isdst=0)
    
    >>> print(time_obj.tm_year,time_obj.tm_mon)
    2016 9
    
    >>> type(time_obj)
    <class \'time.struct_time\'>
    
    >>> ret = "Year={year} Month={mnth}".format(year=time_obj.tm_year,mnth=time_obj.tm_mon)
    
    >>> print(ret)
    Year=2016 Month=9
    
    >>> time_pre_obj = time.gmtime(time.time()-86400) # 返回struct_time类型
    >>> print(time_pre_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=8, tm_hour=13, tm_min=34, tm_sec=49, tm_wday=3, tm_yday=252, tm_isdst=0)
    time.gmtime( )
  4. 按本地时间来显示时间,并且返回 struct_time类型
    >>> print(time.localtime())
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=38, tm_sec=47, tm_wday=4, tm_yday=253, tm_isdst=0)
    
    >>> time_obj = time.localtime()
    
    >>> print(time_obj)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=38, tm_sec=59, tm_wday=4, tm_yday=253, tm_isdst=0)
    
    >>> type(time_obj)
    <class \'time.struct_time\'>
    time.localtime( )
  5. 把一个struct_time类型转换成时间戳
    >>> print(time.mktime(time_obj)) 
    1473428339.0
    time.mktime( )
  6. 让时间睡眠
    >>> time.sleep(4) 
    >>> print("--------")
    time.sleep( )
  7. 將 struct_time 类型转换成字符串类型 (from struct_time to string)
    >>> print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime())) 
    2016-09-09 13:47:50
    
    >>> print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()))
    2016-09-09 21:47:51
    time.strftime( )
  8. 將字符串类型转换成 struct_time 类型 (from string to struct_time)
    >>> tm = time.strptime("2016-09-03","%Y-%m-%d")  # 將字符串类型转换成struct_time类型
    
    >>> print(tm)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=3, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=247, tm_isdst=-1)
    
    >>> type(tm)
    <class \'time.struct_time\'>
    
    >>> print(time.mktime(tm)) 
    1472832000.0
    time.strptime( )

 

Datetime 模块

  1. 输出:2016-09-03
    >>> import datetime
    >>> d1 = datetime.date.today()
    >>> print(d1)
    datetime.date.today()
  2. 时间戳直接转成日期格式 2016-08-19
    >>> d2 = datetime.date.fromtimestamp(time.time());
    >>> print(d2)
    2016-09-09
    datetime.date.fromtimestamp()
  3. current time
    >>> current_time = datetime.datetime.now()
    >>> print(current_time)
    2016-09-09 21:59:45.125933
    datetime.datetime.now()
  4. 返回  struct_time 类型
    >>> t = current_time.timetuple()
    
    >>> print(t)
    time.struct_time(tm_year=2016, tm_mon=9, tm_mday=9, tm_hour=21, tm_min=59, tm_sec=45, tm_wday=4, tm_yday=253, tm_isdst=-1)
    
    >>> type(t)
    <class \'time.struct_time\'>
    timetuple( )
  5. 时间的加减在Python中会调用datetime.timedelta ( )
    >>> d3 = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    
    >>> print(d3) 
    2016-09-09 22:03:29
    
    >>> new_date = datetime.datetime.now() + datetime.timedelta(days=10)
    >>> print(new_date)
    2016-09-19 22:03:38.745696
    
    >>> new_hour = datetime.datetime.now() + datetime.timedelta(hours=4)
    >>> print(new_hour)
    2016-09-10 02:03:41.642530
    
    >>> new_hour = datetime.datetime.now() + datetime.timedelta(hours=4)
    >>> print(new_hour)
    2016-09-10 02:03:44.630359
    时间的加减
  6. datetime.datetime.strptime( )
    >>> tm = datetime.datetime.strptime("2016-09-03","%Y-%m-%d")
    >>> print(tm)
    2016-09-03 00:00:00
    strptime( )
  7. replace( )
    >>> current_time = datetime.datetime.now()
    >>> print(current_time)
    2016-09-09 22:07:10.352970
    
    >>> replace_time = current_time.replace(2015,5)
    >>> print(replace_time)
    2015-05-09 22:07:10.352970
    
    >>> print(type(current_time))
    <class \'datetime.datetime\'>
    
    >>> print(type(replace_time))
    <class \'datetime.datetime\'>
    replace( )

Date Format

格式    含义                        取值范围(格式)
%y        去掉世纪的年份                   00~99,如 "15"
%Y        完整的年份                     如 "2015"
%j        指定日期是一年中的第几天              001~366
%m        返回月份                      01~12
%b        本地简化月份的名称                 简写英文月份
%B        本地完整月份的名称                 完整英文月份
%d        该月的第几日                    如5月1日返回 "01"
%H        该日的第几时(24小时)                00~23
%l        该日的第几时(12小时)                01~12
%M        分种                        00~59
%S        秒                         00~59
%U        在该年中的第多少星期(以每周日为一周的起点)        00~53
%W        在该年中的第多少星期(以每周一为一周的起点)        00~53
%w        一星期中的第几天                  0~6
%Z        时区                        中国返回CST,即China Standard Time
%x        日期                        日/月/%X        时间                        时:分:秒
%c        详细日期时间                    日/月/年 时:分:秒
%%        \'%\'字符                      \'%\'字符
%p        上下午                       AM or PM
format格式定义

  

logging 模块

logging 基础

每个程序都需要有日志记录,日志有几个级别:1. DEBUG; 2.INFO; 3. WARNING; 4.ERROR; 5.CRITICAL

import logging

logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down")

logging.debug(\'This message should go to the log file\')
logging.info(\'So should this\')
logging.warning(\'And this, too\')

#WARNING:root:User [alex] attempt wrong password for more than 3 times
#CRITICAL:root:Server is down
#WARNING:root:And this, too
logging

想输出日志到文件可以调用以下函数,filename: 文件名,filemode: 写入模式,level: 日志的级别 (跟这个级别同等或者是比这个更高级别的日志才会写入文件)

logging.basicConfig(filename=\'log.txt\',filemode=\'w\',level=logging.INFO)

把 basicConfig 加到程序中然后执行程序,因为日志级别是INFO,所以这里的结果是只有INFO级别或以上的,才会写入log.txt的文件里

import logging

logging.basicConfig(filename=\'log.txt\',filemode=\'w\',level=logging.INFO)

logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down")
logging.debug(\'This message should go to the log file\')
logging.info(\'So should this\')
logging.warning(\'And this, too\')

#log.txt 会有INFO级别或以上的日志
"""
WARNING:root:User [alex] attempt wrong password for more than 3 times
CRITICAL:root:Server is down
INFO:root:So should this
WARNING:root:And this, too
"""
Log写进文件的例子

basicConfig可以传入很多不同的参数

logging.basicConfig(filename=\'log.txt\',
                    level=logging.DEBUG,
                    format=\'%(asctime)s %(message)s\',
                    datefmt=\'%m/%d/%Y %I:%M:%S %p\')
import logging

logging.basicConfig(filename=\'log.txt\',
                    level=logging.DEBUG,
                    format=\'%(asctime)s %(message)s\',
                    datefmt=\'%m/%d/%Y %I:%M:%S %p\')

logging.warning("User [alex] attempt wrong password for more than 3 times")
logging.critical("Server is down")
logging.debug(\'This message should go to the log file\')
logging.info(\'So should this\')
logging.warning(\'And this, too\')

# log.tx.
"""
09/09/2016 11:15:35 PM User [alex] attempt wrong password for more than 3 times
09/09/2016 11:15:35 PM Server is down
09/09/2016 11:15:35 PM This message should go to the log file
09/09/2016 11:15:35 PM So should this
09/09/2016 11:15:35 PM And this, too
"""
Log写进文件的例子二

logging 进阶

如果想打印日志到文件和 Console 上,必须先了解以下几个概念:

  1. 第一步,创建 Logger,然后设置全区的日志级别。(会比较全区和区部的日志级别,较高的那个会成为该日志输出级别)
    logger = logging.getLogger(\'TEST-LOG\')
    logger.setLevel(logging.INFO) #configure a global logging level
    logger
  2. 第二步、创建Console Handler 对象,也可以设置 Console 控制台的日志级别,不可以比全区的日志记录级别小,CRITICAL> ERROR> WARNING> INFO> DEBUG。也就是说这两个日志记录级别会比较然后选出最大的那个日志记录级别
    console_handler = logging.StreamHandler() #print the log on the console
    console_handler.setLevel(logging.DEBUG)
    console_handler
  3. 第三步、创建File Handler 对象,也可以设置 File Handler 的日志级别。