收藏 分享(赏)

python函数设计与异常.ppt

上传人:精品资料 文档编号:10876980 上传时间:2020-01-17 格式:PPT 页数:61 大小:8.66MB
下载 相关 举报
python函数设计与异常.ppt_第1页
第1页 / 共61页
python函数设计与异常.ppt_第2页
第2页 / 共61页
python函数设计与异常.ppt_第3页
第3页 / 共61页
python函数设计与异常.ppt_第4页
第4页 / 共61页
python函数设计与异常.ppt_第5页
第5页 / 共61页
点击查看更多>>
资源描述

1、Python函数设计和异常,汇报人:付红玉,汇报时间:2018年5月,函数设计与使用,1,“,”,Python函数,将可能需要反复执行的代码封装为函数,并在需要执行该段代码功能的地方进行调用,不仅可以实现代码的复用,更重要的是可以保证代码的一致性,只需要修改该函数代码则所有调用位置均得到体现。 在编写函数时,有很多原则需要参考和遵守: 1、不要在同一个函数中执行太多的功能,尽量只让其完成一个高度相关且大小合适的功能,以提高模块的内聚性。 2、尽量减少不同函数之间的隐式耦合,例如减少全局变量的使用,使得函数之间仅通过调用和参数传递来显式体现其相互关系。,2,函数定义,函数定义语法:def 函数名

2、(参数列表):注释函数体,函数形参不需要声明类型,也不需要指定函数返回值类型 即使该函数不需要接收任何参数,也必须保留一对空的圆括号 括号后面的冒号必不可少 函数体相对于def关键字必须保持一定的空格缩进 Python允许嵌套定义函数,注意事项,3,函数定义格式,生成斐波那契数列的函数定义和调用:,调用函数,1000是实参,n是形参,def fib(n):a, b = 1, 1while a n:print(a, end= )a, b = b, a+bprint()fib(1000),定义头,函数体,4,函数的注释,在定义函数时,开头部分的注释并不是必需的,但如果为函数的定义加上注释的话,可以

3、为用户提供友好的提示.,5,函数对象的增加、删除, def func():print(func.x) #查看func的成员 func() #现在函数func还没有成员x,出错 AttributeError: function object has no attribute x func.x = 3 #动态为函数增加新成员 func() 3 del func.x #删除成员 func() #删除之后不可访问 AttributeError: function object has no attribute x,6,函数的递归调用,函数的递归调用是函数调用的一种情况,函数调用自己,自己再调用自己,自

4、己再调用自己,当某个条件得到满足的时候,就不再调用了,然后再一层一层地返回知道该函数第一次调用的位置,需要用栈来存储该函数离开的位置,栈比较小,如果递归调用很深,则导致栈崩溃,7,尾递归,尾递归是指:在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。,8,递归实现n的阶乘:,def fact(n):if n=1:return 1return n * fact(n - 1),def fact(n):return fact_iter(n, 1)def fact_iter

5、(num, product):if num = 1:return productreturn fact_iter(num - 1, num * product),改成尾递归,return fact_iter(num - 1, num * product) 仅返回递归函数本身 num - 1和num * product在函数调用前就会被计算,不影响函数调用,遗憾的是:大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出,01,02,03,在Python中,定义函数时不需要声明函数的返回值类型,而是使用return语

6、句结束函数的执行的同时返回任意类型的值,函数返回值类型与return语句返回表达式的类型一致。,如果函数没有return语句或者执行了不返回任何值的return语句,Python将认为该函数以return None结束,即返回空值,函数基本语法,9,不论return语句出现在函数的什么位置,一旦得到执行将直接结束函数的执行。,函数参数不得不说的几件事(一),1)在定义函数时,对参数个数并没有限制,如果有多个形参,则需要使用逗号进行分隔.下面的函数用来接收2个参数,并输出其中的最大值: def printMax(a, b):if ab:pirnt(a, is the max)else:print

7、(b, is the max),2)对于绝大多数情况下,在函数内部直接修改形参的值不会影响实参 : def addOne(a):print(a) #输出原变量a的值a += 1 #这条语句会得到一个新的变量aprint(a) a = 3 addOne(a) 3 4 a 3,10,函数参数不得不说的几件事(二),在有些情况下,可以通过特殊的方式在函数内部修改实参的值。 def modify(v): #修改列表元素值v0 = v0+1 a = 2 modify(a) a 3 def modify(v, item): #为列表增加元素v.append(item) a = 2 modify(a, 3)

8、 a 2, 3 def modify(d): #修改字典元素值或为字典增加元素dage = 38 a = name:Dong, age:37, sex:Male a age: 37, name: Dong, sex: Male modify(a) a age: 38, name: Dong, sex: Male,11,函数参数不得不说的几件事(三),默认值参数 在调用带有默认值参数的函数时,可以不用为设置了默认值的形参进行传值,此时函数将会直接使用函数定义时设置的默认值,也可以通过显式赋值来替换其默认值。def 函数名(,形参名=默认值):函数体,可以使用“函数名._defaults_”随时查

9、看函数所有默认值参数的当前值,其返回值为一个元组,其中的元素依次表示每个默认值参数的当前值。 def say( message, times =1 ):print(message+ ) * times) say._defaults_ (1,),注意:函数参数的默认值是在定义函数时确定的,12,函数参数不得不说的几件事(四),(2)关键参数 通过关键参数可以按参数名字传递值,实参顺序可以和形参顺序不一致,但不影响参数值的传递结果,避免了用户需要牢记参数位置和顺序的麻烦,使得函数的调用和参数传递更加灵活方便。 def demo(a, b, c=5):print(a, b, c) demo(c=8,

10、 a=9, b=0) 9 0 8,13,函数参数不得不说的几件事(五),(3)可变长度参数 可变长度参数在定义函数时主要有两种形式:*parameter和*parameter,前者用来接收任意多个实参并将其放在一个元组中,后者接收类似于关键参数一样显式赋值形式的多个实参并将其放入字典中。,第一种形式可变长度参数的用法,无论调用该函数时传递了多少实参,一律将其放入元组中: def demo(*p):print(p) demo(1, 2, 3, 4, 5, 6, 7) (1, 2, 3, 4, 5, 6, 7),第二种形式可变长度参数的用法: def demo(*p):for item in p.

11、items():print(item) demo(x=1, y=2, z=3) (y, 2) (x, 1) (z, 3),14,函数参数不得不说的几件事(六),传递参数时的序列解包 def demo(a, b, c):print(a+b+c) seq = 1, 2, 3 demo(*seq) 6 tup = (1, 2, 3) demo(*tup) 6 dic = 1:a, 2:b, 3:c demo(*dic) 6 Set = 1, 2, 3 demo(*Set) 6 demo(*dic.values() abc,15,Key作为实参,函数参数不得不说的几件事(七),注意:调用函数时如果对实

12、参使用一个星号*进行序列解包,这么这些解包后的实参将会被当做普通位置参数对待,并且会在关键参数和使用两个星号*进行序列解包的参数之前进行处理。 def demo(a, b, c): #定义函数print(a, b, c) demo(a=1, *(2, 3) #序列解包相当于位置参数,优先处理 Traceback (most recent call last):File “, line 1, in demo(a=1, *(2, 3) TypeError: demo() got multiple values for argument a demo(c=1, *(2, 3) 2 3 1 demo(

13、*a:1, b:2, *(3,) #序列解包不能在关键参数解包之后 SyntaxError: iterable argument unpacking follows keyword argument unpacking demo(*(3,), *c:1, b:2) 3 2 1,16,参数检查,调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError:,17,def my_abs(x):if x = 0:return xelse:return -x, my_abs(1, 2) Traceback (most recent call last):File “, li

14、ne 1, in TypeError: my_abs() takes 1 positional argument but 2 were given,如果参数类型不对,Python解释器就无法帮我们检查。看一下 my_abs和内置函数abs的差别:, my_abs(A) Traceback (most recent call last):File “, line 1, in File “, line 2, in my_abs TypeError: unorderable types: str() = int() abs(A) Traceback (most recent call last):F

15、ile “, line 1, in TypeError: bad operand type for abs(): str,参数检查,我们修改一下my_abs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance()实现:,18,def my_abs(x):if not isinstance(x, (int, float):raise TypeError(bad operand type)if x = 0:return xelse:return -x, my_abs(A) Traceback (most recent call last):File

16、 “, line 1, in File “, line 3, in my_abs TypeError: bad operand type,变量的作用域,1、变量起作用的代码范围称为变量的作用域,不同作用域内变量名可以相同,互不影响 2、在函数内部定义的普通变量只在函数内部起作用,称为局部变量。当函数执行结束后,局部变量自动删除,不再可以使用 3、局部变量的引用比全局变量速度快,应优先考虑使用,1、一个变量已在函数外定义,如果在函数内需要为这个变量赋值,并要将这个赋值结果反映到函数外,可以在函数内使用global将其声明为全局变量。 2、如果一个变量在函数外没有定义,在函数内部也可以直接将一个变

17、量定义为全局变量,该函数执行后,将增加一个新的全局变量。,全局变量可以通过关键字global来定义。这分为两种情况:,19, def demo():global xx = 3y = 4print(x,y) x = 5 demo() 3 4 x 3 y NameError: name y is not defined, del x x NameError: name x is not defined demo() 3 4 x 3 y NameError: name y is not defined,变量的作用域例子,20,如果局部变量与全局变量具有相同的名字,那么该局部变量会在自己的作用域内隐藏

18、同名的全局变量。 def demo():x = 3 #创建了局部变量,并自动隐藏了同名的全局变量print(x) x = 5 demo() 3 x #函数执行不影响外面全局变量的值 5,变量的作用域例子,21,如果需要在同一个程序的不同模块之间共享全局变量的话,可以编写一个专门的模块来实现这一目的。例如,假设在模块A.py中有如下变量定义:global_variable = 0而在模块B.py中包含以下用来设置全局变量的语句: import A A.global_variable = 1在模块C.py中有以下语句来访问全局变量的值: import A print(A.global_variab

19、le),变量的作用域例子,22,lambda表达式可以用来声明匿名函数,也就是没有函数名字的临时使用的小函数,尤其适合需要一个函数作为另一个函数参数的场合。也可以定义匿名函数。 lambda表达式只可以包含一个表达式,该表达式的计算结果可以看作是函数的返回值,不允许包含复合语句,但在表达式中可以调用其他函数。,Lambda 表达式,格式: f = lambda x, y, z: x+y+z #可以给lambda表达式起名字 f(1,2,3) #像函数一样调用 6 g = lambda x, y=2, z=3: x+y+z #参数默认值 g(1) 6 g(2, z=4, y=5) #关键参数 1

20、1,23, L = (lambda x: x*2),(lambda x: x*3),(lambda x: x*4) print(L0(2),L1(2),L2(2) 4 8 16 D = f1:(lambda:2+3),f2:(lambda:2*3), f3:(lambda:2*3) print(Df1(), Df2(), Df3() 5 6 8 L = 1,2,3,4,5 print(list(map(lambda x: x+10, L) #模拟向量运算 11, 12, 13, 14, 15 L 1, 2, 3, 4, 5,Lambda 表达式,24, data = list(range(20

21、) #创建列表 data 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 import random random.shuffle(data) #打乱顺序 data 4, 3, 11, 13, 12, 15, 9, 2, 10, 6, 19, 18, 14, 8, 0, 7, 5, 17, 1, 16 data.sort(key=lambda x: x) #和不指定规则效果一样 data 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1

22、7, 18, 19 data.sort(key=lambda x: len(str(x) #按转换成字符串以后的长度排序 data 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 data.sort(key=lambda x: len(str(x), reverse=True) #降序排序 data 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,Lambda 表达式,25,函数可以返回多个值吗?答案是肯定的。 比如

23、在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的坐标:import mathdef move(x, y, step, angle=0):nx = x + step * math.cos(angle)ny = y - step * math.sin(angle)return nx, ny,函数返回多个值(一),26,import mathdef move(x, y, step, angle=0):nx = x + step * math.cos(angle)ny = y - step * math.sin(angle)return nx, ny,27,x, y =

24、move(100, 100, 60 ,math.pi/6) print(x,y) 151.96152422706632 70.0,但其实这只是一种假象,Python函数返回的仍然是单一值。, r = move(100, 100, 60, math.pi / 6) print(r) (151.96152422706632, 70.0),原来返回值是一个tuple! 多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,函数返回多个值(二),例1 编写函数,接收包含20个整数的列表lst和一个整数k作为参数,返回新列表。处理规则为:将列

25、表lst中下标k之前的元素逆序,下标k之后的元素逆序,然后将整个列表lst中的所有元素逆序。 def demo(lst, k):x = lst:kx.reverse()y = lstk:y.reverse()r = x+yreturn list(reversed(r)lst = list(range(1, 21) print(lst) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 print(demo(lst, 5) 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17

26、, 18, 19, 20, 1, 2, 3, 4, 5,案例精选(一),28,例2 编写函数,接收一个正偶数为参数,输出两个素数,并且这两个素数之和等于原来的正偶数。如果存在多组符合条件的素数,则全部输出。 import math def IsPrime(n):m = int(math.sqrt(n)+1for i in range(2, m):if n%i=0:return Falsereturn True def demo(n):if isinstance(n, int) and n0 and n%2=0:for i in range(3, int(n/2)+1):if i%2=1 and

27、 IsPrime(i) and IsPrime(n-i):print(i, +, n-i, =, n)demo(60),7 + 53 = 60 13 + 47 = 60 17 + 43 = 60 19 + 41 = 60 23 + 37 = 60 29 + 31 = 60,案例精选(二),29,例3 编写函数,接收两个正整数作为参数,返回一个元组,其中第一个元素为最大公约数,第二个元素为最小公倍数。 def demo(m, n):if mn:m, n = n, mp = m*nwhile m!=0:r = n%mn = mm = rreturn (n, int(p/n)print(demo(2

28、0, 30) (10,60),案例精选(三),30,函数设计与使用小结,1、定义函数时,需要确定函数名和参数个数2、如果有必要,可以先对参数的数据类型做检查3、函数体内部可以用return随时返回函数结果4、函数执行完毕也没有return语句时,自动return None5、函数可以同时返回多个值,但其实就是一个tuple,31,Python 异常处理结构,32,“,”,小故事,欧洲阿丽亚娜5型火箭经过近十年研发,1996年首次发射失败,火箭和箭上卫星全毁,造成巨大经济损失。事故起因是新火箭直接继承了4型火箭“久经考验”的控制系统,但5型火箭加速度大造成传感器读数大,导致一次从浮点数到整数的数

29、值转换溢出。惯性导航系统失效后飞行状态失控,控制系统关闭了火箭的状态调节系统,安全系统最后引爆火箭自毁。,33,箭载软件出错的原因是,没有达到软件容错的目标,异常的基础知识,34,“,”,异常概述,简单地说,异常是指程序运行时引发的错误,引发错误的原因有很多,例如除零、下标越界、文件不存在、网络异常、类型错误、名字错误、字典键错误、磁盘空间不足,等等。如果这些错误得不到正确的处理,将会导致程序终止运行,而合理地使用异常处理结果,可以使得程序更加健壮, 具有更强的容错性,不会因为用户不小心的错误输入或其他运行时原因而造成程序中止。,35,一、异常的基本概念,36,一、异常的几种表现形式,37,一

30、、异常处理的作用,1、提高程序的健壮性和容错性 2、把晦涩难懂的错误提示转换为友好提示显示给最终用户,?可不可以把所有代码都放到一个异常处理结构中?,影响出错后的调试和代码维护!,?可不可以为每条语句都配上异常处理结构?,导致代码乱且庞大!,注意:,不建议使用异常来代替常规的检查,如ifelse 判断 应避免过多使用异常处理机制,只在确实需要时采用使用 捕捉异常时,应尽量精准,并针对不同类型的异常设计不同的处理代码,38,一、 Python中异常类的层次结构,BaseException +- SystemExit +- KeyboardInterrupt +- GeneratorExit +-

31、 Exception +- StopIteration +- StandardError | +- BufferError | +- ArithmeticError | | +- FloatingPointError | | +- OverflowError | | +- ZeroDivisionError| +- AssertionError | +- AttributeError | +- EnvironmentError | | +- IOError | | +- OSError | | +- WindowsError| | +- VMSError (VMS),点击此处编辑文字阐述您的论

32、文内容,点击此处编辑文字阐述您的论文内容,点击此处编辑文字阐述您的论文内容,点击此处编辑文字阐述您的论文内容,点击此处编辑文字阐述您的论文内容,点击此处编辑文字阐述您的论文内容。,+- Exception+- StandardError| +- EOFError | +- ImportError | +- LookupError | | +- IndexError| | +- KeyError| +- MemoryError | +- NameError | | +- UnboundLocalError | +- ReferenceError | +- RuntimeError | | +-

33、NotImplementedError| +- SyntaxError | | +- IndentationError | | +- TabError | +- SystemError | +- TypeError| +- ValueError,39,一、 Python 自定义异常类,可以继承python内置异常类来实现自定义的异常类,class DatabaseException(Exception): #继承python的内置异常类def _init_(self,err=数据库错误): #在自定义异常类中,重写父类init方法Exception._init_(self,err)class

34、PreconditionsException(DatabaseException): #继承DatabaseExceptiondef _init_(self,err=PreconditionsErr):DatabaseException._init_(self,err),40,Python 自定义异常类,如果自己编写某个模块需要抛出多个不同的异常,可以先创建一个基类,再创建多个派生类分别表示不同的异常,class MyError(Exception): #基类passclass InputError(MyError): def _int_(self, expression, next, mes

35、sage): #继承基类,新建派生类self.expression = expressionself.message = messageclass TransitionError(MyError):def _int_(self, previous, next, message): #继承基类,新建派生类self.previous = previousself.next = nextself.message = message,41,常见异常处理结构,42,二、tryexcept结构,try:try块 #被监控的语句 except Exception as reason:except 块 #处理

36、异常的语句,try:try块 except BaseException as e: #不建议这样做except 块 #处理所有错误,try子句中的代码块放置可能出现异常的语句,except子句中的代码块处理异常,当需要捕获所有异常时,可以使用BaseException,43,二、tryexceptelse结构,for arg in sys.argv1:try:f = open(arg, r)except IOError:print(cannot open, arg)else:print(arg, has, len(f.readlines(), lines)f.close(),如果try范围内捕

37、获了异常,就执行except块:如果try范围内没有捕获异常,就执行else块,例如:查看多个文本,分析分别有多少行,44,try:f = open(test.txt, r)line = f.readline()print(line) except IOError:print(cannot open file) finally:f.close(),二、tryexceptfinally结构,try:f = open(test.txt, r)line = f.readline()print(line) except IOError:print(cannot open file) finally:f

38、.close(),使用异常处理结构保证文件总是能关闭,这样真的可以么?,使用异常处理结构的本意是为了防止文件读取操作出现异常而导致文件不能正常关闭,但是如果因为文件不存在而导致文件对象创建失败,那么finally子句中关闭文件对象的代码将会抛出异常,导致程序终止运行。,45,二、带有多个except的try结构,try:x = float(input(请输入被除数: )y = float(input(请输入除数: )z = x / y except ZeroDivisionError:print(除数不能为零) except TypeError:print(被除数和除数应为数值类型) exce

39、pt NameError:print(变量不存在) else:print(x, /, y, =, z),46,二、带有多个except的try结构,import sys try:f = open(myfile.txt)s = f.readline()i = int(s.trip()f.close() except (OSError, ValueError, RuntimeError, NameError): pass,也可以这样写: 将要捕获的异常写在一个元组中,可以使用一个except语句捕获多个异常:,47,def demo_div(a, b):try:return a/bexcept:p

40、assfinally:return -1,使用带有finally子句的异常处理结构时,应尽量避免在finally子句中使用return语句,否则可能会出现出乎意料的错误。,二、tryexceptfinally结构,demo_div(1, 0) -1,demo_div(1, 2) -1,48,def div(x,y)try :print(x/y)except ZeroDivisionError:print(ZeroDivisionError)except TypeError:print(TypeError)else:print(No Error)finally:print(executing f

41、inally clause),Python异常处理结构中可以同时包含多个except子句、else子句和finally子句,二、tryexceptexceptelsefinally结构,49,断言assert,断言语句的语法是: assert expression , reason assert len(lists) =5,列表元素个数小于5 assert 2=1,2不等于1,当判断表达式expression为真时,什么都不做;如果表达式为假,则抛出异常。,使用assert断言是学习python一个非常好的习惯, 在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行时崩溃,不如在出

42、现错误条件时就崩溃,这时候就需要assert断言的帮助。,断言语句assert也是一种比较常用的技术,常用来在程序的某个位置确认指定条件必须满足,常和异常处理结构一起使用,50,With上下文管理语句,在Python2.5中with关键字被加入,它是用来替代tryexceptfinally的模式。 1、使用with自动关闭资源,可以在代码块执行完毕后还原进入该代码块时的现场。 2、不论何种原因跳出with块,不论是否发生异常,总能保证文件被正确关闭,资源被正确释放。 3、用于文件使用后自动关闭,线程中锁的自动获取和释放,with EXPR as VAR :BLOCK,EXPR 可以是任意表达式

43、 as VAR 是可选的(起别名) BLOCK 是with语句的语句体,51,With上下文管理语句案例,file = open(“/tmp/foo.txt“) data = file.read() file.close(),try: f = open(xxx) except: print fail to open exit(-1) try: do something except: do something else:f.close(),52,with open(“/tmp/foo.txt“) as file:data = file.read(),用sys模块回溯 最后的异常,53,三、用s

44、ys模块回溯最后的异常,54,三、用sys模块回溯最后的异常,sys.exc_info()的返回值tuple是一个三元组(type, value, traceback) type 异常的类型 value异常的信息或者参数 traceback包含调用栈信息的对象,格式如下: import sys try:block except:tuple = sys.exc_info()print(tuple),55,三、用sys模块回溯最后的异常,def A():1/0 def B():A() def C():B(),C() ZeroDivisionError Traceback (most recent

45、call last) in ()C()in C()B()in B()A()in A()1/0 ZeroDivisionError: division by zero,使用sys.exc_info()查看异常信息 import sys try:C() except:r = sys.exc_info()print(r),(, ZeroDivisionError(division by zero,), ),56,如果需要的话,可以用traceback模块来查看详细信息:,三、用sys模块回溯最后的异常,import traceback import sys def A():1/0 def B():A

46、() def C():B() try:C() except:excType, excValue, excTraceback = sys.exc_info()traceback.print_exception(excType, excValue,excTraceback, limit = 3)print(excValue)traceback.print_tb(excTraceback),57,#err.py def foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():bar(0)main(),Traceback (mos

47、t recent call last):File “err.py“, line 11, in main()File “err.py“, line 9, in mainbar(0)File “err.py“, line 6, in barreturn foo(s) * 2File “err.py“, line 3, in fooreturn 10 / int(s) ZeroDivisionError: division by zero,从上往下可以看到整个错误的调用栈,四、python内置logging模块,58,四、python内置logging模块,# err_logging.py import loggingdef foo(s):return 10 / int(s)def bar(s):return foo(s) * 2def main():try:bar(0)except Exception as e:logging.exception(e)main() print(END),

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报