zoukankan      html  css  js  c++  java
  • Python进阶笔记

    1. 列表生成式
    2. 函数的参数类型
    3. lambda函数
    4. map, reduce, filter, sorted函数
    5. eval, exec, join, zip函数
    6. itertools中的函数
    7. copy与deepcopy函数
    8. 模块
    9. os、sys模块
    10. 迭代器
    11. 生成器
    12. 迭代器

    参考网站:

    1. Python3教程: https://www.python-course.eu/python3_course.php
    2. Python之函数参数的使用:https://blog.csdn.net/jclian91/article/details/78309522
    3. 廖雪峰Python教程: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
    4. Python之浅谈exec函数: https://blog.csdn.net/jclian91/article/details/80076512
    5. Python官网的itertools说明: https://docs.python.org/3.6/library/itertools.html
    6. Python-copy()与deepcopy()区别: https://blog.csdn.net/qq_32907349/article/details/52190796
    7. copy模块官网:https://docs.python.org/3.5/library/copy.html

    列表生成式

    列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。一般是利用原有的数据结构来生成新的列表。

    # 利用range()生成[1,2,...,9,10]
    list(range(1,11))
    
    # 生成[1x1, 2x2, 3x3, ..., 10x10]
    [x * x for x in range(1, 11)]
    # 可以通过占位符_代表列表中的元素
    [_*_ for _ in range(1,11)]
    
    # 筛选出仅偶数的平方, 在for循环后加上if判断语句
    [x * x for x in range(1, 11) if x % 2 == 0]
    # 利用占位符简化
    [_*_ for _ in range(1, 11) if not _%2]
    
    # 两层循环,三层循环,....
    [m + n for m in 'ABC' for n in 'XYZ']
    [x+y+z for x in  'ab' for y in 'cd' for z in 'ef']
    
    # 遍历字典,生成列表
    d = {'x': 'A', 'y': 'B', 'z': 'C' }
    [k + '=' + v for k, v in d.items()]
    

    函数的参数类型

    在Python中定义函数,其参数类型有:

    • 位置参数
    • 默认参数
    • 可变参数
    • 关键字参数

    这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:位置参数、默认参数、可变参数和关键字参数。

    可变参数以*开头,允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。关键字参数以**开头,允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个dict。若默认参数与可变参数放在一起,则接受完默认参数后,其后参数为可变参数。

    位置参数

    位置参数指定名称的必须放在未指定名称的后面

    def person(name,age,city):
        s = "info: name=%s, age=%s, city=%s"%(name,age,city)
        return s
    
    print(person('Jack', 25, 'NY'))
    print(person(name='Jack', age=25, city='NY'))
    print(person('Jack', 25, city='NY'))
    # 下面的参数使用有误,位置参数指定名称的必须放在未指定名称的后面
    print(person(name='Jack', 25, 'NY'))
    

    默认参数

    默认参数必须放在非默认参数的后面,可以该表默认参数的值

    def person(name, city, age=18):
        s = "info: name=%s, age=%s, city=%s"%(name,age,city)
        return s
    
    print(person('Jack', 'NY'))
    print(person('Jack', 'NY', 20))
    

    可变参数

    可变参数以*开头,允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。函数参数的长度是可以变化的, 例如内置的sum, min, max等

    def var_sum(*args):
        sum = 0
        for i in args:
            sum += i
    
        return sum
    
    print(var_sum(1,2,3))
    print(var_sum(1,2,3,4))
    # 利用*号来分解参数
    print(var_sum(*[1,2,3,4,5]))
    

    若位置参数或默认参数与可变参数放在一起,则接受完位置参数或默认参数后,其后参数为可变参数。

    def var_sum(a, *args):
        sum = 0
        for i in args:
            sum += i
    
        print('a is %s, sum is %s'%(a,sum))
    
    var_sum(1,2)
    var_sum(1,2,3)
    

    关键字参数

    关键字参数以**开头,允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个dict。

    def test_args(**kwargs):
        print('-'*20)
        for key in kwargs:
            print('key:', key, ',value:', kwargs[key])
    
        print()
    
    test_args(a=1,b=2)
    test_args(a=1,b=2,c=3)
    

    lambda函数

    lambda函数即为匿名函数,用关键字lambda表示,冒号(:)前面的为参数,后面为返回值,不用写return.

    如:

    lambda x: x*x
    

    匿名函数有个限制,就是只能有一个表达式,一般一行代码,不用写return,返回值就是该表达式的结果。

    用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数,即函数也是变量,此为函数式编程(functional programming)思想。

    f = lambda x: x*x
    f(5)
    

    map, reduce, filter, sorted函数

    map函数

    map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

    可以直接作用于for循环的对象统称为可迭代对象:Iterable.

    举例说明,比如我们有一个函数f(x)=x^2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:

    # map函数: 一一映射
    def f(x):
        return x * x
    
    r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    list(r)
    
    # 利用lambda简化上述代码
    
    list(map(lambda x: x*x, range(1, 11)))
    
    

    再例如: 把list所有数字转为字符串:

    list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
    

    reduce函数

    reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,一个是函数,一个是Iterable. reduce把结果继续和序列的下一个元素做累积计算,其效果就是:

    reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

    比方说对一个序列求和,就可以用reduce实现:

    # 导入reduce, 这很重要
    from functools import reduce
    
    def add(x, y):
        return x + y
    
    reduce(add, [1, 3, 5, 7, 9])
    
    # 利用lambda函数简化
    reduce(lambda x,y: x+y, range(1,10,2))
    

    作业: 利用reduce将序列[1, 3, 5, 7, 9]转化为整数13579.

    map, reduce的一个复杂例子:

    将字符串列表['1', '3', '5', '7', '9']转化为整数13579

    from functools import reduce
    
    a = ['1', '3', '5', '7', '9']
    t = reduce(lambda x,y: 10*x+y, map(int, a))
    print(t)
    

    filter函数

    Python内建的filter()函数用于过滤序列。

    和map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

    例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

    list(filter(lambda x: x%2 == 1, [1, 2, 4, 5, 6, 9, 10, 15]))
    

    sorted函数

    Python内置的sorted()函数就可以对list进行排序。

    sorted([36, 5, -12, 9, -21])
    

    此外,sorted()函数还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

    sorted([36, 5, -12, 9, -21], key=abs)
    sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
    
    

    高阶函数,就是让函数的参数能够接收别的函数。map, reduce, filter, sorted都是高阶函数。

    join, zip, eval, exec函数

    join函数

    Python中的join函数有两个,分别为: join()和os.path.join(),具体作用如下:

    • join(): 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串
    • os.path.join(): 将多个路径组合后返回

    字符串中的join()函数的使用方法:

    'sep'.join(seq)

    sep:分隔符。可以为空。 seq:要连接的元素序列。 返回一个新的字符串。

    seq = ['hello','good','boy','Dido']
    
    print(' '.join(seq))
    print('*'.join(seq))
    

    zip函数

    zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

    如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

    # basic use of zip
    x = [1, 2, 3]
    y = [4, 5, 6]
    zipped = zip(x, y)
    print(list(zipped))
    
    # zip for loops
    for i,j in zip(x,y):
        print(i, "->", j)
    
    # unzip the list
    a = [(1,2,3), (3,4,5)]
    x2, y2, z2 = zip(*a)
    print(x2)
    print(y2)
    print(z2)
    
    # transpose a matrix
    mtx = [(1, 2),
           (3, 4),
           (5, 6)]
    print(list(zip(*mtx)))
    
    # clustering a data series into n-length groups idiom
    seq = range(1, 10)
    print(list(zip(*[iter(seq)]*3)))
    
    # dict and zip
    keys = ['spam', 'eggs']
    vals = [42, 1729]
    d = dict(zip(keys, vals))
    print(d)
    
    

    eval函数

    eval函数用来计算字符串表达式的值

    t = eval("23")
    print(t)
    print(type(t))
    
    print(eval("(1+2)*(3+4)"))
    

    exec函数

    exec()是Python的内置函数,不同于eval()函数只能执行计算数学表达式的结果的功能,exec()能够动态地执行复杂的Python代码,能够十分强大。

    简单例子:

    # 执行简单的Python语句
    i = 12
    j = 13
    exec("answer=i*j")
    print("Answer is %s"%answer)
    
    # 执行复杂的Python语句
    func = "def fact(n):
    	return 1 if n==1 else n*fact(n-1)"
    exec(func)
    a = fact(5)
    print(a)
    

    exec函数还可以执行储存在其他文件中的Python代码,例如位于E盘的eg.txt,如下:

    def fact(n):
        if n==1:
            return 1
        else:
            return n*fact(n-1)
    t = fact(6)
    print(t)
    

    利用exec函数执行eg.txt中的代码:

    with open('E://eg.txt', 'r') as f:
        s = f.read()
    
    exec(s)
    

    还可以在exec()函数中加入参数,参数的传递可以写成字典(dict)形式。

    x = 10
    
    expr = """
    z = 30
    sum = x + y + z
    print(sum)
    """
    
    def func():
        y = 20
        exec(expr)
        exec(expr, {'x': 1, 'y': 2})
        exec(expr, {'x': 1, 'y': 2}, {'y': 3, 'z': 4})
    
    func()
    

    输出结果为:

    60 
    33 
    34
    

    itertools模块中的函数

    Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数。

    itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算。

    无穷迭代器

    Iterator Arguments Results Example
    count() start, [step] start, start+step, start+2*step, ... count(10) --> 10 11 12 13 14 ...
    cycle() p p0, p1, ... plast, p0, p1, ... cycle('ABCD') --> A B C D A B C D ...
    repeat() elem [,n] elem, elem, elem, ... endlessly or up to n times repeat(10, 3) --> 10 10 10

    “有限”迭代器

    Iterator Arguments Results Example
    accumulate() p [,func] p0, p0+p1, p0+p1+p2, ... accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    chain() p, q, ... p0, p1, ... plast, q0, q1, ... chain('ABC', 'DEF') --> A B C D E F
    chain.from_iterable() iterable p0, p1, ... plast, q0, q1, ... chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
    compress() data, selectors (d[0] if s[0]), (d[1] if s[1]), ... compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
    dropwhile() pred, seq seq[n], seq[n+1], starting when pred fails dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
    filterfalse() pred, seq elements of seq where pred(elem) is false filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
    groupby() iterable[, keyfunc] sub-iterators grouped by value of keyfunc(v)
    islice() seq, [start,] stop [, step] elements from seq[start:stop:step] islice('ABCDEFG', 2, None) --> C D E F G
    starmap() func, seq func(seq[0]), func(seq[1]), ... starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
    takewhile() pred, seq seq[0], seq[1], until pred fails takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
    tee() it, n it1, it2, ... itn splits one iterator into n
    zip_longest() p, q, ... (p[0], q[0]), (p[1], q[1]), ... zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-

    groupby()函数

    groupby()把迭代器中相邻的重复元素挑出来放在一起:

    for key, group in itertools.groupby('AAABBBCCAAA'):
         print(key, list(group))
    
    A ['A', 'A', 'A']
    B ['B', 'B', 'B']
    C ['C', 'C']
    A ['A', 'A', 'A']
    

    实际上挑选规则是通过函数完成的,只要作用于函数的两个元素返回的值相等,这两个元素就被认为是在一组的,而函数返回值作为组的key。

    另一个例子

    # 按身高归类
    from itertools import *
    
    def height_class(h):
        if h>180:
            return 'tall'
        elif h<160:
            return 'short'
        else:
            return 'middle'
    
    friends = [191, 158, 159, 165, 170, 177, 181, 182, 190]
    
    for m,n in groupby(friends,key = height_class):
        print(m)
        print(list(n))
    

    作业: 对于一组身高的数据(list),利用上面代码给出的身高标准,将所以的tall, short, middle归为一类。注意与groupby()函数的区别。

    tee()函数

    把一个迭代器分为n个迭代器, 返回一个元组.默认是两个

    from itertools import *
    a = "hello"
    c, d, e = tee(iter(a), 3)
    for i, j, k in zip(c, d, e):
        print(i, j, k)
    

    组合生成器

    Iterator Arguments Results
    product() p, q, ... [repeat=1] cartesian product, equivalent to a nested for-loop
    permutations() p[, r] r-length tuples, all possible orderings, no repeated elements
    combinations() p, r r-length tuples, in sorted order, no repeated elements
    combinations_with_replacement() p, r r-length tuples, in sorted order, with repeated elements
    product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
    permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
    combinations('ABCD', 2) AB AC AD BC BD CD
    combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD

    copy与deepcopy函数

    copy: 浅拷贝(shallow copy), deepcopy: 深拷贝(deep copy).

    • 我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。
    • 而浅复制并不会产生一个独立的对象单独存在,他只是将原有的数据块打上一个新标签,所以当其中一个标签被改变的时候,数据块就会发生变化,另一个标签也会随之改变。这就和我们寻常意义上的复制有所不同了。
    • 对于简单的 object,用 shallow copy 和 deep copy 没区别
    • 复杂的 object, 如 list 中套着 list 的情况,shallow copy 中的 子list,并未从原 object 真的「独立」出来。也就是说,如果你改变原 object 的子 list 中的一个元素,你的 copy 就会跟着一起变。这跟我们直觉上对「复制」的理解不同。

    例子:

    from copy import copy, deepcopy
    
    #origin 里边有三个元素:1,2,[3, 4]
    origin = [1, 2, [3, 4]]
    
    # cop1为浅拷贝,cop2为深拷贝
    cop1 = copy(origin)
    cop2 = deepcopy(origin)
    
    # cop1是否与cop2内容相同
    print(cop1 == cop2)
    # cop1是否与cop2为同一个引用
    print(cop1 is cop2)
    
    # 改变origin中嵌套列表中的元素
    origin[2][0] = "hey"
    
    # 查看输出
    print(origin)
    print(cop1)
    print(cop2)
    
    # 改变origin中嵌套列表中的元素
    origin[1] = "hello"
    
    # 查看输出
    print(origin)
    print(cop1)
    print(cop2)
    

    输出结果:

    True
    False
    [1, 2, ['hey', 4]]
    [1, 2, ['hey', 4]]
    [1, 2, [3, 4]]
    [1, 'hello', ['hey', 4]]
    [1, 2, ['hey', 4]]
    [1, 2, [3, 4]]
    

    模块

    在Python中,一个Python文件就是一个模块。

    模块让你能够有逻辑地组织你的 Python 代码段。

    把相关的代码分配到一个模块里能让你的代码更好用,更易懂。

    模块能定义函数,类和变量,模块里也能包含可执行的代码。

    一个简单的模块例子:

    hello.py

    def say_hello(name):
        s = 'hello, %s!'%name
        return s
    

    使用模块:

    • import module
    • from module import ...
    import hello
    
    print(hello.say_hello("Lee"))
    
    from hello import say_hello
    
    print(say_hello("Jack"))
    

    os、sys模块

    os模块

    os模块包含普遍的操作系统功能。

    os常用方法及属性

    os.sep 可以取代操作系统特定的路径分隔符。windows下为 “”
    os.name字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'。

    os.getcwd() 函数得到当前工作目录,即当前Python脚本工作的目录路径。

    os.getenv() 获取一个环境变量,如果没有返回none

    os.putenv(key, value) 设置一个环境变量值

    os.listdir(path) 返回指定目录下的所有文件和目录名。

    os.remove(path) 函数用来删除一个文件。

    os.system(command) 函数用来运行shell命令。

    os.linesep 字符串给出当前平台使用的行终止符。例如,Windows使用' ',Linux使用' '而Mac使用' '。

    os.curdir: 返回当前目录('.')

    os.chdir(dirname): 改变工作目录到dirname

    os.path常用方法:

    os.path.isfile()和os.path.isdir()函数分别检验给出的路径是一个文件还是目录。

    os.path.existe()函数用来检验给出的路径是否真地存在

    os.path.getsize(name):获得文件大小,如果name是目录返回0L

    os.path.abspath(name):获得绝对路径
    os.path.normpath(path):规范path字符串形式

    os.path.split(path) :将path分割成目录和文件名二元组返回。

    os.path.splitext():分离文件名与扩展名

    os.path.join(path,name):连接目录与文件名或目录;使用“”连接
    os.path.basename(path):返回文件名
    os.path.dirname(path):返回文件路径

    sys模块

    sys模块提供了一系列有关Python运行环境的变量和函数。

    sys模块的常用方法

    sys.argv: 实现从终端向程序传递参数。

    sys.exit([arg]): 程序中间的退出,arg=0为正常退出。

    sys.getdefaultencoding(): 获取系统当前编码,一般默认为ascii。

    sys.setdefaultencoding(): 设置系统默认编码,执行dir(sys)时不会看到这个方法,在解释器中执行不通过,可以先执行reload(sys),在执行 setdefaultencoding('utf8'),此时将系统默认编码设置为utf8。(见设置系统默认编码 )

    sys.getfilesystemencoding(): 获取文件系统使用编码方式,Windows下返回'mbcs',mac下返回'utf-8'.

    sys.path: 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。

    sys.platform: 获取当前系统平台。

    sys.stdin, sys.stdout, sys.stderr: stdin , stdout , 以及stderr 变量包含与标准I/O 流对应的流对象. 如果需要更好地控制输出,而print 不能满足你的要求, 它们就是你所需要的. 你也可以替换它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或者以非标准的方式处理它们

    生成器

    通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

    所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。

    创建generator的办法:

    • 把一个列表生成式的[]改成()
    • yield关键字

    将列表的[]改成()的例子:

    # 列表生成式
    L = [x * x for x in range(10)]
    print(type(L))
    
    # 创建生成器
    g = (x * x for x in range(10))
    print(type(g))
    
    # 获取下一个返回值
    # 当没有更多元素时,会抛出StopIteration错误
    print(next(g))
    print(next(g))
    print(next(g))
    
    # for循环
    for n in g:
        print(n)
    

    通过yield创建生成器

    # 普通方法生成斐波拉契数列
    # 前几个斐波拉契数
    def fib1(max):
        n, a, b = 0, 0, 1
        while n < max:
            print(b)
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    fib1(6)
    
    # 通过yield创建生成器
    # 注意yield的执行流程
    def fib2(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    
    # 将生成器函数赋值给变量f
    f = fib2(6)
    print(type(f))
    for n in f:
        print(n)
    

    generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

    generator执行流程的理解:

    def odd():
        print('step 1')
        yield 1
        print('step 2')
        yield(3)
        print('step 3')
        yield(5)
    
    o = odd()
    
    print(next(o))
    print(next(o))
    print(next(o))
    

    迭代器

    可以直接作用于for循环的数据类型有以下几种:

    • 集合数据类型,如list、tuple、dict、set、str等;

    • generator,包括生成器和带yield的generator function。

    这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

    可以使用isinstance()判断一个对象是否是Iterable对象:

    from collections import Iterable
    
    # 判断空列表是否为Iterable对象
    # True
    print(isinstance([], Iterable))
    
    # 判断空集合是否为Iterable对象
    # True
    print(isinstance({}, Iterable))
    
    # 判断字符是否为Iterable对象
    # True
    print(isinstance('abc', Iterable))
    
    # 判断生成器是否为Iterable对象
    # True
    print(isinstance((x for x in range(10)), Iterable))
    
    # 判断数字否为Iterable对象
    # False
    print(isinstance(100, Iterable))
    

    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

    可以使用isinstance()判断一个对象是否是Iterator对象:

    from collections import Iterator
    
    # 判断生成器是否为Iterator对象
    # True
    print(isinstance((x for x in range(10)), Iterator))
    
    # 判断空列表是否为Iterator对象
    # False
    print(isinstance([], Iterator))
    
    # 判断空集合是否为Iterator对象
    # False
    print(isinstance({}, Iterator))
    
    # 判断字符串是否为Iterator对象
    # False
    print(isinstance('abc', Iterator))
    

    生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

    把list、dict、str等Iterable变成Iterator可以使用iter()函数。

  • 相关阅读:
    20145325张梓靖 《Java程序设计》第9周学习总结
    20145325张梓靖 实验四 "Andoid开发基础"
    20145325张梓靖 《Java程序设计》第8周学习总结
    20145307《信息安全系统设计基础》第7周学习总结
    20145307《信息安全系统设计基础》第六周学习总结
    Y86模拟器安装
    20145307《信息安全系统设计基础》第五周学习总结PT2
    git失败案例
    20145307陈俊达《信息安全系统设计基础》第5周学习总结PT1
    20145307陈俊达《信息安全系统设计基础》第3周学习总结
  • 原文地址:https://www.cnblogs.com/jclian91/p/9152740.html
Copyright © 2011-2022 走看看