zoukankan      html  css  js  c++  java
  • Python学习笔记

    ------------------从2014-8-1号开始重新学习Python的笔记------------------

    是学习vamei的Python快速教程的笔记。

    1、关于变量

    在Python中,变量不需要声明,可以直接使用

    2、序列(Squence)是一种有序元素的组合

    有:tuple(定值表,或称为元组,用圆括号表示)、list(表,用方括号表示)。tuple的值不可以变,list的值可以变。

     3、一个新的函数,range()可以用来帮助建立表list,实现循环的时候会经常用到。

     for循环使用的格式是:

    for 元素 in 序列:
        statement

    序列可以是tuple,也可以是list,而且list可以用range()来创建。

    while就比较简单了:

    while 条件:
        statement

    4、Python下面也有值传递(不会影响传递变量的值,他会在函数内部重新产生一个变量)&指针传递(会改变传递变量的值)

    值传递发生在传递的是基本数据类型的变量,像是整形啊什么的。

    指针传递发生在将一个表list传递给一个函数,对于表来说,表传递给函数的是一个指针,指针指向序列在内存中的位置,在函数中对表的操作将在原有内存中进行,从而影响原有变量。

     附加,定义一个函数的格式为

    def functionname(参数):
        statement
        return something    #return is not necessary

    记住:一个函数是一个对象 

    5、Python中的面向对象

    Python的类有属性(attribute)&方法(method)。方法的第一个参数是self,因为我们需要用self来调用这个类的属性

    特殊方法:特殊方法名字前后都有两个下划线。如__init__(),在初始化的时候都会调用这个函数,在建立对象时自动执行。

    class Human(object):
        def __init__(self, input_gender):
            self.gender = input_gender
        def printGender(self):
            print self.gender
    
    li_lei = Human('male') # 这里,'male'作为参数传递给__init__()方法的input_gender变量。
    print li_lei.gender
    li_lei.printGender()

    __init__()把属性Human.gender的不确定表现的很好,让我们自己来设定。NOTE:跟构造有同样的作用。

    6、自学Python很重要的两个命令

    dir()用来查询一个类或者对象的属性。help()用来查询说明文档。

    注意:要明确Everything is Object!像我们用到的list、int都是一个类。

    7、一个新的类:dictionary字典,它分为键和值,注意,词典的元素没有顺序,不能通过下标引用元素,而是用键来引用。。ex:   dic={'tom':11,'sam':57,'lily':34}

    容器(Container),可以存储多个元素的对象叫做容器。圆括号是tuple,中括号是list,大括号是dictionary

     注意,字典的常用方法:dictionary.keys(),获取所有键;dictionary.values(),获取所有值;dictionary.items(),所有元素,也就是键值对;dictionary.clear(),清空。     dic是一个对象,dic(键)就是代表相应的值。

    8、文件操作

    打开文件:

    f=open(文件名,模式)   #模式有“r”,只读;“w”,写入

    操作:

    content=f.read(N)           #读取N bytes的数据
    content=f.readline()        #读取一行
    content=f.readlines()       #读取所有行,存储在列表中,每个元素是一行
    
    f.write('I love U')

    关闭文件:

    f.close()

    我们用print dir(file) 可以打印出更多的属性和方法。像是writelines()啊什么的都可以看见了。

    9、模块(module):一个.py文件就是一个模块。

    在一个模块中引入另一个模块a,这样写    import a

    引入模块后,可以通过模块.对象的方式来调用引入模块中的某个对象(也可以用这种格式调用其中的函数,因为函数就是一个对象)。

    其他的引入方式:

      import a as b  将名字a重命名为b

      from a import function1  引用a.function1,但是不用前面那么男写了,直接写function1就ok啦

      from a import *      你懂的,跟上面的很像嘛

    import搜索包的路径有:文件所在文件夹,标准库安装路径,操作系统环境变量PYTHONPATH所包涵的路径。

    模块包,将功能相似的模块房子啊同一个文件夹(比如说this_dir)中,构成一个模块包,通过 import this_dir.module   引入文件夹中的module模块。文件夹中必须要包含一个__init__.py,提醒Python,该文件为一个模块包,__init__.py可以是一个空文件。

    10、函数的参数

    默认参数的设置

    def f(a,b,c=10):
        return a+b+c
    
    print(f(3,2))
    print(f(3,2,5))    #这样就对了,这样的话c就不是默认的10,c的值是5

    包裹传递

    在定义函数的时候,我们不知道要调用的时候会传递多少个参数。这时候,包裹(Packing)位置参数,或者包裹关键字参数,来进行参数传递,it works。 

    def func(*name):

    在func参数表中,所有的参数被name收集,根据位置合并成一个元组(tuple)。为了提醒Python参数,name是包裹位置传递所用的元组名,在定义func时,在name前加*号

    def func(**dict):

    合并成一个字典(dictionary)。要在前面加**

    *和**,也可以在调用的时候使用,即解包裹(unpacking)

    11、几个可以使循环更加灵活的函数

    first one:      range()

    second one:  enumerate(),每次循环可以同时得到下标和元素。

    third one:  zip(),有多个等长的序列,然后想要每次循环时从各个序列分别取出一个元素,用它。每次循环,在list从左至右取出一个数组成一个tuple,所有的tuple合并成一个list:

    ta=[1,2,3]
    tb=[7,8,9]
    
    #cluster   聚合
    zipped=zip(ta,tb)
    print(zipped)
    
    #decompose    解聚合
    na,nb=zip(*zipped)
    print(na.nb)

    上面这个例子就很吊啦。注意decompose之后是几个tuple,而不是list。

    12、循环对象

    iteration [计算机]循环,迭代

    一、迭代器iter()

    生成器(generator)的主要目的就是构成一个用户自定义的循环对象。generator的编写方法和函数定义类似,只是在return的地方改为yield它可以有多个yield,当生成器遇到一个yield的时候会暂停运行生成器,返回yield后面的值,当再次调用生成器的时候会从刚才暂停的地方继续运行,知道下一个yield

    二、生成器表达式(generator expression)generator expression是生成器的一种简便的编写方式

    一个生成器:

    def gen():
        for i in range(4):
            yield i

    可以写成generator expression:

    G=(x for x in range(4))

    三、表推导(list comprehension)是快速生成表的方法。语法简单,很有实用价值。

    L=[]
    for x in range(10):
        L.append(x**2)

    生成一个表。也可以用表推导的方式:

    L=[x**2 for x in range(10)]

    表推导与生成器表达式类似,只不过generator expression用的是小括号,表推导list comperhension用的是中括号。

    13、函数对象

    函数也可以作为一个对象进行参数传递,当然函数也可以作为一个对象作为return的结果。函数一个简写的方法,lambda表达式

    def func(x,y):
        return x+y
    
    #which can be express as follows
    func=lambda x,y:x+y

    map()函数

    re=map((lambda x:x+3),[1,2,4,6])

    map()的功能是将后面list中数值依次带入前面的函数中,得到的结果依次放在re表中。

    filter()函数

    filter()第一个参数为一个函数,第二个对象是一个列表list,将list中的数依次放入到函数中运算,返回的是True则将这儿数放到结果的list中,要是返回的是False,则这个数就被过滤掉了。

    reduce()函数 

    print reduce((lambda x,y:x+y),[1,3,4,5,7,9])

    上面的例子相当于((((1+3)+4)+5)+7)+9

    reduce()函数在3.0里面不能直接用的,它被定义在了functools包里面,需要引入包。

    14、上下文管理器(Context Manager)

     规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存,只是比如,并不是所有的离开了context就是释放了内存空间对象回收了)。它的语法形式是with   ..EXPRESS..   as  ..VAR..

    任何定义了__enter__()__exit__()方法的对象都可以用于上下文管理器。

    实际上,任何一个有__call__()特殊方法的对象都被当作是函数。

    15、属性attribute

    类属性(class attribute)对象属性(object attribute)。对象属性存储在对象的__dict__属性中,__dict__是一个词典,键为属性名,值为属性本身

    在不知道一个对象用的是什么类的时候,用__class__属性可以找到对象的类,用类的__base__属性来查询父类。

    特性(porperty)。一个对象的属性可能依赖另一个属性,当一个属性修改的时依赖他的属性也会相应改变。这是Python就需要一种特殊的机制来即时生成属性,这就是特性。特性使用内置函数property()来创建。前三个参数为函数,分别用于处理查询特性、修改特性、删除特性。最后一个参数为特性的文档,可以为一个字符串,起说明作用。

    __getattr__(),他是一个特殊的方法,用来获得即时的生成的属性。我们用__dict__无法找到即时的属性,通过__getattr__()就可以获得该属性。

    Python中还有一个__getattribute__特殊方法,用于查询任意属性。__getattr__只能用来查询不在__dict__系统中的属性

    16、闭包(closure)

    closure之于函数式编程,就像函数之于面向过程编程,class之于面向对象编程。

    闭包(closure):一个函数和它的环境变量一起组成了一个闭包。环境变量取值被保存在函数对象的__closure__属性中。

    def line_conf(a, b):
        def line(x):
            return ax + b
        return line
    
    line1 = line_conf(1, 1)
    line2 = line_conf(4, 5)
    print(line1(5), line2(5))

    上面就是闭包的一个很好的例子。利用line1和line2创建了两个函数x+1,4x+5,并将它们返回,在print中有可以利用它们。这样就利用闭包创建了泛函。有效的减少了要定义函数的数目,减少了函数所需要定义的参数的数目。

    17、装饰器(decorator)

    def decorator(F):
        def new_F(a, b):
            print("input", a, b)
            return F(a, b)
        return new_F
    
    # get square sum
    @decorator
    def square_sum(a, b):
        return a**2 + b**2
    
    # get square diff
    @decorator
    def square_diff(a, b):
        return a**2 - b**2
    
    print(square_sum(3, 4))
    print(square_diff(3, 4))

    看上面的例子,我们可以很明显的发现,decorator就是将函数当做一个对象传递进来再将处理好的函数输出出去。被@了的函数就换掉了。

    装饰器接受一个函数,并返回一个函数,从而起到加工函数的效果

    扩展一下:接受一个类,处理之后返回一个类,就达到了加工类的效果。这就是装饰类

    18、标准库(standard library)

    forgive me,我已经迫不及待要进行标准库以及网络和服务器的搭建学习,基于Python。

    Python的强大得益于它丰富的模块。

    标准库:标准库会随着Python解释器,一起安装在你的电脑中的。它是Python的一个组成部分。这些标准库是Python为你准备好的利器,可以让编程事半功倍。

      正则表达式(re,regular expression)注意之前混淆的     .任意一个字符  *重复>=0次  +重复>=1次  ?重复0次或1次

      时间包有time包和datetime

      os.path包主要是处理路径字符串(这个包一部分类似于Linux中的ls命令)。

      文件管理有(os部分,shutil包)

      存储对象管理。我们在将内存中的数据转化成文本流(这个过程叫做serialize),然后将文本流存到文件中。由于有些对象的类使我们自己定义的,所以serialize的时候我们需要知道类的格式才是存储。所以我们需要用Python中的pickle包。还有就是cPickle,用法与pickle一样。可以用 import cPickle as pickle  然后就将cPickle当做pickle一样用就好了。

      pickle.dumps() #serialize object  pickle.dump()#serialize and save object  

      pickle.load()#read file and build object

      执行外部命令和程序用subprocess包,从这个意义上来说,subprocess的功能与shell类似。这个简直是太棒了! 

    在Python下利用subprocess调用shell命令

        除了subprocess.call()之外还有subprocess.check_call()、subprocess.check_output(),他们的用法几乎相同。实际上他们的用法都是基于Popen()的封装(wrapped)。 

    import subprocess
    child = subprocess.Popen(["ping","-c","5","www.google.com"])
    child.wait()
    print("parent process")

      要是没有child.wait()的话,就不一定先执行ping了,他会先执行print。

      另外还有:

    child.poll()           # 检查子进程状态
    
    child.kill()           # 终止子进程
    
    child.send_signal()    # 向子进程发送信号
    
    child.terminate()      # 终止子进程

      subprocess.PIPE的用法 

    import subprocess
    child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
    child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
    out = child2.communicate()
    print(out)

      subprocess.PIPE实际上为文本流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

      Popen.wait(), Popen.communicate()

      信号包signal。用signal.signal(signalnum, handler)来预设信号处理函数。一个有用的函数是signal.alarm(),它被用于在一定时间之后,向进程自身发送SIGALRM信号。

      补充几个信号:

      SIGINT   当键盘按下CTRL+C从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是中断(INTERRUPT) 该进程。

      SIGQUIT  当键盘按下CTRL+从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是退出 (QUIT) 该进程。

      SIGTSTP  当键盘按下CTRL+Z从shell中发出信号,信号被传递给shell中前台运行的进程,对应该信号的默认操作是暂停 (STOP) 该进程。

      SIGCONT  用于通知暂停的进程继续。

      SIGALRM  起到定时器的作用,通常是程序在一定的时间之后才生成该信号。

      实现多线程用threading包。

    19、网络编程

     在Python中,我们利用socket包来进行网络编程。然而,socket传输自由度太高,从而带来很多安全和兼容的问题。我们往往利用高一些应用层协议来规定socket使用规则。以及所传输信息的格式。

    我们还可以用SocketServer包来方便的架设服务器。

    20.Django网络架构

     要完成一个完美的服务器,需要学习MySQL。我能不能继续学习MySQL!

    ------------------以下全是2014-8-1号之前的笔记----------------

    1.变量是指向内存的地址,改变数据值的大小,是改变他的指向。所以我们不能通过给变量赋值改变内存中的值。

    2.变量不需要指定变量的类型:因为他们都是指向某一块数据类型单元,他们的类型是一样的,不要指定什么类型

    3.在linux中安装第三方函数库很简单:easy_install httplib2

    4.python的函数库主要包括:系统函数库、网上的第三方函数库、自己写的函数

    5.Type(a) 输出变量a的类型

    6.序列(Sequence)有两种:tuple(定值表; 也有翻译为元组) 和 list (表)。

    一旦建立,tuple的各个元素不可再变更,而list的各个元素可以再变更。

    7.字符串是一种特殊的元组!!!!

    ×8.乘方运算,比如3的2次方写成: 3**2

    9.if elif else

    10.range()可以用来建立表

    11.函数的定义以def作为标记

    12.None是Python中特殊的字符,表示什么也没有

    13.基本数据类型的参数:值传递; 表作为参数:指针传递

    14.在class中定义一个方法用def(跟函数的定义是一样的),方法的第一个参数必须是self,不管是不是用得到。

    15.Python中的继承,是直接卸载类名后面的括号中的,要是没有父类就写object

    16.在第14条中说到,方法的第一个参数必须是self,为什么?通过self,调用类的其他属性。

    17.__init__()是一个特殊方法(special method)。Python有一些特殊方法。Python会特殊的对待它们。特殊方法的特点是名字前后有两个下划线。
    如果你在类中定义了__init__()这个方法,创建对象时,Python会自动调用这个方法。这个过程也叫初始化。

    18.__init__()是初始化,不是什么构造函数。__init__(): 在建立对象时自动执行.

    19.dir()用来查询一个类或者对象所有属性; help()用来查询说明文档。

    20.词典(dictionary)与列表相似,可以存储多个元素。这种存储多个元素的对象成为容器(container)。

    21.在Python中,一个.py文件就构成一个模块。通过模块,你可以调用其它文件中的程序。引入模块用import

    22.可以将功能相似的模块放在同一个文件夹(比如说this_dir)中,构成一个模块包。该文件夹中必须包含一个__init__.py的文件,提醒Python,该文件夹为一个模块包。__init__.py可以是一个空文件。

    23.函数的参数传递可以有关键字传递。

    24.关键字(keyword)传递是根据每个参数的名字传递参数。

    25.包裹传递(Packing).在定义函数时,我们有时候并不知道调用的时候会传递多少个参数。这时候,包裹(packing)位置参数,或者包裹关键字参数,来进行参数传递.
    包裹传递的关键在于定义函数时,在相应元组(tuple)或字典(dict)前加*或**。

    26.*和**,也可以在调用的时候使用,即解包裹(unpacking).

    27.用range()来控制for循环

    28.利用enumerate()函数,可以在每次循环中同时得到下标和元素。

    29.如果有多个等长的序列,然后想要每次循环时从各个序列分别取出一个元素,可以利用zip()方便地实现。zip()函数的功能,就是从多个列表中,依次各取出一个元素。每次取出的(来自不同列表的)元素合成一个元组,合并成的元组放入zip()返回的列表中。zip()函数起到了聚合列表的功能。

    30.当一个循环结构(比如for)调用循环对象时,它就会每次循环的时候调用next()方法,直到StopIteration出现,for循环接收到,就知道循环已经结束,停止调用next()。

    31.生成器(generator)的主要目的是构成一个用户自定义的循环对象。
    生成器的编写方法和函数定义类似,只是在return的地方改为yield。生成器中可以有多个yield。当生成器遇到一个yield时,会暂停运行生成器,返回yield后面的值。当再次调用生成器的时候,会从刚才暂停的地方继续运行,直到下一个yield。生成器自身又构成一个循环器,每次循环使用一个yield返回的值。

    32.生成器表达式 (GeneratorExpression)

    33.表推导(list comprehension)是快速生成表的方法.
    Ex:L = [x**2 for x in range(10)]

    34.Python中函数也是一个对象

    35.lambda函数

    36.函数可以作为一个对象,进行参数传递。

    37.map()是Python的内置函数。map()的功能是将函数对象依次作用于表的每一个元素,他返回的是一个表(list)。

    38.filter().filter函数的第一个参数也是一个函数对象。它也是将作为参数的函数对象作用于多个元素。如果函数对象返回的是True,则该次的元素被储存于返回的表中(NOTE:说明在函数中要是返回的是True或者False,但是filter返回的是list中的数,而不是True或者False)。filter通过读入的函数来筛选数据。同样,在Python 3.X中,filter返回的不是表,而是循环对象。

    39.reduce函数的第一个参数也是函数,但有一个要求,就是这个函数自身能接收两个参数。reduce可以累进地将函数作用于各个参数。reduce()函数在3.0里面不能直接用的,它被定义在了functools包里面,需要引入包。

    40.在我们接触的对象中,有一类特殊的对象,是用于存储数据的。常见的该类对象包括各种数字,字符串,表,词典。在C语言中,我们称这样一些数据结构为变量。而在Python中,这些是对象。

    41.对象是储存在内存中的实体。但我们并不能直接接触到该对象。我们在程序中写的对象名,只是指向这一对象的引用(reference)。

    42.引用和对象分离,是动态类型的核心。

    43.关于对象动态类型的讨论→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→→ mutable object & immutable object
    列表可以通过引用其元素,改变对象自身(in-place change)。这种对象类型,称为可变数据对象(mutable object),词典也是这样的数据类型。
    而像之前的数字和字符串,不能改变对象本身,只能改变引用的指向,称为不可变数据对象(immutable object)。
    我们之前学的元组(tuple),尽管可以调用引用元素,但不可以赋值,因此不能改变对象自身,所以也算是immutable object.

    44.函数的参数传递,本质上传递的是引用。

    45.immutable对象和mutable对象在传递时的不同
    如果参数是不可变(immutable)的对象,a和x引用之间相互独立。对参数x的操作不会影响引用a。这样的传递类似于C语言中的值传递。
    如果传递的是可变(mutable)的对象,那么改变函数参数,有可能改变原对象。

    46.但是Python也提供更加简洁的语法,让你使用不同的编程形态,从而在必要时隐藏一些面向对象的接口。
    EX:在连接字符串的时候'abc'+'def',实际上是利用了字符串'abc'对象的方法.__add__() 所以实际执行的操作是'abc'.__add__('def')

    47.上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...
    NOTE:很像C#中的using语句

    48.Python中变量名和对象是分离的。变量名可以指向任何一个对象。

    49.装饰器(decorator)接收一个函数/类,返回一个函数/类。
    从本质上,装饰器起到的就是一个重新指向变量名的作用(name binding),让同一个变量名指向一个新返回的可调用对象,从而达到修改可调用对象的目的。

    50.为了探索对象在内存的存储,我们可以求助于Python的内置函数id()。它用于返回对象的身份(identity)。其实,这里所谓的身份,就是该对象的内存地址。

    51.is用于判断两个引用所指的对象是否相同。

    52.Python的一个容器对象(container),比如表、词典等,可以包含多个对象。实际上,容器对象中包含的并不是元素对象本身,是指向各个元素对象的引用。

    53.Python中内置的对字符串进行格式化的操作%

    54.IndentationError: unexpected indent错误
    提示格式不对,检查缩进等等可能出现的错误

    55.程序包(Package)

    56.pip
    A tool for installing and managing Python packages.
    在https://pypi.python.org/pypi/pip中可下载

    57.在Python里面任何非0的数也会被解释为'True'

    58.pass
    pass表示什么也不做,pass

    59.在Python3中,即使是整数相除,除法也会进行浮点数除法。

    60.Python可是一个文件管理的利器

    61.关于文本流与serialize
    计算机的内存中存储的是二进制的序列 (当然,在Linux眼中,是文本流)。我们可以直接将某个对象所对应位置的数据抓取下来,转换成文本流 (这个过程叫做serialize),然后将文本流存入到文件中。

    -------------------------------语法(Syntax)------------------------------------------

    1.import re
    添加正则表达式的包

    2.用from导入模块
    如 from math import pi,现在就可以直接用pi了。要是没有前面的from,直接写import math,在用pi的时候须写成 math.pi

    3.Python2提供了一个内置函数raw_input来从键盘获取输入。在Python3里,这个函数是input

    4.time包

    5.datetime包是基于time包的一个高级包, 为我们提供了多一层的便利。datetime可以理解为date和time两个组成部分。date是指年月日构成的日期(相当于日历),time是指时分秒微秒构成的一天24小时中的具体时间(相当于手表)

    6.os.path 包主要是处理路径字符串。os.path还可以查询文件的相关信息(metadata)。实际上,这一部分,类似于Linux中的ls命令的某些功能。

    7.glob包最常用的方法只有一个, glob.glob()。该方法的功能与Linux中的ls相似

    8.os包包括各种各样的函数,以实现操作系统的许多功能。这个包非常庞杂。os包的一些命令就是用于文件管理。

    9.cwd(current working directory,当前工作路径)

    10.pickele和cPickle可以将:内存中的对象转换成文本流;重建对象

    11.subprocess包主要功能是执行外部的命令和程序,从这个意义上来说,subprocess的功能与shell类似。subprocess可以创建子进程,另外它还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

    12.用subprocess.Popen()创建子进程,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待(也就是阻塞block)

    13.可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe).subprocess.PIPE实际上为文本流提供一个缓存区。

    14.通过使用subprocess包,我们可以运行外部程序。这极大的拓展了Python的功能。

    15.signal信号
    要注意,signal包主要是针对UNIX平台(比如Linux, MAC OS),而Windows内核中由于对信号机制的支持不充分,所以在Windows上的Python不能发挥信号系统的功能。

    16.signal包的核心是使用signal.signal()函数来预设(register)信号处理函数

    17.socket包,用来进行底层的socket的编程

    Just like writing, coding is a work of creating!
  • 相关阅读:
    OpenStreetMap/Google/百度/Bing瓦片地图服务(TMS)
    【APM】Pinpoint 监控告警(三)
    【APM】Pinpoint 使用教程(二)
    【APM】Pinpoint 安装部署(一)
    【HBase】HBase 单机版安装及使用
    【SpringBoot】SpringBoot快速入门(一)
    【Java】Swagger快速入门
    【WebSocket】WebSocket快速入门
    【JS】AJAX跨域-被调用方与调用方解决方案(二)
    【JS】AJAX跨域-JSONP解决方案(一)
  • 原文地址:https://www.cnblogs.com/chenbuer/p/3843528.html
Copyright © 2011-2022 走看看