day05 Python多层装饰器、模块、序列化、字符串格式化、生成器和迭代器、递归、time、datetime模块、logging模块

一、多层装饰器

需求如下:

    程序运行时需判断当前是否有用户登录,以及当前登录的用户名是否为管理员账户,但有的函数只需判断当前是否有用户登录就可以,有的函数两个都需要判断,所以将这两个判断分开写成两个装饰器,在需要判断时直接使用相应的一个或两个装饰器即可,具体代码如下:

#!/usr/bin/env python
# -*- coding:utf-8 -*-


#保存当前登录的账户名及账户类型(管理员为2,普通用户为1)
USER_INFO = {}

def check_login(func):
    """
    判断当前是否有用户登录的装饰器
    :param func:
    :return:
    """
    def inner(*args, **kwargs):
        if USER_INFO.get('is_login', None):
            ret = func(*args, **kwargs)
            return ret
        else:
            return ('请登录')
    return inner

def check_admin(func):
    """
    装饰器:用来判断当前所登录用户的类型是普通账户还是管理员账户
    :param func:
    :return:
    """
    def inner(*args, **kwargs):
        if USER_INFO.get('user_type', None) == 2:
            ret = func(*args, **kwargs)
            return ret
        else:
            return ('无权限查看')
    return inner

def login():
    """
    登录函数
    :return:
    """
    username = input("请输入用户名: ")
    password = input("请输入密码:")
    if username == 'ordinary' and password == '123':
        USER_INFO['is_login'] = True
        USER_INFO['user_type'] = 1
        return ("欢迎访问")
    elif username == 'admin' and password == '456':
        USER_INFO['is_login'] = True
        USER_INFO['user_type'] = 2
        return ("欢迎管理员登录")
    else:
        return "用户名或密码错误"

@check_login
@check_admin
def index_admin():
    """
    管理员的功能
    管理员的功能需要判断当前是否有用户登录,以及当前登录的用户是否为管理员账户,所以这里要用到两个装饰器
    :return:
    """
    return ('管理员的功能')

@check_login
def index_ordinary():
    """
    普通账户的功能
    :return:
    """
    return "普通用户的功能"

def run():
    """
    前端
    :return:
    """
    dict_choice = {'1':login,'2':index_admin,'3':index_ordinary}
    while True:
        print("1: 登录\n2: 管理员功能\n3: 普通用户功能")
        user_choice = input("请输入项目编号(输入'q'结束程序):")
        if user_choice in dict_choice.keys():
            res = dict_choice[user_choice]()
            print(res)
        elif user_choice == 'q':
            break
        else:
            print("你的输入有误,请重新输入")

if __name__ == '__main__':
    run()

双层装饰器执行图解:

QQ图片20160612115035

二、模块

Python的模块分为三类:

1、内置模块(python自带的比如os、file等模块)

2、自定义模块,自己写的模块

3、第三方模块

 

导入模块的方法:

单模块:
 import xxx
嵌套在文件夹下:
from xxx import xxx(*)     #导入某模块下的指定模块(或全部模块)
from xxx import xxx  as ooo   #导入指定模块并给他设置别名 

三、序列化(json和pickle)

Python的序列化有两个模块可以实现,json和pickle模块

这两个模块的区别在于json更适合跨语言,而pickle仅适用于Python,且pickle能对Python的所有类型进行序列化

通过序列化我们可以实现以下目的:

1、将Python基本数据类型转化为字符串形式

2、将字符串形式转化为Python基本数据类型

import json
# 将python基本数据类型转化成字符串形式
dic = {'k1': 'v1'}
print(dic,type(dic))
result = json.dumps(dic)
print(result,type(result))

# 将python字符串形式转化成基本数据类型
s1 = '{"k1": 123}'
dic = json.loads(s1)    # 反序列化时,一定要使用 "
print(dic,type(dic))



#利用json将Python中的除字符串外的数据类型写入到文件中
#这个过程也是将Python的基本数据类型序列化为字符串形式,然后写入到文件中
li = [11,22,33]
json.dump(li,open('db','w'))

#利用json将文件中读取出的数据序列化为Python的基本数据类型
li = json.load(open('db','r'))
print(type(li),li)

pickle的用法和json的用法类似,这里就不再重复写了

四、字符串格式化

Python的字符创格式化也有两种方式,一个是使用format,另一个是使用%

%用法:
格式符为真实值预留位置,并控制显示的格式。格式符可以包含有一个类型码,用以控制显示的类型,如下:

%s    字符串 (采用str()的显示)
%r    字符串 (采用repr()的显示)
%c    单个字符
%b    二进制整数
%d    十进制整数
%i    十进制整数
%o    八进制整数
%x    十六进制整数
%e    指数 (基底写为e)
%E    指数 (基底写为E)
%f    浮点数
%F    浮点数,与上相同
%g    指数(e)或浮点数 (根据显示长度)
%G    指数(E)或浮点数 (根据显示长度)
%%    字符"%"   (当格式化时,字符串中出现占位符 %s.. 需要用 %% 输出 %)

eg:
print("I'm %s. I'm %d year old" % ('xuanouba', 18))
print("I'm %(name)s. I'm %(age)d year old" % {'name':'xuanouba', 'age':18})

可以用如下的方式,对格式进行进一步的控制:

%[(name)][flags][width].[precision]typecode
(name)为命名
flags可以有+,-,' '或0。+表示右对齐。-表示左对齐。' '为一个空格,表示在正数的左侧填充一个空格,从而与负数对齐。0表示使用0填充。
width表示显示宽度
precision表示小数点后精度

eg:
print("%+10x" % 10)
print("%04d" % 5)
print("%6.3f" % 2.3)
format用法:
自python2.6开始,新增了一种格式化字符串的函数str.format()

'b' - 二进制. 将数字以2为基数进行输出.
'c' - 字符. 在打印之前将整数转换成对应的Unicode字符串.
'd' - 十进制整数. 将数字以10为基数进行输出.
'o' - 八进制. 将数字以8为基数进行输出. 
'x' - 十六进制. 将数字以16为基数进行输出, 9以上的位数用小写字母.
'e' - 幂符号. 用科学计数法打印数字, 用'e'表示幂. 
'g' - 一般格式. 将数值以fixed-point格式输出. 当数值特别大的时候, 用幂形式打印. 
'n' - 数字. 当值为整数时和'd'相同, 值为浮点数时和'g'相同. 不同的是它会根据区域设置插入数字分隔符. 
'%' - 百分数. 将数值乘以100然后以fixed-point('f')格式打印, 值后面会有一个百分号. 

它通过{}和:来代替%。
通过占位符:
print("I'm {},I'm {} year old".format('xuanouba',18))
通过位置进行映射:
print("I'm {0},I‘m {0},I'm {1} year old".format('xuanouba',18))  #下标可重复使用
通过指定key:
print("I'm {name},I'm {age} year old".format(name='xuanouba',age=18))  
#这几种方式也可以混着用

格式控制:
可以指定所需长度的字符串的对齐方式:
< (默认)左对齐
> 右对齐
^ 中间对齐
= (只用于数字)在小数点后进行补齐

eg:
print('{:>8}'.format('189'))    #填充与对齐
print('{:.2f}'.format(321.33345)    )   #精度
#用,号还能用来做金额的千位分隔符:
print('{:,}'.format(1234567890))

五、生成器和迭代器

python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。

迭代器(iterator)

迭代器用来为类序列对象提供一个类序列的接口。迭代器就是生成一个有next()方法的对象,而不是通过索引来计数。

序列、字典、文件中当使用for x in y的结构时,其实质就是迭代器,迭代器是和实际对象绑定在一起的,所以在使用迭代器时或者上述3者时不能修改可变对象的值。这会产生错误。如:在使用for x in y的结构来遍历字典时删除符合条件的字典内容,这会导致报错。

创建迭代器的方法:iter(object)和iter(func,sentinel)两种。一种使用的是序列,另一种使用类来创建。

迭代器代码示例:
def eg():
    print(11)
    yield 1
    print(22)
    yield 2
    print(33)
    yield 3

res = eg()
for i in range(3):
    last_res = res.__next__()
    print(last_res)

生成器

生成器是特定的函数,允许你返回一个值,然后“暂停”代码的执行,稍后恢复。生成器使用了“延迟计算”,所以在内存上面更加有效。

生成器表达式:(expr for iter_var in iterable if cond_expr)

利用生成器写一个自己的range函数
def myrange(arg):
    start = 0
    while True:
        if start == arg:
            break
        yield start
        start += 1


res = myrange(10)
for i in res:
    print(i)

详细解释链接:http://www.cnblogs.com/kaituorensheng/p/3826911.html

六、递归:

如果函数包含了对其自身的调用,该函数就是递归的:

eg:

def func(n):
    n += 1
    if n >= 4:
        return 'end'
    return func(n)


res = func(1)
print(res)
def digui(num):
    if num == 1:
        return num
    return num * digui(num-1)

res = digui(5)
print(res)

这里插入一些关于递归的网方解释,因为我是从网上搜到的这些内容:
(1)递归就是在过程或函数里调用自身;
(2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。

递归算法一般用于解决三类问题:
(1)数据的定义是按递归定义的。(比如Fibonacci函数)
(2)问题解法按递归算法实现。(回溯)
(3)数据的结构形式是按递归定义的。(比如树的遍历,图的搜索)

递归的缺点:递归算法解题的运行效率较低。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等

七、time,datetime模块

print(time.clock()) #返回处理器时间,3.3开始已废弃
print(time.process_time()) #返回处理器时间,3.3开始已废弃
print(time.time()) #返回当前系统时间戳
print(time.ctime()) #输出Tue Jan 26 18:23:48 2016 ,当前系统时间
print(time.ctime(time.time()-86640)) #将时间戳转为字符串格式
print(time.gmtime(time.time()-86640)) #将时间戳转换成struct_time格式
print(time.localtime(time.time()-86640)) #将时间戳转换成struct_time格式,但返回 的本地时间
print(time.mktime(time.localtime())) #与time.localtime()功能相反,将struct_time格式转回成时间戳格式
#time.sleep(4) #sleep
print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将struct_time格式转成指定的字符串格式
print(time.strptime("2016-01-28","%Y-%m-%d") ) #将字符串格式转换成struct_time格式
 
#datetime module
 
print(datetime.date.today()) #输出格式 2016-01-26
print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 将时间戳转成日期格式
current_time = datetime.datetime.now() #
print(current_time) #输出2016-01-26 19:04:30.335935
print(current_time.timetuple()) #返回struct_time格式
 
#datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]])
print(current_time.replace(2014,9,12)) #输出2014-09-12 19:06:24.074900,返回当前时间,但指定的值将被替换
 
str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #将字符串转换成日期格式
new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比现在加10天
new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比现在减10天
new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比现在减10小时
new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比现在+120s
print(new_date)

eg:

import datetime,time

#根据日期得到时间戳以及struct_time对象
start_time = datetime.date.today()    #今天日期
str_start_time = str(start_time)     #将日期转化为字符串格式
start_time_struct = time.strptime(str_start_time,"%Y-%m-%d")    #将字符串格式的日期转化为struct_time对象
start_time_chuo = time.mktime(start_time_struct) + 28800   #将字符串格式的日期转化为时间戳,时间戳默认是从格林威治时间算起

#根据时间戳得到struct_time对象以及日期
ref_time_struct = time.gmtime(start_time_chuo)      #将时间戳转化为struct_time对象
ref_time = time.strftime('%Y-%m-%d',ref_time_struct)   #将struct_time对象转化为日期

posted on 2016-06-12 12:00  宣欧巴  阅读(215)  评论(0编辑  收藏  举报