模块和包
一 模块
什么是模块
常见的场景 : 一个模块就是一个包含了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 '''
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 '''
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 '''
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或者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 '''
需要特别强调的一点是: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 '''
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 '''
在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'
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)
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')
至于.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()
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(
软件开发规范
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][用户名不存在]