Python之路,Day4 - Python基础4 (new版)

1. 迭代器&生成器
2. 装饰器
3. Json & pickle 数据序列化
4. 软件目录结构规范
5. 作业:ATM项目开发

1.列表生成式，迭代器&生成器

列表生成式

>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = []
>>> for i in a:b.append(i+1)
...
>>> b
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = b
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

a = [1,3,4,6,7,7,8,9,11]for index,i in enumerate(a):    a[index] +=1print(a)原值修改
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x101d2c630>
>>> for i in a:print(i)
...
2
3
4
5
6
7
8
9
10
11

>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成器

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>


>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration


>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
...
0
1
4
9
16
25
36
49
64
81


generator非常强大。如果推算的算法比较复杂，用类似列表生成式的for循环无法实现的时候，还可以用函数来实现。

1, 1, 2, 3, 5, 8, 13, 21, 34, ...

def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a + b
n = n + 1
return 'done'


a, b = b, a + b


t = (b, a + b) # t是一个tuple
a = t[0]
b = t[1]


>>> fib(10)
1
1
2
3
5
8
13
21
34
55
done


def fib(max):
n,a,b = 0,0,1

while n < max:
#print(b)
yield  b
a,b = b,a+b

n += 1

return 'done' 

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

data = fib(10)
print(data)

print(data.__next__())
print(data.__next__())
print("干点别的事")
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())
print(data.__next__())

#输出
<generator object fib at 0x101be02b0>
1
1

2
3
5
8
13

在上面fib的例子，我们在循环过程中不断调用yield，就会不断中断。当然要给循环设置一个条件来退出循环，不然就会产生一个无限数列出来。

>>> for n in fib(6):
...     print(n)
...
1
1
2
3
5
8

>>> g = fib(6)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
Generator return value: done


#_*_coding:utf-8_*_
__author__ = 'Alex Li'

import time
def consumer(name):
print("%s 准备吃包子啦!" %name)
while True:
baozi = yield

print("包子[%s]来了,被[%s]吃了!" %(baozi,name))

def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i)

producer("alex")

迭代器

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False


*可以被next()函数调用并不断返回下一个值的对象称为迭代器：Iterator

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False


listdictstrIterable变成Iterator可以使用iter()函数：

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True


Iterator甚至可以表示一个无限大的数据流，例如全体自然数。而使用list是永远不可能存储全体自然数的。

Python的for循环本质上就是通过不断调用next()函数实现的，例如：

for x in [1, 2, 3, 4, 5]:
pass


# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break

2.装饰器

def home():
print("---首页----")

def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan():
print("----河南专区----")


#_*_coding:utf-8_*_

user_status = False #用户登录了就把这个改成True

_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status

if user_status == False:

user_status = True
else:
else:
print("用户已登录，验证通过...")

def home():
print("---首页----")

def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan():
print("----河南专区----")

home()
america()
henan()


• 封闭：已实现的功能代码块不应该被修改
• 开放：对现有功能的扩展开放

#_*_coding:utf-8_*_

user_status = False #用户登录了就把这个改成True

_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status

if user_status == False:

user_status = True
else:

if user_status == True:
func() # 看这里看这里，只要验证通过了，就调用相应功能

def home():
print("---首页----")

def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan():
print("----河南专区----")

home()
# home()
# america()


def plus(n):
return n+1

plus2 = lambda x:x+1


calc = plus

calc(n)


home()
# home()
# america()


home()


home()
america = login(america) #你在这里相当于把america这个函数替换了

#那用户调用时依然写
america()


def login(func): #把要执行的模块从这里传进来

def inner():#再定义一层函数
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status

if user_status == False:

user_status = True
else:

if user_status == True:
func() # 看这里看这里，只要验证通过了，就调用相应功能



america = login(america) #你在这里相当于把america这个函数替换了


@login
def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan():
print("----河南专区----")


#_*_coding:utf-8_*_

user_status = False #用户登录了就把这个改成True

def inner(*args,**kwargs):#再定义一层函数
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status

if user_status == False:

user_status = True
else:

if user_status == True:
func(*args,**kwargs) # 看这里看这里，只要验证通过了，就调用相应功能

def home():
print("---首页----")

def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan(style):
'''
:param style: 喜欢看什么类型的，就传进来
:return:
'''
print("----河南专区----")

home()
# america = login(america) #你在这里相当于把america这个函数替换了

# #那用户调用时依然写
america()

henan("3p")


第二2天早上，产品经理又提了新的需求，要允许用户选择用qq\weibo\weixin认证，此时的你，已深谙装饰器各种装逼技巧，轻松的就实现了新的需求。

#_*_coding:utf-8_*_

user_status = False #用户登录了就把这个改成True

def auth(func):
def inner(*args,**kwargs):#再定义一层函数
if auth_type == "qq":
_username = "alex" #假装这是DB里存的用户信息
_password = "abc!23" #假装这是DB里存的用户信息
global user_status

if user_status == False:

user_status = True
else:

if user_status == True:
return func(*args,**kwargs) # 看这里看这里，只要验证通过了，就调用相应功能
else:
print("only support qq ")

return auth

def home():
print("---首页----")

def america():
print("----欧美专区----")

def japan():
print("----日韩专区----")

def henan(style):
'''
:param style: 喜欢看什么类型的，就传进来
:return:
'''
print("----河南专区----")

home()
# america = login(america) #你在这里相当于把america这个函数替换了

# #那用户调用时依然写
america()

# henan("3p")

4.软件目录结构规范

为什么要设计好目录结构?

"设计项目目录结构"，就和"代码编码风格"一样，属于个人风格问题。对于这种风格上的规范，一直都存在两种态度:

1. 一类同学认为，这种个人风格问题"无关紧要"。理由是能让程序work就好，风格问题根本不是问题。
2. 另一类同学认为，规范化能更好的控制程序结构，让程序具有更高的可读性。

1. 可读性高: 不熟悉这个项目的代码的人，一眼就能看懂目录结构，知道程序启动脚本是哪个，测试目录在哪儿，配置文件在哪儿等等。从而非常快速的了解这个项目。
2. 可维护性高: 定义好组织规则后，维护者就能很明确地知道，新增的哪个文件和代码应该放在什么目录之下。这个好处是，随着时间的推移，代码/配置的规模增加，项目结构不会混乱，仍然能够组织良好。

目录组织方式

Foo/
|-- bin/
|   |-- foo
|
|-- foo/
|   |-- tests/
|   |   |-- __init__.py
|   |   |-- test_main.py
|   |
|   |-- __init__.py
|   |-- main.py
|
|-- docs/
|   |-- conf.py
|   |-- abc.rst
|
|-- setup.py
|-- requirements.txt


1. bin/: 存放项目的一些可执行文件，当然你可以起名script/之类的也行。
2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码； (3) 程序的入口最好命名为main.py
3. docs/: 存放一些文档。
4. setup.py: 安装、部署、打包的脚本。
5. requirements.txt: 存放软件依赖的外部Python包列表。
6. README: 项目说明文件。

1. 软件定位，软件的基本功能。
2. 运行代码的方法: 安装环境、启动命令等。
3. 简要的使用说明。
4. 代码目录结构说明，更详细点可以说明软件的基本原理。
5. 常见问题说明。

setup.py

1. 安装环境时经常忘了最近又添加了一个新的Python包，结果一到线上运行，程序就出错了。
2. Python包的版本依赖问题，有时候我们程序中使用的是一个版本的Python包，但是官方的已经是最新的包了，通过手动安装就可能装错了。
3. 如果依赖的包很多的话，一个一个安装这些依赖是很费时的事情。
4. 新同学开始写项目的时候，将程序跑起来非常麻烦，因为可能经常忘了要怎么安装各种依赖。

setup.py可以将这些事情自动化起来，提高效率、减少出错的概率。"复杂的东西自动化，能自动化的东西一定要自动化。"是一个非常好的习惯。

requirements.txt

1. 方便开发者维护软件的包依赖。将开发过程中新增的包添加进这个列表中，避免在setup.py安装依赖时漏掉软件包。
2. 方便读者明确项目使用了哪些Python包。

注意，在上面的目录结构中，没有将conf.py放在源码目录下，而是放在docs/目录下。

1. 配置文件写在一个或多个python文件中，比如此处的conf.py。
2. 项目中哪个模块用到这个配置文件就直接通过import conf这种形式来在代码中使用配置。

1. 这让单元测试变得困难（因为模块内部依赖了外部配置）
2. 另一方面配置文件作为用户控制程序的接口，应当可以由用户自由指定该文件的路径。
3. 程序组件可复用性太差，因为这种贯穿所有模块的代码硬编码方式，使得大部分模块都依赖conf.py这个文件。

1. 模块的配置都是可以灵活配置的，不受外部配置文件的影响。
2. 程序的配置也是可以灵活控制的。

5.本节作业

1. 额度 15000或自定义
2. 实现购物商城，买东西加入 购物车，调用信用卡接口结账
3. 可以提现，手续费5%
4. 每月22号出账单，每月10号为还款日，过期未还，按欠款总额 万分之5 每日计息
5. 支持多账户登录
6. 支持账户间转账
7. 记录每月日常消费流水
8. 提供还款接口
9. ATM记录操作日志
10. 提供管理接口，包括添加账户、用户额度，冻结账户等。。。
11. 用户认证用装饰器

posted @ 2016-08-12 15:12 金角大王 阅读(...) 评论(...) 编辑 收藏