模块和包

一  模块                                                   

                                  什么是模块                                    

常见的场景 :  一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

 但其实import加载的模块分为四个通用类别:

1 使用Python编写的代码  (.py文件)

2 已被编译为共享库或DLL的C或C++扩展

3 包好一组模块的包

4 使用C编程并连接到Python解释器的内置模块

                           2 为何要使用模块?                      

 如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

    随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,

3 如何使用模块?

3.1 import

示例文件:自定义模块my_moudule.py,文件名my_module.py,模块名my_module

 1 # my_module.py
 2 print("form the my_moudle.py")
 3 
 4 money = 1000
 5 
 6 def read1():
 7     print("my_moudle->read1->monet",money)
 8     
 9 def read2():
10     print("my_moudle->read2 calling read1",)
11     read1()
12 
13 def change():
14     global money
15     money = 0

 

3.1.1                  

模块可以包含可执行文件的语句和函数的定义,这些语句的目的是初始化模块,他可以只在模块名第一次遇见打入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块可以import多次,为了防止你重复导入,Python的优化手段是:第一次导入后就将模块加载到内存了,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句)如下:

 1 # demo.py
 2 import my_module   # 只在第一次导入时才执行my_module.py 内代码,此处的显式效果是只打印一次'from the my_module.py',当然其他的顶级代码也都被执行了,只不过没有显示效果
 3 import my_module
 4 import my_module
 5 import my_module
 6 
 7 
 8 
 9 #  结果
10 form the my_moudle.py

 

我们可以从sys.modules中找到当前已经加载的模块,sys.module是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入.

 

3.12                 

每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会被导入时,与使用者的全局变量冲突

 1 #测试一:money与my_module.money不冲突
 2 #demo.py
 3 import my_module
 4 money=10
 5 print(my_module.money)
 6 
 7 '''
 8 执行结果:
 9 from the my_module.py
10 1000
11 '''
测试一:money与my_module.money不冲突
 1 #测试二:read1与my_module.read1不冲突
 2 #demo.py
 3 import my_module
 4 def read1():
 5     print('========')
 6 my_module.read1()
 7 
 8 '''
 9 执行结果:
10 from the my_module.py
11 my_module->read1->money 1000
12 '''
测试二:read1与my_module.read1不冲突
 1 #测试二:read1与my_module.read1不冲突
 2 #demo.py
 3 import my_module
 4 def read1():
 5     print('========')
 6 my_module.read1()
 7 
 8 '''
 9 执行结果:
10 from the my_module.py
11 my_module->read1->money 1000
12 '''
测试三:my_module.change()操作的全局变量money仍然是my_module中的

 

3.13       

总结:首次导入模块my_modlule是会做三件事:

1.为源文件(my_module模块)创建新的名称空间,在my_module中定义的函数和方法若是使用到了global是访问的就是这个名称空间.

2. 在新创建的命名空间中执行模块中包含的代码,见初始导入import my_module

 

1 提示:导入模块时到底执行了什么?
2 
3 In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table.
4 事实上函数定义也是“被执行”的语句,模块级别函数定义的执行将函数名放入模块全局名称空间表,用globals()可以查看

 

 

3 创建名字my_module来引用该命名空间

1 这个名字和变量名没什么区别,都是‘第一类的’,且使用my_module.名字的方式可以访问my_module.py文件中定义的名字,my_module.名字与test.py中的名字来自两个完全不同的地方。

 

3.1.4    

为模块名起别名, m1 = 1 ; m2 = m1

import my_module as sm
print(sm.money)

3.1.5    

在一行导入多个模块

1 import sys,os,re

 

3.2   from...import...

3.2.1  

对比import my_module,会将源文件的名称空间'my_module'带到当前名称空间中,使用时必须是my_module.名字的方式

而from 语句相当于import,也会创建新的名称空间,但是将my_module中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了、

from my_module import read1,read2

这样在当前位置直接使用read1和read2就好了,执行时,仍然以my_module.py文件全局名称空间

 1 #测试一:导入的函数read1,执行时仍然回到my_module.py中寻找全局变量money
 2 #demo.py
 3 from my_module import read1
 4 money=1000
 5 read1()
 6 '''
 7 执行结果:
 8 from the my_module.py
 9 spam->read1->money 1000
10 '''
11 
12 #测试二:导入的函数read2,执行时需要调用read1(),仍然回到my_module.py中找read1()
13 #demo.py
14 from my_module import read2
15 def read1():
16     print('==========')
17 read2()
18 
19 '''
20 执行结果:
21 from the my_module.py
22 my_module->read2 calling read1
23 my_module->read1->money 1000
24 '''
测试一:导入的函数read1,执行时仍然回到my_module.py中寻找全局变量money

如果当前有重名read1或者read2,那么会有覆盖效果。

 1 #测试三:导入的函数read1,被当前位置定义的read1覆盖掉了
 2 #demo.py
 3 from my_module import read1
 4 def read1():
 5     print('==========')
 6 read1()
 7 '''
 8 执行结果:
 9 from the my_module.py
10 ==========
11 '''
测试三:导入的函数read1,被当前位置定义的read1覆盖掉了

需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系,如下:

from my_module import money,read1
money=100 #将当前位置的名字money绑定到了100
print(money) #打印当前的名字
read1() #读取my_module.py中的名字money,仍然为1000

'''
from the my_module.py
100
my_module->read1->money 1000
'''
View Code

 

3.2.2     

也支持as

1 from my_module import read1 as read

 

3.2.3    

也支持导入多行

1 from my_module import (read1,
2                   read2,
3                   money)

 

3.2.4    

from my_module import * 把my_module中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。

 1 from my_module import * #将模块my_module中所有的名字都导入到当前名称空间
 2 print(money)
 3 print(read1)
 4 print(read2)
 5 print(change)
 6 
 7 '''
 8 执行结果:
 9 from the my_module.py
10 1000
11 <function read1 at 0x1012e8158>
12 <function read2 at 0x1012e81e0>
13 <function change at 0x1012e8268>
14 '''
View Code

 

在my_module.py中新增一行

__all__=['money','read1'] #这样在另外一个文件中用from my_module import *就这能导入列表中规定的两个名字

 

*如果my_module.py中的名字前加_,即_money,则from my_module import *,则_money不能被导入

3.25       模块的循环引用问题 

循环引用会报错

例如:

# a.py
import b   #  引用b模块

def funca():
    print('funca')

b.funcb()




# b.py
import a    # 引用a模块

def funcb():
    print('in funcb')

a.funca()



#结果  
会报错

<module>
    a.funca()
AttributeError: module 'a' has no attribute 'funca'

 

3.2.6   模块的加载与修改

每个模块只被导入一次,放入字典sys.modules中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,

一般会想到直接从sys.modules中删除一个模块不就可以卸载了,但是你删了sys.modules中的模块对象仍然可能被其他程序的组件所引用,因而不会被清除。

特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。

如果只是你想交互测试的一个模块,使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename),这只能用于测试环境。

def func1():
    print('func1'
aa.py
1 import time,importlib
2 import aa
3  
4 time.sleep(20)
5 # importlib.reload(aa)
6 aa.func1()
测试代码

在20秒的等待时间里,修改aa.py中func1的内容,等待test.py的结果。

打开importlib注释,重新测试

 

3.3   把模块当脚本执行

我们可以通过模块的全局变量__name__来查看模块名:
当做脚本运行:
__name__ 等于'__main__'

当做模块导入:
__name__= 模块名

作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
if __name__ == '__main__':

 1 def fib(n):   
 2     a, b = 0, 1
 3     while b < n:
 4         print(b, end=' ')
 5         a, b = b, a+b
 6     print()
 7 
 8 if __name__ == "__main__":  # 当做脚本执行的时候,会执行if里面的代码块
 9     print(__name__)
10     num = input('num :')
11     fib(int(num)
View Code

 

3.4  模块搜索路径 

python解释器在启动时会自动加载一些模块,可以使用sys.modules查看

在第一次导入某个模块时(比如my_module),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用

如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找my_module.py文件。

所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块

特别注意的是:我们自定义的模块名不应该与系统内置模块重名。

在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载

1 >>> import sys
2 >>> sys.path.append('/a/b/c/d')
3 >>> sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索

 

注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。

 1 #首先制作归档文件:zip module.zip foo.py bar.py
 2 
 3 import sys
 4 sys.path.append('module.zip')
 5 import foo,bar
 6 
 7 #也可以使用zip中目录结构的具体位置
 8 sys.path.append('module.zip/lib/python')
 9 
10 #windows下的路径不加r开头,会语法错误
11 sys.path.insert(0,r'C:\Users\Administrator\PycharmProjects\a')
View Code

至于.egg文件是由setuptools创建的包,这是按照第三方python库和扩展时使用的一种常见格式,.egg文件实际上只是添加了额外元数据(如版本号,依赖项等)的.zip文件。

需要强调的一点是:只能从.zip文件中导入.py,.pyc等文件。使用C编写的共享库和扩展块无法直接从.zip文件中加载(此时setuptools等打包系统有时能提供一种规避方法),且从.zip中加载文件不会创建.pyc或者.pyo文件,因此一定要事先创建他们,来避免加载模块是性能下降。

 

补充:dir()函数

内建函数dir是用来查找模块中定义的名字,返回一个有序字符串列表

import my_module
dir(my_module)

 

如果没有参数,dir()列举出当前定义的名字

dir()不会列举出内建函数或者变量的名字,它们都被定义到了标准模块builtin中,可以列举出它们,

import builtins
dir(builtins)

 

二  包          

包是一种通过使用‘.模块名’来组织python模块名称空间的方式

1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)

3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件

强调:

  1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错

  2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

 

包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间

 1 import os
 2 os.makedirs('glance/api')
 3 os.makedirs('glance/cmd')
 4 os.makedirs('glance/db')
 5 l = []
 6 l.append(open('glance/__init__.py','w'))
 7 l.append(open('glance/api/__init__.py','w'))
 8 l.append(open('glance/api/policy.py','w'))
 9 l.append(open('glance/api/versions.py','w'))
10 l.append(open('glance/cmd/__init__.py','w'))
11 l.append(open('glance/cmd/manage.py','w'))
12 l.append(open('glance/db/models.py','w'))
13 map(lambda f:f.close() ,l)
创建目录文件
 1 glance/                   #Top-level package
 2 
 3 ├── __init__.py      #Initialize the glance package
 4 
 5 ├── api                  #Subpackage for api
 6 
 7 │   ├── __init__.py
 8 
 9 │   ├── policy.py
10 
11 │   └── versions.py
12 
13 ├── cmd                #Subpackage for cmd
14 
15 │   ├── __init__.py
16 
17 │   └── manage.py
18 
19 └── db                  #Subpackage for db
20 
21     ├── __init__.py
22 
23     └── models.py
目录结构
 1 #文件内容
 2 
 3 #policy.py
 4 def get():
 5     print('from policy.py')
 6 
 7 #versions.py
 8 def create_resource(conf):
 9     print('from version.py: ',conf)
10 
11 #manage.py
12 def main():
13     print('from manage.py')
14 
15 #models.py
16 def register_models(engine):
17     print('from models.py: ',engine)
文件内容

 

 

2.1 注意事项   

1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。

2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。

3.对比import item 和from item import name的应用场景:
如果我们想直接使用name那必须使用后者。

 

2.2   import

我们在与包glance同级别的文件中测试

1 import glance.db.models
2 glance.db.models.register_models('mysql')

 

2.3 from ... import ...

需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法

我们在与包glance同级别的文件中测试 

1 from glance.db import models
2 models.register_models('mysql')
3  
4 from glance.db.models import register_models
5 register_models('mysql')

 

2.4 __init__.py文件  

不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件(我们可以在每个包的文件内都打印一行内容来验证一下),这个文件可以为空,但是也可以存放一些初始化包的代码。

 

2.5  form glance.api import *  

从一个包导入所有*  ,  要想从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:

#在__init__.py中定义
x=10

def func():
    print('from api.__init.py')

__all__=['x','func','policy']

此时我们在于glance同级的文件中执行from glance.api import *就导入__all__中的内容(versions仍然不能导入)

 1 glance/                   
 2 
 3 ├── __init__.py      
 4 
 5 ├── api                  
 6 
 7 │   ├── __init__.py   __all__ = ['policy','versions'] 
 8 
 9 │   ├── policy.py
10 
11 │   └── versions.py
12 
13 ├── cmd               __all__ = ['manage']    
14 
15 │   ├── __init__.py
16 
17 │   └── manage.py    
18 
19 └── db                __all__ = ['models']              
20 
21     ├── __init__.py
22 
23     └── models.py
24 
25 
26 
27 from glance.api import *
28 policy.get()
from glance.api import *

 

2.6  绝对导入和相对导入  

绝对导入:以glance作为起始

相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

例如:我们在glance/api/version.py中想要导入glance/cmd/manage.py

在glance/api/version.py

#绝对导入
from glance.cmd import manage
manage.main()

#相对导入
from ..cmd import manage
manage.main()

测试结果:注意一定要在于glance同级的文件中测试

 from glance.api import versions

 

 

特别需要注意的是:可以用import导入内置或者第三方模块(已经在sys.path中),但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中),应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式。

 

比如我们想在glance/api/versions.py中导入glance/api/policy.py,有时候一抽这俩模块是在同一个目录下,它直接这么做

#在version.py中

import policy
policy.get()

 

没错,我们单独运行version.py是一点问题没有的,运行version.py的路径搜索就是从当前路径开始的,于是在导入policy时能在当前目录下找到

但是你子包中的模块version.py极有可能是被一个glance包同一级别的其他文件导入,比如我们在于glance同级下的一个test.py文件中导入version.py,如下

 

from glance.api import versions

'''
执行结果:
ImportError: No module named 'policy'
'''

'''
分析:
此时我们导入versions在versions.py中执行
import policy需要找从sys.path也就是从当前目录找policy.py,
这必然是找不到的
'''

 

 1 glance/                   
 2 
 3 ├── __init__.py      from glance import api
 4                              from glance import cmd
 5                              from glance import db
 6 
 7 ├── api                  
 8 
 9 │   ├── __init__.py  from glance.api import policy
10                               from glance.api import versions
11 
12 │   ├── policy.py
13 
14 │   └── versions.py
15 
16 ├── cmd                 from glance.cmd import manage
17 
18 │   ├── __init__.py
19 
20 │   └── manage.py
21 
22 └── db                   from glance.db import models
23 
24     ├── __init__.py
25 
26     └── models.py
绝对导入
 1 glance/                   
 2 
 3 ├── __init__.py      from . import api  #.表示当前目录
 4                      from . import cmd
 5                      from . import db
 6 
 7 ├── api                  
 8 
 9 │   ├── __init__.py  from . import policy
10                      from . import versions
11 
12 │   ├── policy.py
13 
14 │   └── versions.py
15 
16 ├── cmd              from . import manage
17 
18 │   ├── __init__.py
19 
20 │   └── manage.py    from ..api import policy   
21                      #..表示上一级目录,想再manage中使用policy中的方法就需要回到上一级glance目录往下找api包,从api导入policy
22 
23 └── db               from . import models
24 
25     ├── __init__.py
26 
27     └── models.py
相对导入

 

2.7 单独导入包    

单独导入包名称时不会导入包中所有包含的所有子模块,如

#在与glance同级的test.py中
import glance
glance.cmd.manage.main()

'''
执行结果:
AttributeError: module 'glance' has no attribute 'cmd'

'''

 

解决办法:

1 #glance/__init__.py
2 from . import cmd
3 
4 #glance/cmd/__init__.py
5 from . import manage

 

执行:

#在于glance同级的test.py中
import glance
glance.cmd.manage.main()

 

千万别问  :    __all__不能解决吗,__all__是用于控制from...import * 

import glance之后直接调用模块中的方法

 1 glance/                   
 2 
 3 ├── __init__.py     from .api import *
 4                     from .cmd import *
 5                     from .db import *    
 6 ├── api                  
 7 
 8 │   ├── __init__.py   __all__ = ['policy','versions'] 
 9 
10 │   ├── policy.py
11 
12 │   └── versions.py
13 
14 ├── cmd               __all__ = ['manage']    
15 
16 │   ├── __init__.py
17 
18 │   └── manage.py    
19 
20 └── db                __all__ = ['models']              
21 
22     ├── __init__.py
23 
24     └── models.py
25 
26 
27 import glance
28 policy.get(
import glance

 

 

软件开发规范           

 

  1 #=============>bin目录:存放执行脚本
  2 #start.py
  3 import sys,os
  4 
  5 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  6 sys.path.append(BASE_DIR)
  7 
  8 from core import core
  9 from conf import my_log_settings
 10 
 11 if __name__ == '__main__':
 12     my_log_settings.load_my_logging_cfg()
 13     core.run()
 14 
 15 #=============>conf目录:存放配置文件
 16 #config.ini
 17 [DEFAULT]
 18 user_timeout = 1000
 19 
 20 [egon]
 21 password = 123
 22 money = 10000000
 23 
 24 [alex]
 25 password = alex3714
 26 money=10000000000
 27 
 28 [yuanhao]
 29 password = ysb123
 30 money=10
 31 
 32 #settings.py
 33 import os
 34 config_path=r'%s\%s' %(os.path.dirname(os.path.abspath(__file__)),'config.ini')
 35 user_timeout=10
 36 user_db_path=r'%s\%s' %(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),\
 37                      'db')
 38 
 39 
 40 #my_log_settings.py
 41 """
 42 logging配置
 43 """
 44 
 45 import os
 46 import logging.config
 47 
 48 # 定义三种日志输出格式 开始
 49 
 50 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
 51                   '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
 52 
 53 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
 54 
 55 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
 56 
 57 # 定义日志输出格式 结束
 58 
 59 logfile_dir = r'%s\log' %os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # log文件的目录
 60 
 61 logfile_name = 'all2.log'  # log文件名
 62 
 63 # 如果不存在定义的日志目录就创建一个
 64 if not os.path.isdir(logfile_dir):
 65     os.mkdir(logfile_dir)
 66 
 67 # log文件的全路径
 68 logfile_path = os.path.join(logfile_dir, logfile_name)
 69 
 70 # log配置字典
 71 LOGGING_DIC = {
 72     'version': 1,
 73     'disable_existing_loggers': False,
 74     'formatters': {
 75         'standard': {
 76             'format': standard_format
 77         },
 78         'simple': {
 79             'format': simple_format
 80         },
 81     },
 82     'filters': {},
 83     'handlers': {
 84         #打印到终端的日志
 85         'console': {
 86             'level': 'DEBUG',
 87             'class': 'logging.StreamHandler',  # 打印到屏幕
 88             'formatter': 'simple'
 89         },
 90         #打印到文件的日志,收集info及以上的日志
 91         'default': {
 92             'level': 'DEBUG',
 93             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
 94             'formatter': 'standard',
 95             'filename': logfile_path,  # 日志文件
 96             'maxBytes': 1024*1024*5,  # 日志大小 5M
 97             'backupCount': 5,
 98             'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
 99         },
100     },
101     'loggers': {
102         #logging.getLogger(__name__)拿到的logger配置
103         '': {
104             'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
105             'level': 'DEBUG',
106             'propagate': True,  # 向上(更高level的logger)传递
107         },
108     },
109 }
110 
111 
112 def load_my_logging_cfg():
113     logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
114     logger = logging.getLogger(__name__)  # 生成一个log实例
115     logger.info('It works!')  # 记录该文件的运行状态
116 
117 if __name__ == '__main__':
118     load_my_logging_cfg()
119 
120 #=============>core目录:存放核心逻辑
121 #core.py
122 import logging
123 import time
124 from conf import settings
125 from lib import read_ini
126 
127 config=read_ini.read(settings.config_path)
128 logger=logging.getLogger(__name__)
129 
130 current_user={'user':None,'login_time':None,'timeout':int(settings.user_timeout)}
131 def auth(func):
132     def wrapper(*args,**kwargs):
133         if current_user['user']:
134             interval=time.time()-current_user['login_time']
135             if interval < current_user['timeout']:
136                 return func(*args,**kwargs)
137         name = input('name>>: ')
138         password = input('password>>: ')
139         if config.has_section(name):
140             if password == config.get(name,'password'):
141                 logger.info('登录成功')
142                 current_user['user']=name
143                 current_user['login_time']=time.time()
144                 return func(*args,**kwargs)
145         else:
146             logger.error('用户名不存在')
147 
148     return wrapper
149 
150 @auth
151 def buy():
152     print('buy...')
153 
154 @auth
155 def run():
156 
157     print('''
158 购物
159 查看余额
160 转账
161     ''')
162     while True:
163         choice = input('>>: ').strip()
164         if not choice:continue
165         if choice == '1':
166             buy()
167 
168 
169 
170 if __name__ == '__main__':
171     run()
172 
173 #=============>db目录:存放数据库文件
174 #alex_json
175 #egon_json
176 
177 #=============>lib目录:存放自定义的模块与包
178 #read_ini.py
179 import configparser
180 def read(config_file):
181     config=configparser.ConfigParser()
182     config.read(config_file)
183     return config
184 
185 #=============>log目录:存放日志
186 #all2.log
187 [2017-07-29 00:31:40,272][MainThread:11692][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
188 [2017-07-29 00:31:41,789][MainThread:11692][task_id:core.core][core.py:25][ERROR][用户名不存在]
189 [2017-07-29 00:31:46,394][MainThread:12348][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
190 [2017-07-29 00:31:47,629][MainThread:12348][task_id:core.core][core.py:25][ERROR][用户名不存在]
191 [2017-07-29 00:31:57,912][MainThread:10528][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
192 [2017-07-29 00:32:03,340][MainThread:12744][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
193 [2017-07-29 00:32:05,065][MainThread:12916][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
194 [2017-07-29 00:32:08,181][MainThread:12916][task_id:core.core][core.py:25][ERROR][用户名不存在]
195 [2017-07-29 00:32:13,638][MainThread:7220][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
196 [2017-07-29 00:32:23,005][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
197 [2017-07-29 00:32:40,941][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
198 [2017-07-29 00:32:47,222][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
199 [2017-07-29 00:32:51,949][MainThread:7220][task_id:core.core][core.py:25][ERROR][用户名不存在]
200 [2017-07-29 00:33:00,213][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
201 [2017-07-29 00:33:50,118][MainThread:8500][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
202 [2017-07-29 00:33:55,845][MainThread:8500][task_id:core.core][core.py:20][INFO][登录成功]
203 [2017-07-29 00:34:06,837][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
204 [2017-07-29 00:34:09,405][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
205 [2017-07-29 00:34:10,645][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
软件开发规范代码介绍

 

posted @ 2018-08-23 17:29  heshun  阅读(243)  评论(0编辑  收藏  举报