python-模块,异常,环境管理器

模块 Modulepython

  什么是模块:编程

    一、模块是一个包含有一系列数据,函数,类等组成的程序组json

    二、模块是一个文件,模块文件名一般以.py结尾dom

  做用:ide

    一、让一些相关数据,函数,类等有逻辑的组织在一块儿,使逻辑结构更加清晰模块化

    二、模块中的数据,函数和类等可提供给其它模块或程序使用函数

  模块的分类:(同一个模块在不一样的操做系统下可能数不一样类型的模块)ui

    一、内置模块(builtins),通常是用C语言来写的,在解析器的内部能够直接使用。模块说明中有builtins关键字this

    二、标准库模块,安装python时已经安装且可直接使用。spa

    三、第三方模块(一般为开源),须要本身安装

    四、用户本身完成的模块(能够做为其余人的第三方模块)

模块的导入语句

  import语句

    语法:import 模块名1 [as 模块新名1][,模块名2[ as 模块新名2]],....

    做用:将某模块总体导入到当前模块

    用法:模块.属性名

  dir(obj)函数返回模块全部属性的字符串列表

  help(obj)能够查看模块相关的文档字符串

  from  import语句

    语法: from 模块名 import 模块属性名1[as 属性新名1] [,模块属性名2[as 属性新名2],....]

    做用:将模块内的一个或多个属性导入到当前模块的做用域 

    说明:属性是模块内的全部全局变量

  from import * 语句 (通常不用)

    语法:from 模块名 import *

    做用:将某模块的全部属性都导入到当前模块

dir函数:

  dir([对象])返回一个字符串列表

  做用:一、若是没有参数调用,则返回当前做用域内的全部变量的列表

     二、若是给定一个对象做为参数,则返回这个对象的全部变量的列表

      1)对于一个模块,返回这个模块的所有属性

      2)对于一个类对象,返回这个类对象的全部变量,亲递归基类对象的全部变量

      3)对于其它对象,返回全部的变量,类变量,基类变量

数学模块 math

  变量:

    math.e  天然对数的底e

    math.pi  圆周率pi

  函数:

    math.ceil(x)          对x向上取整,好比x = 1.2 ,返回2

    math.floor(x)           对x向下取整,好比x = 1.8 ,返回1

    math.sqrt(x)          返回x的平方根

    math.factorial(x)        求x的阶乘

    math.log(x,[base])        返回以base为底的x的对数,若是不给base,则以天然对数e为底

    math.log10(x)          求以10为底x的对数

    math.pow(x,y)             返回x**y

    math.fabs(x)          返回浮点数x的绝对值,好比x = -1,返回1.0

  角度degrees和弧度radians互换

    math.degrees(x)          将弧度x转换为角度

    math.radians(x)         将角度x转换为弧度

  三角函数,下面的x都是以弧度为单位的

    math.sin(x)           返回x的正弦

    math.cos(x)             返回x的余弦

    math.tan(x)           返回x的正切

    math.asin(x)            返回x的反正弦(返回值为弧度)

    math.acos(x)           返回x的反余弦(返回值为弧度)

    math.atan(x)            返回x的反正切(返回值为弧度)

时间模块 time

此模块提供了时间相关的函数,且一直可用

  时间简介

    一、公元纪年是从公元0000年1月1日0时开始的

    二、计算机元年是从1970年1月1日0时开始的,此时间为0,以后每过一秒时间+1

    三、UTC时间(Coordinated Universal Time )是从Greenwich时间开始计算的,UTC时间不会因时区问题而产生错误

    四、DST阳光节约时间(Daylight Saving Time ),又称夏玲时,是一个通过日照时间修正后的时间(中国已经不用了)

  时间元组

    时间元组是一个9个整型元素组成的,这九个元素自前至后一次为

      一、四位的年(如:1992)

      二、月(1-12)

      三、日(1-31)

      四、时(0-23)

      五、分(0-59)

      六、秒(0-59)

      七、星期几(0-6,周一是0)

      八、元旦开始日(1-366)

      九、夏令时修时间(-1,0 or 1),对中国来讲是0

    注:若是年份小于100,则会自动转换为加上1900后的值

  变量

    time.altzone    夏令时时间与UTC时间差(秒为单位),-32400秒

    time.daylight      夏令时校订时间,在中国为0

    time.timezone   本地区时间与UTC时间差(秒为单位),-28800秒

    time.tzname    时区名字的元组,第一个名字为未经夏令时修正的时区,第二个名字为经夏令时修正后的时间("CST","CST")

    注:CST为中国标准时间(China Standard Time UTC+8:00)

  函数:

    time.time()     返回从计算机元年至当前时间的秒数的浮点数(UTC时间为准)

    time.sleep(secs)    让程序按给定秒数的浮点数睡眠一段时间

    time.gmtime([secs]) 用给定秒数转换为用UTC表达的时间元组(默认返回当前时间元组)

    time.asctime([tuple]) 将时间元组转为日期时间字符串,默认为当前时间

    time.ctime([secs])  将时间戳转发为日期时间字符串,默认是当前时间

    time.mktime(tuple)    将本地日期时间元组转为新纪元秒数时间(UTC为准)

    time.localtime([secs])   将UTC秒数时间转为日期元组(以本地时间为准),默认为当前时间

    注:time.mktime(time.localtime()) - time.mktime(time.gmtime()) = 28800.0 说明当时时间比UTC时间早8个小时

    time.clock()     返回处理器时间,3.0版本开始已经废弃,改为time.process_time()

    time.strftime(formt[,tuple]) 返回可读字符串时间,格式有参数format决定。

    time.strptime()

    time.tzset()

  python中时间日期格式化符号

    %y      表示两位数的年份(00-99)

    %Y      表示四位数的年份(0000-9999)

    %m      月份(01-12)

    %d      月内中的一天(0-31)

    %H      24小时制小时数(0-23)

    %I       12小时制小时数(01-12)

    %M      分钟数(00-59)

    %S      秒数(00-59)

    %a      本地简化星期名称

    %A      本地完整星期名称

    %b      本地简化月份名称

    %B      本地完整月份名称

    %c      本地相应的的日期表示和时间表示

    %j       年内的一天(001-366)

    %p      本地A.M.或P.M.的等价符

    %U      一年中的星期数(00-53)星期日为星期的开始

    %w      星期(0-6),星期天为星期的开始

    %W      一年中的星期数(00-53)星期一为星期的开始

    %x      本地相应的日期表示

    %X      本地相应的时间表示

    %Z      当前时区的名称

    %%      %号自己

import time
print(time.localtime())#time.struct_time(tm_year=2018, tm_mon=7, tm_mday=19, tm_hour=0, tm_min=44, tm_sec=5, tm_wday=3, tm_yday=200, tm_isdst=0)
print(time.strftime("%Y-%m-%d  %H:%M:%S",time.localtime()))#2018-07-19  00:44:05
print(time.strftime("%y-%m-%d  %I:%M:%S",time.localtime()))#18-07-19  12:44:05
print(time.strftime("%a-%A-%b-%B-%c-%j-%p-%U-%w-%W-%x-%X-%Z-%%",time.localtime()))
#              Thu-Thursday-Jul-July-Thu Jul 19 00:44:05 2018-200-AM-28-4-29-07/19/18-00:44:05-?D1¨²¡À¨º¡Á?¨º¡À??-%
#               a    A       b   B             c               j   p  U w W     x        X         Z                 %

 

系统模块sys

此模块所有是运行时系统相关的信息

  做用:用于获取和设置与系统相关的信息

  变量

    sys.path      返回模块的搜索路径,path[0]是当前脚本程序的路径,初始化时使用pythonPath环境变量的值

    sys.modules    返回已加载模块的字典,字典的键为模块名,值为已加载的模块

    sys.version      返回python版本信息的字符串:'3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)]'

    sys.version_info   返回python版本信息的命名元组:sys.version_info(major=3, minor=5, micro=4, releaselevel='final', serial=0)

    sys.platform    操做系统平台的名称信息(Win32)

    sys.argv        命令行参数argv[0]表明当前脚本程序的路径名,绑定用户启动程序时命令参数的列表

    sys.copyright    得到python版权相关信息

    sys.builtin_module_names  得到python内建模块的名称(字符串元组)

    标准输入输出时会用到

    sys.stdin      标准输入文件对象,多用于input()

    sys.stdout       标准输出文件对象,多用于print()

    sys.stderr        标准错误输出文件对象,用于输出错误信息

  函数:

    sys.exit([arg])    退出程序,正常退出时sys.exit(0)

    sys.getrecursionlimit()  获得递归嵌套层次限制(栈的深度)

    sys.setrecursionlimit(n)  获得和修改递归嵌套层次限制(栈的深度),你表明递归的次数,脚本中止,则这个限制还原

自定义模块

  自定义模块模块名必须符合“标识符”的命名规则(同变量名),模块有各自独立的做用域

  模块化编程的优势:

    一、有利于多人合做开发

    二、使代码更易于维护

    三、提升代码的复用率

    四、有利于解决变量名冲突问题

import 语句  搜索模块的路径顺序

  一、搜索程序运行时的路径(当前路径)

  二、sys.path提供的路径

  三、搜索内置模块

  说明:sys.path是一个存储模块搜索路径的列表

      一、能够把自定义的模块放在相应的路径下能够导入

      二、能够把本身模块的路径添加在sys.path列表中

模块的加载过程:

  一、在模块导入时,模块的全部语句会执行

  二、若是一个模块已经导入,则再次导入时不会从新执行模块内的语句

模块的从新加载:

  当已经被导入的模块内容被修改后,能够经过从新执行当前的程序从新加载,或者经过import imp;imp.reload(模块名)的方法从新加载

模块被导入和执行的过程

  一、先搜索相关的路径找到模块(.py)

  二、判断是否有此模块对应的.pyc文件,若是存在pyc文件且比.py文件新,则直接加载.pyc文件

  三、不然用.py文件生成.pyc文件后再进行加载

pyc 模块的编译文件:

  mymod1.py----编译(compile)------→mymod1.pyc------解释执行-----→python3

模块的属性

  属性的实质是变量(是模块内的全局变量)

模块内预置的属性

  __doc__属性

    做用:用来绑定模块的文档字符串

  模块内第一个没有赋值给任何变量的字符串为模块的文档字符串,(若是没有赋值的字符串出如今第二个语句,则文档字符串为空)

  __file__属性

    用来绑定模块对应的文档路径名

      一、对于内建模块,不绑定路径(没有__file__属性)

      二、对于其它模块,绑定路径名的字符串(相对路径:模块名.py)

  __name__属性

    此属性用来记录模块的自身名字

    做用:一、记录模块名

       二、用来判断是否为主模块(最早运行的模块)

    说明:一、当此模块为主模块时,__name__绑定"__main__"

       二、当此模块不是主模块时,此属性绑定模块名

模块的__all__列表(不属于模块的属性)

  模块中的__all__列表是一个用来存放可导出属性的字符串列表

  做用:当用from import * 语句导入时,只导入__all__列表内的属性,若是没有次列表则模块的全部属性都被导入

     不会影响import 模块名 和  from 模块名 import 属性名 两个语句的导入

模块的隐藏属性:

  模块中以"_"下划线(不只仅是单下划线,多个下划线)开头的属性,在from import *语句导入时,将不被导入,一般称这些属性为隐藏属性。

  若是该属性被放入__all__列表中,将会被导入

随机模块 random

做用:用于模拟或生成随机输出的模块

  函数(import random as R)

  R.random()            返回一个[0,1)之间的随机实数

  R.randint(a,b)           返回一个 [a~b]之间的随机整数,包括a,b

  R.uniform(a,b)            返回[a,b)区间内的随机实数

  R.randrange([start,] stop[,step])   返回range(start,stop,step)中的随机数

  R.choice(seq)           从序列中返回随机数

  R.shuffle(seq, [,random])      随机指定序列的顺序(乱序序列),函数的第二个参数表明必须传入random模块中无参的函数目前只有random函数,可使用         R.random代替,目前版本没有什么用

  R.sample(seq,n)            从序列中选择n个随机且不重复的元素

import random
L = [i for i in range(10)]
L5 = random.sample(L,5)
print(L)
print(L5)

json&pick模块

序列化:

  咱们把对象(变量)从内存中变成可存储的或传输的过程称之为序列化,反过来,把变量内容从序列化后的对象从新读到内存中称为反序列化

  说明:json不能讲高级的对象序列化,好比:函数、类,若是要序列化函数 或者 类时须要使用pickle模块

  json中的函数:

    一、dumps():序列化

    二、loades():反序列化

import json
dic = {'name':"xdl",'age':25}
#将字典对象序列,使之变为可存储的对象
dic = json.dumps(dic)
f = open('json_test','w')
f.write(dic)
import json
f = open('json_test','r')
dic = f.read()
#将读出的数据反序列化,并读入到内存中
dic = json.loads(dic)
print(dic['name'])

  pickle中的函数

    一、dumps():序列化对象

    二、loads():反序列化对象

import pickle
def foo():
    print('ok')
#将字典对象序列,使之变为可存储的对象,是字节串,须要使用wb写入
foo = pickle.dumps(foo)
f = open('json_test','wb')
f.write(foo)
f.close()
import pickle
def foo():
    print('ok')
f = open('json_test','rb')
data = f.read()
#将读出的数据反序列化,并读入到内存中
#反序列化以前要建立一个与读取的函数名相同的函数
#不然会报错:AttributeError: Can't get attribute 'foo' on <module '__main__' from '
# /home/tarena/PycharmProjects/xdl/module/pickle_load.py'>
data = pickle.loads(data)
data()

logging模块(日志模块)

使用步骤:

  一、获取logger实例对象,若是参数为空则返回root logger,

    logger = logging.getLogger()

  二、指定logger的格式

    formatter = logging.Formatter('自定义格式')

  三、建立具体的日志handler,并将日志格式添加处处理器上,包括文件日志和终端日志

    1)文件日志:

      file_handler = logging.FileHandler('文件名称.log')

      file_handler.setFormatter(formatter)

    2)终端日志(在终端上显示日志信息)

      console_handler = logging.StreamHandler(sys.stdout)

      console_handler.setFormatter(formatter)

  四、设置日志级别

    logger.setLevel(日志级别)

  五、把日志的handler对象添加到日志对象logger中

    logger.addHandler(file_handler)

    logger.addHandler(console_handler)

  六、写日志   

    logger.debug('this is debug info')
    logger.info('this is information')
    logger.warn('this is warning message')
    logger.error('this is error message')
    logger.fatal('this is fatal message, it is same as logger.critical')
    logger.critical('this is critical message')

  七、移除日志处理器

    logger.removeHandler(file_handler)
    logger.removeHandler(console_handler)

import logging
import sys
#一、获取logger的实例,<Logger testlog (INFO)>,(INFO)是本身设置的日志级别,若是不给参数,<RootLogger root (INFO)>
logger = logging.getLogger('testlog')
#二、指定logger的格式
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
#三、建立具体的日志handler,文件日志,终端日志
#3.一、文件日志
file_handler = logging.FileHandler('testLog.log')
file_handler.setFormatter(formatter)
#3.二、终端日志
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(formatter)
#四、设置日志的级别,高于等于这个默认级别才会被显示
logger.setLevel(logging.INFO)
#五、把日志的handler添加到logger实例中
logger.addHandler(file_handler)
logger.addHandler(console_handler)
#六、写日志
logger.error("Test Error log")
logger.info("Test info log")
logger.debug("Test debug log")
#七、清空日志
logger.removeHandler(file_handler)
logger.removeHandler(console_handler)

将日志封装成一个模块

class LogerHelper:
    
    def __init__(self,name='LogerHelper',setLevel=logging.DEBUG):
        self.logger = logging.getLogger(name)
        self.formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
        self.file_handler = logging.FileHandler(name+'.log')
        self.file_handler.setFormatter(self.formatter)
        self.console_handler = logging.StreamHandler(sys.stdout)
        self.console_handler.setFormatter(self.formatter)
        self.logger.setLevel(setLevel)
        self.logger.addHandler(self.file_handler)
        self.logger.addHandler(self.console_handler)
        
    def writeLog(self,info,level='debug'):
        if level == 'critial':
            self.logger.critical(info)
        elif level == 'error':
            self.logger.error(info)
        elif level == 'warn':
            self.logger.warn(info)
        elif level == 'info':
            self.logger.info(info)
        elif level == 'debug':
            self.logger.debug(info)

    def removeLog(self):
        self.logger.removeHandler(self.file_handler)
        self.logger.removeHandler(self.console_handler)
        
if __name__ == '__main__':
    logger = LogerHelper()
    logger.writeLog("hello world",'critial')
    logger.writeLog("hello world",'error')
    logger.writeLog("hello world",'warn')
    logger.writeLog("hello world",'info')
    logger.writeLog("hello world",'debug')
    logger.removeLog()

 

包(模块包)package

  包是将模块以文件夹的组织形式进行分组管理的方法(包比其它普通文件夹多一个__init__.py)

  做用:将一系列模块进行分类管理,有利于防止命名冲突,能够在须要时加载一个或一部分模块而不是所有模块

  __init__.py文件

    常规包内必须存在的文件

    __init__.py会在包加载时被自动调用

    做用:一、编写此包的内容

       二、在内部填写文档字符串

       三、在__init__.py内能够加载此包所依赖的一些其它模块

  包的导入

    用三条import语句能够导入包(同模块的导入规则)

    import 包名 [as 包别名]

    import 包名.模块名 [as 模块新名]

    import 包名.子包名.模块名

 

    from 包名 import 模块名  [as 模块新名]

    from 包名.子包名 import 模块名 [as 模块新名]

    from 包名.子包名.模块名 import 属性名 [as  属性新名]

 

    from 包名 import *

    from 包名.模块名 import *

  包的__init__.py内的__all__列表

    做用:用来记录此包中有哪些子包或模块在用from 包 import * 语句导入时是否被导入

    说明:__all__列表只对from import * 语句起做用,若是没有此列表则,都不会被导入

包的相对导入

  包的相对导入是指包内模块的相互导入

  语法:一、from 相对路径包或模块 import 属性或模块名

     二、from 相对路径或模块 import *

  相对路径:

     一、.表明当前目录 如:a/b/c.py   其中.c.py表明b路径

     二、..表明上一级目录

     三、...表明上二级目录

     四、....依次类推

     注:相对导入时不能超出包的外部,若是超出包的外部会报错ValueError: attempted relative import beyond top-level package

包的加载路径:

  和模块的加载路径相同

     一、当前文件夹

     二、sys.path给出的路径

异常 exception

什么是错误:

  错误是指因为逻辑或语法等致使一个程序没法正常执行的问题

  特色:有些错误是没法预知的

什么是异常:

  异常是程序出错时标识的一种状态,

  当异常发生时,程序不会再向下执行,而转去调用此函数的地方待处理错误并恢复为正常状态

  做用:

    一、通知上层调用者有错误产生须要处理

    二、用做信号通知

try 语句的两种语法

  try - except  语句

    语法:try:

          可能触发异常的语句

       except 错误类型1 [as 变量1]:

          异常处理语句1

       except 错误类型2 [as 变量2]:

          异常处理语句2

       except(错误类型3,错误类型4,...)[as 变量3]:#前面必须是异常类型元组

          异常处理语句3

       ...

       except:                  #捕获全部错误类型

          异常处理语句other

       else:

          未发生异常时执行的语句,(try语句嵌套的try语句出现异常并被处理,也要执行,若是没有被处理将交给外部try语句进行处理)

       finally:

          最终执行语句(无论有没有发生异常都会执行该语句,发生异常没有被处理一样会执行该语句)

    做用:尝试捕获异常,将程序转为正常状态并继续执行

    说明:一、as 子句用于绑定错误对象的变量,能够省略不写

       二、except子句能够有一个或多个,但至少要有一个

       三、else子句最多只能有一个,也能够省略不写

       四、finally子句最多只能有一个,也能够省略不写

  try-finally语句

    语法:try:

        可能触发异常的语句

       finally:

        最终语句

    说明:一、finally子句不能够省略

       二、必定不存在except子句

    做用:一般try-finally语句来作触发异常时必需要处理的事情,不管异常是否发生,finally子句都会执行

    注:try-finally语句不会改变程序的(正常/异常)状态

raise语句

  做用:触发一个错误,让程序进入异常状态

  语法:一、raise 异常类型 :raise ZeroDivisionError

     二、raise 异常对象:rasie ZeroDivisionError("被零除了...")

assert 语句(断言语句)

  语法:assert 真值表达式,错误数据(一般是字符串)

  做用:当真值表达式为False时,用错误数据建立一个AssertionError类型的错误,并进入异常状态

  相似于:if   真值表达式 == False:

        raise AssertionError(错误数据)

                  

              

小结:

  接收错误消息:try- except

  作必需要处理的事情的语句:try-finally

  发错误消息的语句:一、raise 语句

           二、assert 语句

为何要用异常处理处理机制:

  在程序调用层数较深时,向主调用函数传递错误信息须要用return语句层层传递比较麻烦,因此用异常处理机制

异常(高级)
    回顾异常相关的语句:
        try-exept         用来捕获异常通知
        try-finally        用来作必定要作的事情
        raise               用来发生异常通知
        assert             用来根据条件来发出AssertionError类型的异常通知
    with语句:
        语法:with 表达式1 [as 变量1],表达式2 [as 变量2]:
                        语句块
        做用:使用于对资源进行访问的场合,肯定使用过程当中不论是否发生异常,都会执行必须的‘清理’操做,并释放资源
            如:文件使用后自动关闭,线程中锁的自动获取和释放等
        说明:可以用于with语句进行管理的对象必须是环境管理器

'''此示例示意用try-except 和 try-finally 组合来对文件进行操做'''
def read_from_file(filename="info.txt"):
    try:
        f = open(filename)
        try:
            print("正在读取文件")
            n = int(f.read())
            print("n=",n)
        finally:
            f.close()
            print("文件已经关闭")
    except OSError:
        print("文件打开失败")
read_from_file()
View Code

环境管理器:
    一、类内有__enter__ 和 __exit__实例方法的类被称为环境管理器
    二、能用with语句管理的对象必须是环境管理器
    三、__enter__方法将在进入with语句时被调用,并返回由as变量管理的对象
    四、__exit__方法将在离开with语句时被调用,且能够用参数来判断在离开with语句时是否有异常发生并作出相应的处理

contextlib,给咱们提供了一个装饰器,只要按照它的代码协议来实现函数内容,就能够将这个函数对象变成一个上下文管理器

使用环境管理器(上下文管理器)的好处

  1.提升代码的复用率

  2.提升代码的优雅度

  3.提升代码的可读性

import contextlib

@contextlib.contextmanager
def open_func(file_name):
    #__enter__方法
    print('openfile',file_name,'in __enter__')
    file_handler = open(file_name,'r')

    #在被装饰的函数中,必须是一个生成器,而yield以前的代码至关于__enter__,以后的代码至关于__exit__
    try:
        yield file_handler
    except Exception as e:
        print(e)
    finally:
        print('closefile',file_name,'in __exit__')
        file_handler.close()

if __name__ == "__main__":
    with open_func('aa.txt') as f:
        print(f)
        1 / 0
def read_from_file(filename="info.txt"):
    try:
        with open(filename) as f:
            print("正在读取文件")
            n = int(f.read())
            print("n=",n)
            print("文件已经关闭")
    except OSError:
        print("文件打开失败")
read_from_file()
View Code
'''此示例示意环境管理器的定义及使用'''
class A:
    def __enter__(self):
        print("已经进入with语句")
        return self #返回的对象将由as 绑定
    def __exit__(self,exc_type,exc_val,exc_tb):
        '''此方法会在退出with语句时自动调用
            exc_type在没有异常时为None,在出现异常时为绑定异常类型
            exc_val在没有异常时为None,在出现异常时绑定错误对象
            exc_tb在没有异常时为None,在出现异常时绑定traceback(跟踪)'''
        if exc_type is None:
            print("正常离开with语句!")
        else:
            print("异常离开with语句!")
            print("异常类型是:",exc_type)
            print("错误对象是",exc_val)
            print("traceback是:",exc_tb)
with A() as a:
    print("我是with语句内的一条语句")
    int(input("输入一个数:"))
# 已经进入with语句
# 我是with语句内的一条语句
# 输入一个数:aa
# 异常离开with语句!
# 异常类型是: <class 'ValueError'>
# 错误对象是 invalid literal for int() with base 10: 'aa'
# traceback是: <traceback object at 0x7f443a0e2748>
# Traceback (most recent call last):
#   File "02_enter_exit.py", line 24, in <module>
#     int(input("输入一个数:"))
# ValueError: invalid literal for int() with base 10: 'aa'
View Code
相关文章
相关标签/搜索