(一)functools:管理函数的工具

  1. import functools
  2.  
  3. '''
  4. functools模块提供了一些工具来管理或扩展和其他callable对象,从而不必完全重写
  5. '''

  

1.修饰符

  1. from functools import partial
  2.  
  3. '''
  4. functools模块提供的主要工具就是partial类,可以用来包装一个有默认参数的callable对象。
  5. 得到的对象本身就是callable,可以把它看作是原来的参数。
  6. '''
  7.  
  8. # 举个栗子
  9. def foo(name, age, gender):
  10. print(name, age, gender)
  11.  
  12. p = partial(foo, "mashiro", 16)
  13. p("female") # mashiro 16 female
  14. '''
  15. 可以看到p相当于是已经绑定了name和age的foo函数,name我们在传参的时候只需要传入一个gender就可以了
  16. 这个函数的源码实现比较复杂,但是如果以简单的装饰器的方式实现就很清晰了
  17. '''
  18.  
  19. def my_partial(f, name, age):
  20. def inner(gender):
  21. return f(name, age, gender)
  22. return inner
  23.  
  24. p = my_partial(foo, "satori", 16)
  25. p("female") # satori 16 female
  26. '''
  27. 可以看到,当我调用my_partial(foo, "satori", 16)的时候,返回了inner函数
  28. 此时的p相当于是inner,当我再调用p("female")的时候,等价于调用inner("female")
  29. 然后将两次传入的参数,按照顺序组合起来传递给foo函数,如果不限制参数的话就是:
  30. def my_partial(f, *args1, **kwargs1):
  31. def inner(*args2, **kwargs2):
  32. from collections import ChainMap
  33. args = args1 + args2
  34. kwargs = dict(ChainMap(kwargs1, kwargs2))
  35. return f(*args, **kwargs)
  36. return inner
  37.  
  38. 所以一定要和原函数的参数顺序保持一致,如果我传入p = my_partial("mashiro", 16),此时"mashiro"会传给name,16传给age
  39. 我再调用p(name="xxx")的话,肯定会报错的
  40. '''

  

  1. from functools import partial
  2. import functools
  3.  
  4. '''
  5. 默认情况下,partial对象没有__name__属性的,如果没有这些属性,那么被修饰的函数会很难调试。
  6. '''
  7.  
  8. def foo():
  9. # fucking
  10. pass
  11.  
  12. print(foo.__name__) # foo
  13. p = partial(foo)
  14. try:
  15. print(p.__name__)
  16. except AttributeError as e:
  17. print(e) # 'functools.partial' object has no attribute '__name__'
  18.  
  19. # 那么如何添加呢?首先增加到包装器的属性在WRAPPER_ASSIGNMENTS中定义,另外WRAPPER_UPDATES列出了要修改的值
  20. print("assign:", functools.WRAPPER_ASSIGNMENTS) # assign: ('__module__', '__name__', '__qualname__', '__doc__', '__annotations__')
  21. print("update:", functools.WRAPPER_UPDATES) # update: ('__dict__',)
  22.  
  23. # 添加,表示从原函数将属性赋值或增加到partial对象
  24. functools.update_wrapper(p, foo)
  25. print(p.__name__) # foo

  

  1. from functools import partial
  2.  
  3. '''
  4. 可以把partial看成是一个简单的装饰器,装饰器不仅可以装饰函数,还可以装饰类,只要是callable对象,说白了只要是能加上()的都可以
  5. 这就是Python的魅力,非常的动态。比如列表进行extend, 其实不仅仅可以extend一个列表,还可以是元组,甚至是字典,只要是iterable对象都可以。
  6. '''
  7.  
  8. class A:
  9. def __init__(self, name, age, gender):
  10. self.name = name
  11. self.age = age
  12. self.gender = gender
  13.  
  14. def print_info(self):
  15. print(f"name: {self.name}, age: {self.age}, gender: {self.gender}")
  16.  
  17. p = partial(A, "mashiro", 16)
  18. a = p("female") # 这两步等价于 a = A("mashiro", 16, "female")
  19. a.print_info() # name: mashiro, age: 16, gender: female

  

  1. from functools import partial, partialmethod
  2.  
  3. '''
  4. partial返回一个可以直接使用的callable,partialmethod返回的callable则可以用做对象的非绑定方法
  5. '''
  6.  
  7. # 举个例子
  8. def standalone(self):
  9. print(f"self = {self}")
  10.  
  11. class A:
  12. method1 = partial(standalone)
  13. method2 = partialmethod(standalone)
  14.  
  15. a = A()
  16. try:
  17. a.method1()
  18. except TypeError as e:
  19. # 由于standalone需要一个参数self,我们这里没有传,因此报错
  20. print(e) # standalone() missing 1 required positional argument: 'self'
  21.  
  22. # 但是我们调用method2呢?
  23. a.method2() # self = <__main__.A object at 0x0000000002964588>
  24. '''
  25. 得到了一个A的实例对象。
  26. 所以,partial在哪里调用时没有区别的,必须手动显示地传递,该是几个就是几个。
  27. 但是在类中如果使用partialmethod定义的话,那么在使用实例(a)调用的话,会自动将实例传进去。
  28. '''

  

  1. from functools import wraps
  2.  
  3. '''
  4. 我们在知道在使用装饰器装饰完函数的时候,属性会变。比如:
  5. '''
  6.  
  7. def deco(func):
  8. def inner(*args, **kwargs):
  9. return func(*args, **kwargs)
  10. return inner
  11.  
  12. @deco
  13. def foo():
  14. pass
  15.  
  16. # 函数从下到下执行,加上@deco等价于,foo = deco(foo) = inner,也就是说此时的foo不再是foo了,已经是inner了
  17. print(foo.__name__) # inner
  18. # 那么如何在装饰的时候,还保证原来函数的信息呢
  19.  
  20. def deco(func):
  21. @wraps(func) # 只需要加上这一个装饰器即可,会自动对所修饰的函数应用update_wrapper
  22. def inner(*args, **kwargs):
  23. return func(*args, **kwargs)
  24. return inner
  25.  
  26. @deco
  27. def bar():
  28. pass
  29.  
  30. # 可以看到原来函数的信息并没有改变
  31. print(bar.__name__) # bar

  

2.比较

  1. import functools
  2.  
  3. '''
  4. 在Python2中,类可以一个__cmp__()方法,它会根据这个对象小于、等于、或者大于所比较的元素而分别返回-1、0、1.
  5. Python2.1中引入了富比较(rich comparision)的方法。
  6. 如:__lt__(),__gt__(),__le__(),__eq__(),__ne__(),__gt__()和__ge__(),可以完成一个比较操作并返回一个bool值。
  7. Python3已经废弃了__cmp__()方法。
  8. 另外,functools提供了一些工具,从而能更容易地编写符合新要求的类,即符合Python3中新的比较需求。
  9. '''
  10.  
  11. @functools.total_ordering
  12. class A:
  13. def __init__(self, val):
  14. self.val = val
  15.  
  16. def __eq__(self, other):
  17. return self.val == other.val
  18.  
  19. def __gt__(self, other):
  20. return self.val > other.val
  21.  
  22. a1 = A(1)
  23. a2 = A(2)
  24. print(a1 < a2)
  25.  
  26. '''
  27. 这个类必须提供__eq__()和另外一个富比较方法的实现,这个修饰符会自动增加其余的方法。
  28. '''

  

  1. import functools
  2.  
  3. '''
  4. 由于Python3废弃了老式的比较函数,sort()之类的函数中也不再支持cmp参数。
  5. 对于使用了比较函数的较老的程序,可以使用cmp_to_key()将比较函数转换为一个比对键的函数,这个键用于确定元素在最终序列中的位置
  6. '''
  7.  
  8. def compare_obj(a, b):
  9. if a < b:
  10. return -1
  11. elif a > b:
  12. return 1
  13. else:
  14. return 0
  15.  
  16. l = [1, 5, 2, 11, 2, 44, 54, 5, 1]
  17.  
  18. print(sorted(l, key=functools.cmp_to_key(compare_obj))) # [1, 1, 2, 2, 5, 5, 11, 44, 54]

  

3.缓存

  1. import functools
  2.  
  3. '''
  4. lru_cache()修饰符将一个函数包装在一个"最近最少使用的"缓存中。函数的参数用来建立一个散列键,然后映射到这个结果。
  5. 后续调用如果有相同的参数,就会从这个缓存中获取值而不会再次调用这个函数。
  6. 这个修饰符还会为函数增加方法来检查缓存的状态(cache_info)和清空缓存(cache_clear)
  7. '''
  8.  
  9. @functools.lru_cache() # 里面可以执行参数maxsize,默认是128
  10. def foo(a, b):
  11. print(f"foo({a} * {b})")
  12. return a * b
  13.  
  14. print("第一次调用")
  15. for i in range(2):
  16. for j in range(2):
  17. foo(i, j)
  18. print(foo.cache_info())
  19.  
  20. print("\n第二次调用")
  21. for i in range(3):
  22. for j in range(3):
  23. foo(i, j)
  24. print(foo.cache_info())
  25.  
  26. print("清除缓存")
  27. foo.cache_clear()
  28. print(foo.cache_info())
  29.  
  30. print("\n第三次调用")
  31. for i in range(2):
  32. for j in range(2):
  33. foo(i, j)
  34. print(foo.cache_info())
  35. '''
  36. 第一次调用
  37. foo(0 * 0)
  38. foo(0 * 1)
  39. foo(1 * 0)
  40. foo(1 * 1)
  41. CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)
  42.  
  43. 第二次调用
  44. foo(0 * 2)
  45. foo(1 * 2)
  46. foo(2 * 0)
  47. foo(2 * 1)
  48. foo(2 * 2)
  49. CacheInfo(hits=4, misses=9, maxsize=128, currsize=9)
  50. 清除缓存
  51. CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)
  52.  
  53. 第三次调用
  54. foo(0 * 0)
  55. foo(0 * 1)
  56. foo(1 * 0)
  57. foo(1 * 1)
  58. CacheInfo(hits=0, misses=4, maxsize=128, currsize=4)
  59. '''
  60. # 我们观察一下第二次调用,3 * 3应该是9次,为什么只有5次,因为第一次调用有4次执行过了,放到缓存里,因此不需要执行了

  

4.reduce

  1. import functools
  2.  
  3. '''
  4. reduce这个函数无需介绍,在Python2中是内置的,但是在Python3中被移到functools下面
  5. '''
  6. l = range(100)
  7. print(functools.reduce(lambda x, y: x+y, l)) # 4950
  8. print(functools.reduce(lambda x, y: x+y, l, 10)) # 4960
  9. print(functools.reduce(lambda x, y: x+y, l, 100)) # 5050
  10.  
  11. l = [1, 2, 3, 4, 5]
  12. print(functools.reduce(lambda x, y: x*y, l)) # 120

  

5.泛型函数

  1. import functools
  2.  
  3. '''
  4. 在类似Python的动态类型语言中,通常需要基于参数的类型完成稍有不同的操作,特别是在处理元素列表与单个元素的差别时。
  5. 直接检查参数的类型固然很简单,但是有些情况下,行为差异可能被隔离到单个的函数中。
  6. 对于这些情况,functools提供了singledispatch修饰符来注册一组泛型函数,可以根据函数第一个参数的类型自动切换
  7. '''
  8.  
  9. @functools.singledispatch
  10. def myfunc(arg):
  11. print(f"default myfunc {arg}")
  12.  
  13. @myfunc.register(int)
  14. def myfunc1(arg):
  15. print(f"myfunc1 {arg}")
  16.  
  17. @myfunc.register(list)
  18. def myfunc2(arg):
  19. print(f"myfunc2 {arg}")
  20.  
  21. myfunc("string") # default myfunc string
  22. myfunc(123) # myfunc1 123
  23. myfunc(["1", "2"]) # myfunc2 ['1', '2']
  24. '''
  25. 可以看到使用signledispatch包装的是默认实现,在未指定其他类型特定函数的时候就用这个默认实现。
  26. 然后使用包装的函数这里是myfunc,通过register(数据类型)进行注册,根据所传参数的类型,从而执行对应的函数
  27. '''

  

(二)itertools:迭代器函数

1.合并和分解迭代器

  1. import itertools
  2.  
  3. '''
  4. chain函数可以接收多个可迭代对象(或者迭代器)作为参数,最后返回一个迭代器。
  5. 它会生成所有输入迭代器的内容,就好像这些内容来自一个迭代器一样。
  6. 类似于collections下的ChainMap,可以合并多个字典。chain可以合并多个可迭代对象
  7. '''
  8.  
  9. c = itertools.chain([1, 2, 3], "abc", {"k1": "v1", "k2": "v2"})
  10. print(c) # <itertools.chain object at 0x00000000029745F8>
  11. for i in c:
  12. print(i, end=" ") # 1 2 3 a b c k1 k2
  13.  
  14. print()
  15. # 还可以使用chain.from_iterable,参数接收多个可迭代对象组成的一个可迭代对象
  16. c = itertools.chain.from_iterable([[1, 2, 3], "abc", {"k1": "v1", "k2": "v2"}])
  17. for i in c:
  18. print(i, end=" ") # 1 2 3 a b c k1 k2
  19.  
  20. # 函数zip则是把多个迭代器对象组合到一个元组中
  21. name = ["古明地觉", "椎名真白", "雪之下雪乃"]
  22. where = ["东方地灵殿", "樱花张的宠物女孩", "春物"]
  23. z = zip(name, where)
  24. print("\n", z) # <zip object at 0x0000000001DC03C8>
  25. print(list(z)) # [('古明地觉', '东方地灵殿'), ('椎名真白', '樱花张的宠物女孩'), ('雪之下雪乃', '春物')]
  26.  
  27. # zip英文意思是拉链,很形象,就是把对应元素给组合起来
  28. # 但如果两者长度不一致怎么办?
  29. name = ["古明地觉", "椎名真白", "雪之下雪乃", "xxx"]
  30. where = ["东方地灵殿", "樱花张的宠物女孩", "春物"]
  31. print(list(zip(name, where))) # [('古明地觉', '东方地灵殿'), ('椎名真白', '樱花张的宠物女孩'), ('雪之下雪乃', '春物')]
  32. # 可以看到,不一致的时候,当一方结束之后就停止匹配。
  33.  
  34. # 如果想匹配长的,那么可以使用zip_longest,这个函数不像zip一样是内置的,它在itertools下面
  35. print(list(itertools.zip_longest(name, where))) # [('古明地觉', '东方地灵殿'), ('椎名真白', '樱花张的宠物女孩'), ('雪之下雪乃', '春物'), ('xxx', None)]
  36. # 可以看到没有的默认赋值为None了,当然我们也可以指定填充字符
  37. print(list(itertools.zip_longest(name, where, fillvalue="你输入的是啥啊")))
  38. # [('古明地觉', '东方地灵殿'), ('椎名真白', '樱花张的宠物女孩'), ('雪之下雪乃', '春物'), ('xxx', '你输入的是啥啊')]
  39.  
  40. # isslice返回一个迭代器,按照索引从迭代器返回所选择的元素
  41. num = range(20)
  42. # 从index=5的地方选到index=10(不包含)的地方
  43. s = itertools.islice(num, 5, 10)
  44. print(list(s)) # [5, 6, 7, 8, 9]
  45. # 从开头选到index=5的地方
  46. s = itertools.islice(num, 5)
  47. print(list(s)) # [0, 1, 2, 3, 4]
  48. # 从index=5的地方选择到index=15的地方,步长为3
  49. s = itertools.islice(num, 5, 15, 3)
  50. print(list(s)) # [5, 8, 11, 14]
  51. '''
  52. 所以除了迭代器之外,
  53. 如果只传一个参数,比如5,表示从index=0选到index=5(不包含)的地方
  54. 如果传两个参数,比如5和10,表示从index=5选到index=10(不包含)的地方
  55. 如果传三个参数,比如5和10和2,表示从index=5选到index=10(不包含)的地方,步长为2
  56. '''
  57. # 那么支不支持负数索引呢?答案是不支持的,因为不知道迭代器有多长,除非全部读取,可是那样的话干嘛不直接转化为列表之后再用[:]这种形式呢?
  58. # 之所以使用isslice这种形式,就是为了在不全部读取的情况下,也能选择出我们想要的部分,所以这种方式只支持从前往后,不能从后往前读。
  59.  
  60. # tee()函数根据一个原输入迭代器返回多个独立、和原迭代器一模一样的迭代器(默认为两个)
  61. r = [1, 2, 3, 4, 5]
  62. i1, i2 = itertools.tee(r)
  63. print(list(i1)) # [1, 2, 3, 4, 5]
  64. print(list(i2)) # [1, 2, 3, 4, 5]

  

2.转换输入

  1. import itertools
  2.  
  3. '''
  4. 内置的map()函数返回一个迭代器,它对输入迭代器中的值调用一个函数并返回结果。
  5. 输入迭代中的元素全部被消费时,map()函数就会停止
  6. '''
  7. l = [1, 2, 3]
  8. map_l = map(lambda x: str(x)+"a", l)
  9. print(list(map_l)) # ['1a', '2a', '3a']
  10.  
  11. l1 = [(0, 5), (1, 6), (2, 7)]
  12. '''
  13. 注意map里面的函数只能有一个参数,因此不可以写成以下格式
  14. map_l1 = map(lambda x, y: x*y, l1)
  15. 但是可以这样
  16. '''
  17. map_l1 = map(lambda x: x[0]*x[1], l1)
  18. print(list(map_l1)) # [0, 6, 14]
  19.  
  20. # 但是itertools下的startmap()是支持的
  21. l2 = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
  22. # 注意里面的函数的参数的参数个数是由我们后面传入对象决定的,这里每个元组显然有三个元素,所以需要三个参数
  23. map_l1 = itertools.starmap(lambda x, y, z: f"{x} + {y} + {z} = {x+y+z}", l2)
  24. print(list(map_l1)) # ['1 + 2 + 3 = 6', '4 + 5 + 6 = 15', '7 + 8 + 9 = 24']
  25. # map的话只能通过lambda x: x[0], x[1], x[2]这样的形式
  26. # starmap只能对类似于[(), (), ()]这种值进行处理,比如[1, 2, 3]使用starmap是会报错的,但是[(1, ), (2, ), (3, )]不会报错

  

3.生成新值

  1. import itertools
  2.  
  3. '''
  4. count(start=0, step=1)函数返回一个迭代器,该迭代器能够无限地生成连续的整数。
  5. 接收两个参数:起始(默认为0)和步长(默认为1)
  6. 等价于:
  7. def count(firstval=0, step=1):
  8. x = firstval
  9. while 1:
  10. yield x
  11. x += step
  12. '''
  13.  
  14. '''
  15. cycle(iterable)返回一个迭代器,会无限重复里面的内容,直到内存耗尽
  16. '''
  17. c2 = itertools.cycle("abc")
  18. print(list(itertools.islice(c2, 0, 10))) # ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c', 'a']
  19.  
  20. '''
  21. repeat(obj, times=None),无限重复obj,除非指定times。
  22. '''
  23. print(list(itertools.repeat("abc", 3))) # ['abc', 'abc', 'abc']

  

4.过滤

  1. import itertools
  2.  
  3. l = [1, 2, 3, 4, 5]
  4. drop_l = itertools.dropwhile(lambda x: x < 3, l)
  5. print(list(drop_l)) # [3, 4, 5]
  6. take_l = itertools.takewhile(lambda x: x < 3, l)
  7. print(list(take_l)) # [1, 2]
  8. filter_l = filter(lambda x: x < 3, l)
  9. print(list(filter_l)) # [1, 2]
  10. filterfalse_l = itertools.filterfalse(lambda x: x < 3, l)
  11. print(list(filterfalse_l)) # [3, 4, 5]
  12. '''
  13. filter和takewhile一样,过滤出条件为True的值
  14. filterfalse和dropwhile一样,过滤出条件为False的值
  15. '''
  16.  
  17. # compress则提供了另一种过滤可迭代对象内容的方法。
  18. # 举个栗子
  19. condition = [True, False, True, True, False]
  20. data = [1, 2, 3, 4, 5]
  21. print(list(itertools.compress(data, condition))) # [1, 3, 4]
  22. # 或者
  23. condition = [1, 0, "x", "x", {}]
  24. print(list(itertools.compress(data, condition))) # [1, 3, 4]

  

5.合并输入

  1. import itertools
  2.  
  3. '''
  4. accumulate函数处理输入迭代器,得到一个类似于斐波那契的结果
  5. '''
  6. print(list(itertools.accumulate(range(5)))) # [0, 1, 3, 6, 10]
  7. print(list(itertools.accumulate("abcde"))) # ["a", "ab", "abc", "abcd", "abcde"]
  8. # 所以这里的相加还要看具体的含义
  9.  
  10. try:
  11. print(list(itertools.accumulate([[1, 2], (3, 4)])))
  12. except TypeError as e:
  13. print(e) # can only concatenate list (not "tuple") to list
  14. # 这里就显示无法将列表和元组相加
  15.  
  16. # 当然也可以自定义
  17. data = [1, 2, 3, 4, 5]
  18. method = lambda x, y: x*y
  19. print(list(itertools.accumulate(data, method))) # [1, 2, 6, 24, 120]
  20. # 可以看到这里的结果就改变了
  21.  
  22. '''
  23. product则是会将多个可迭代对象组合成一个笛卡尔积
  24. '''
  25. print(list(itertools.product([1, 2, 3], [2, 3]))) # [(1, 2), (1, 3), (2, 2), (2, 3), (3, 2), (3, 3)]
  26.  
  27. '''
  28. permutations函数从输入迭代器生成元素,这些元素以给定长度的排列形成组合。默认会生成所以排列的全集
  29. '''
  30. data = [1, 2, 3, 4]
  31. print(list(itertools.permutations(data)))
  32. '''
  33. [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2),
  34. (2, 1, 3, 4), (2, 1, 4, 3), (2, 3, 1, 4), (2, 3, 4, 1), (2, 4, 1, 3), (2, 4, 3, 1),
  35. (3, 1, 2, 4), (3, 1, 4, 2), (3, 2, 1, 4), (3, 2, 4, 1), (3, 4, 1, 2), (3, 4, 2, 1),
  36. (4, 1, 2, 3), (4, 1, 3, 2), (4, 2, 1, 3), (4, 2, 3, 1), (4, 3, 1, 2), (4, 3, 2, 1)]
  37. '''
  38.  
  39. print(list(itertools.permutations(data, 2)))
  40. # [(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]
  41.  
  42. # permutations只要顺序不同就看做一种结果,combinations则保证只要元素相同就是同一种结果
  43. data = "abcd"
  44. print(list(itertools.combinations(data, 3))) # [('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'd'), ('b', 'c', 'd')]
  45. # 尽管combinations不会重复单个的输入元素,但是有时候可能也需要考虑包含重复元素的组合。
  46. # 对于这种情况,可以使用combination_with_replacement
  47. print(list(itertools.combinations_with_replacement(data, 3)))
  48. '''
  49. [('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'a', 'd'), ('a', 'b', 'b'),
  50. ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'c'), ('a', 'c', 'd'), ('a', 'd', 'd'),
  51. ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'b', 'd'), ('b', 'c', 'c'), ('b', 'c', 'd'),
  52. ('b', 'd', 'd'), ('c', 'c', 'c'), ('c', 'c', 'd'), ('c', 'd', 'd'), ('d', 'd', 'd')]
  53. '''

  

(三)operator:内置操作符的函数接口

  1. import operator
  2.  
  3. '''
  4. 使用迭代器编程时,有时需要为简单的表达式创建小函数。
  5. operator模块提供了一些函数,可以对应标准API中内置的算术、比较和其他操作。
  6. 注意:operator中提供的操作,都可以通过lambda函数实现,就我个人而言更喜欢lambda函数
  7. '''

  

1.逻辑操作

  1. import operator
  2.  
  3. '''
  4. 有些函数可以用来确定一个值得相应布尔值,将其取反以创建相反的布尔值,以及比较对象以查看它们是否相等
  5. '''
  6. a = -1 # 为真
  7. b = 5 # 为真
  8.  
  9. # not为关键字,所以是not_,判断值是否为假。由于a=-1为真,不为假,所以是False
  10. print(operator.not_(a)) # False
  11. # truth,判断值是否为真
  12. print(operator.truth(b)) # True
  13. # is_, 等价于a is b
  14. print(operator.is_(a, b)) # False
  15. # is_not,等价于a is not b
  16. print(operator.is_not(a, b)) # True

  

2.比较操作符

  1. import operator
  2.  
  3. '''
  4. 支持所有的富比较操作符
  5. '''
  6. a = -1
  7. b = 5
  8. for func in ("lt", "le", "gt", "ge", "eq", "ne"): # <, <=, >, >=, ==, !=
  9. print(f"{func}(a, b): {getattr(operator, func)(a, b)}")
  10. '''
  11. lt(a, b): True
  12. le(a, b): True
  13. gt(a, b): False
  14. ge(a, b): False
  15. eq(a, b): False
  16. ne(a, b): True
  17. '''

  

3.算术操作符

  1. import operator
  2.  
  3. '''
  4. 支持处理数字值的算术操作符
  5. '''
  6. a = -1
  7. b = 5.0
  8. c = 2
  9. d = 6
  10.  
  11. print("abs(a): ", operator.abs(a))
  12. print("neg(a): ", operator.neg(a))
  13. print("neg(b): ", operator.neg(b))
  14. print("pos(a): ", operator.pos(a))
  15. print("pos(b): ", operator.pos(b))
  16. print("add(a, b): ", operator.add(a, b))
  17. print("floordiv(a, b): ", operator.floordiv(a, b))
  18. print("floordiv(a, c): ", operator.floordiv(a, c))
  19. print("mod(a, b): ", operator.mod(a, b))
  20. print("mul(a, b): ", operator.mul(a, b))
  21. print("pow(c, d): ", operator.pow(c, d))
  22. print("sub(b, a): ", operator.sub(b, a))
  23. print("truediv(a, b): ", operator.truediv(a, b))
  24. print("truediv(d, c): ", operator.truediv(d, c))
  25. print("and_(c, d): ", operator.and_(c, d))
  26. print("invert(c): ", operator.invert(c))
  27. print("lshift(c, d): ", operator.lshift(c, d))
  28. print("or_(c, d): ", operator.or_(c, d))
  29. print("rshift(d, c): ", operator.rshift(d, c))
  30. print("xor(c, d): ", operator.xor(c, d))
  31.  
  32. '''
  33. a = -1
  34. b = 5.0
  35. c = 2
  36. d = 6
  37.  
  38. abs(a): 1
  39. neg(a): 1
  40. neg(b): -5.0
  41. pos(a): -1
  42. pos(b): 5.0
  43. add(a, b): 4.0
  44. floordiv(a, b): -1.0
  45. floordiv(a, c): -1
  46. mod(a, b): 4.0
  47. mul(a, b): -5.0
  48. pow(c, d): 64
  49. sub(b, a): 6.0
  50. truediv(a, b): -0.2
  51. truediv(d, c): 3.0
  52. and_(c, d): 2
  53. invert(c): -3
  54. lshift(c, d): 128
  55. or_(c, d): 6
  56. rshift(d, c): 1
  57. xor(c, d): 4
  58. '''

  

4.序列操作符

  1. import operator
  2.  
  3. '''
  4. 处理序列的操作符可以分为四组:建立序列,搜索元素,访问内容,以及从序列删除元素
  5. '''
  6. a = [1, 2, 3]
  7. b = ['a', 'b', 'c']
  8. print("a =", a)
  9. print("b =", b)
  10. print("concat(a, b): ", operator.concat(a, b))
  11. print("contains(a, 1): ", operator.contains(a, 1))
  12. print("contains(b, 'd'): ", operator.contains(b, 'd'))
  13. print("countOf(a, 1): ", operator.countOf(a, 1))
  14. print("countOf(b, 'd'): ", operator.countOf(b, 'd'))
  15. print("indexOf(a, 5): ", operator.indexOf(a, 1))
  16. print("getitem(b, 1): ", operator.getitem(b, 1))
  17. print("getitem(b slice(1, 3): ", operator.getitem(b, slice(1, 3)))
  18. print("setitem(b, 1, 'd'): ", end=' ')
  19. operator.setitem(b, 1, 'd')
  20. print(b)
  21. print("setitem(a, slice(1, 3), [4, 5]): ", end=' ')
  22. operator.setitem(a, slice(1, 3), [4, 5])
  23. print(a)
  24.  
  25. print("delitem(b, 1)", end=' ')
  26. operator.delitem(b, 1)
  27. print(b)
  28. print("delitem(a, slice(1, 3): ", end=' ')
  29. operator.delitem(b, slice(1, 3))
  30. print(a)
  31. # 其中的一些操作(setitem()和delitem())会原地修改序列,返回的是None
  32. '''
  33. a = [1, 2, 3]
  34. b = ['a', 'b', 'c']
  35. concat(a, b): [1, 2, 3, 'a', 'b', 'c']
  36. contains(a, 1): True
  37. contains(b, 'd'): False
  38. countOf(a, 1): 1
  39. countOf(b, 'd'): 0
  40. indexOf(a, 5): 0
  41. getitem(b, 1): b
  42. getitem(b slice(1, 3): ['b', 'c']
  43. setitem(b, 1, 'd'): ['a', 'd', 'c']
  44. setitem(a, slice(1, 3), [4, 5]): [1, 4, 5]
  45. delitem(b, 1) ['a', 'c']
  46. delitem(a, slice(1, 3): [1, 4, 5]
  47. '''
  48.  
  49. # 个人觉得这些都没有什么乱用,可以直接实现的,没必要使用这个库

  

5.原地操作符

6.排序

  1. import operator
  2.  
  3. '''
  4. 这一节书上没有,是我自己加的。个人觉得这个库只有在这一方面会有用。
  5. '''
  6. l = [
  7. [1, 3],
  8. [7, 4],
  9. [6, 2],
  10. [3, 5]
  11. ]
  12. # 现在我要将这个列表进行排序,怎么排呢?里面里面列表的第一个元素的顺序从小到大排
  13. # 也就是说,排完序之后应该是这样的, [[1, 3], [3, 5], [6, 2], [7, 4]]
  14. l.sort(key=operator.itemgetter(0))
  15. # 按照key来排序,itemgetter(0),表示获取各自索引为0的元素,进行比较
  16. print(l) # [[1, 3], [3, 5], [6, 2], [7, 4]]
  17.  
  18. # 但是我们可以使用lambda函数来实现,而且还可以实现更加复杂的效果
  19. l1 = [
  20. [1, 3],
  21. [7, 4],
  22. [6, 2],
  23. [3, 5]
  24. ]
  25. l1.sort(key=lambda x: x[0])
  26. print(l1) # [[1, 3], [3, 5], [6, 2], [7, 4]]
  27.  
  28. l2 = [-3, -5, 3, -9, 8, 2]
  29. # 对l2我想这样排序,首先按照正负数排序,负数排左边,正数排右边。
  30. # 然后按照绝对值得大小排, 绝对值大的排左边,小的排右边
  31. # 也就是说排完之后应该是这样的,[-9, -5, -3, 8, 3, 2]
  32. l2.sort(key=lambda x: (x > 0, ~abs(x)))
  33. print(l2) # [-9, -5, -3, 8, 3, 2]
  34. # 因此可以看到这个x代表的就是序列里面的元素
  35. # 如果是字典的话,那么x就是字典里面的key
  36.  
  37. d = {"a": 4, "c": 3, "b": 2}
  38. # 可是字典没有sort,我们如何验证呢?
  39. import heapq
  40. # 按照value选择两个最大的
  41. # 参数:选择几个,从哪里选择,按照什么规则去选择
  42. print(heapq.nlargest(2, d, key=lambda x: d[x])) # ['a', 'c']
  43.  
  44. '''
  45. 个人总结一下哈,我个人觉得这个库是真的没有什么用,完全可以使用其他的方法代替,而且更容易理解。
  46. 当然也可能是我能力不够,这个库的更高级的用法我没有看到(雾)
  47. '''

  

(四)contextlib:上下文管理器工具

  1. import contextlib
  2.  
  3. '''
  4. contextlib模块包含的工具用于处理上下文管理器和with语句
  5. '''

1.上下文管理器API

  1. import contextlib
  2.  
  3. '''
  4. 上下文管理器(context manager)负责管理一个代码块中的资源,会在进入代码块时创建资源,然后再退出代码后清理这个资源。
  5. 比如:文件就支持上下文管理器API,可以确保文件读写后关闭文件。
  6. with open("xxx") as f:
  7. f.read()
  8. '''
  9.  
  10. # 那么这是如何实现的呢?我们可以手动模拟一下
  11. class Open:
  12.  
  13. def __init__(self, filename, mode='r', encoding=None):
  14. self.filename = filename
  15. self.mode = mode
  16. self.encoding = encoding
  17.  
  18. def __enter__(self):
  19. print("__enter__,有了这个就可以使用with Open() as xx语句,这里的xx就是我return的内容")
  20. return self
  21.  
  22. def read(self):
  23. print(f"文件进行读操作,读取文件:{self.filename}, 模式:{self.mode}, 编码:{self.encoding}")
  24.  
  25. def __exit__(self, exc_type, exc_val, exc_tb):
  26. print("__exit__,我是用来清理资源的,当操作执行完毕之后就会执行我,比如:关闭文件")
  27.  
  28. with Open("1.xxx") as f:
  29. f.read()
  30. '''
  31. __enter__,有了这个就可以使用with Open() as xx语句,这里的xx就是我return的内容
  32. 文件进行读操作,读取文件:1.xxx, 模式:r, 编码:None
  33. __exit__,我是用来清理资源的,当操作执行完毕之后就会执行我,比如:关闭文件
  34. '''

  

  1. import contextlib
  2.  
  3. # 相较于try:finally语法,结合上下文管理器和with语句是一种更加紧凑的写法,因为__exit__这个方法总是会被调用的,即使产生了异常
  4.  
  5. class Open:
  6.  
  7. def __init__(self, filename, mode='r', encoding=None):
  8. self.filename = filename
  9. self.mode = mode
  10. self.encoding = encoding
  11.  
  12. def __enter__(self):
  13. return 123
  14.  
  15. def __exit__(self, exc_type, exc_val, exc_tb):
  16. # 注意到这里有三个参数,使用pycharm的时候,会很智能地自动帮我们加上去
  17. print(exc_type)
  18. print(exc_val)
  19. print(exc_tb)
  20. return True
  21.  
  22. with Open("1.xx") as f:
  23. print(f)
  24. '''
  25. 123
  26. None
  27. None
  28. None
  29. '''
  30.  
  31. with Open("1.xx") as f:
  32. print(f)
  33. 1 / 0
  34. print(123)
  35. print(456)
  36. print(789)
  37. print("你猜我会被执行吗?")
  38. '''
  39. 123
  40. <class 'ZeroDivisionError'>
  41. division by zero
  42. <traceback object at 0x0000000009EDD848>
  43. 你猜我会被执行吗?
  44. '''
  45.  
  46. '''
  47. 可以看到当我们程序没有出错的时候,打印的值全为None。一旦with语句里面出现了异常,那么会立即执行__exit__函数。
  48. 里面的参数就是:异常的类型,异常的值,异常的信息栈。
  49. 因此:当with语句结束之后会调用__exit__函数,如果with语句里面出现了错误则会立即调用__exit__函数。
  50. 但是__exit__函数返回了个True是什么意思呢?
  51. 当with语句里面出现了异常,理论上是会报错的,但是由于要执行__exit__函数,所以相当于暂时把异常塞进了嘴里。
  52. 如果__exit__函数最后返回了一个布尔类型为True的值,那么会把塞进嘴里的异常吞下去,程序不报错正常执行。如果返回布尔类型为False的值,会在执行完__exit__函数之后再把异常吐出来,引发程序崩溃。
  53. 这里我们返回了True,因此程序正常执行,最后一句话被打印了出来。
  54. 但是1/0这句代码后面的几个print却没有打印,为什么呢?
  55. 因为上下文管理执行是有顺序的,
  56. with Open("1.xxx") as f:
  57. code1
  58. code2
  59. 先执行Open函数的__init__函数,再执行__enter__函数,把其返回值给交给f,然后执行with语句里面的代码,最后执行__exit__函数。
  60. 只要__exit__函数执行结束,那么这个with语句就算结束了。
  61. 而with语句里面如果有异常会立即进入__exit__函数,因此异常语句后面的代码是无论如何都不会被执行的。
  62. '''

  

2.上下文管理器作为函数修饰符

  1. import contextlib
  2.  
  3. '''
  4. 类ContextDecorator增加了对常规上下文管理器类的支持,因此不仅可以作为上下文管理器,也可以作为函数修饰符
  5. '''
  6.  
  7. class Context(contextlib.ContextDecorator):
  8. def __init__(self, how_used):
  9. self.how_used = how_used
  10. print(f"__init__({self.how_used})")
  11.  
  12. def __enter__(self):
  13. print(f"__enter__({self.how_used})")
  14. return self
  15.  
  16. def __exit__(self, exc_type, exc_val, exc_tb):
  17. print(f"__exit__({self.how_used})")
  18.  
  19. # 一旦继承了ContextDecorator这个类,那么便可以作为装饰器去装饰。
  20. # 说白了Context("as decorator")返回了Context的一个实例对象,理论上是不可调用的,但是父类实现了call方法。
  21. # 因此如果我们自己实现了一个定义了__call__方法的类,让Context去继承,也是可以达到类似的效果
  22. @Context("as decorator")
  23. def func(message):
  24. print(message)
  25. '''
  26. __init__(as decorator)
  27. '''
  28.  
  29. # 当我执行执行func的时候,此时的func已经不再是原来的那个func了
  30. # func = self(func),从而调用Context的__call__方法,可是Context没有这个方法,那么它的父类肯定有。
  31. # 我们看看contextlib.ContextDecorator的源码,去掉了注释
  32. '''
  33. class ContextDecorator(object):
  34.  
  35. def _recreate_cm(self):
  36. return self
  37.  
  38. def __call__(self, func):
  39. @wraps(func)
  40. def inner(*args, **kwds):
  41. with self._recreate_cm():
  42. return func(*args, **kwds)
  43. return inner
  44.  
  45. 可以看到首先@Context("as decorator")会执行Context的__init__方法,打印__init__(as decorator),得到实例对象self
  46. 此时等价于@self, -->func = self(func),执行__call__方法,-->func = inner
  47. 当执行inner的时候,会先调用__enter__方法,然后执行inner,最后执行__exit__方法
  48. '''
  49.  
  50. func("doing work i the wrapped function")
  51.  
  52. # 这个无需解释
  53. with Context("as contetx manager"):
  54. print("doing work in the context")
  55. '''
  56. __init__(as contetx manager)
  57. __enter__(as contetx manager)
  58. doing work in the context
  59. __exit__(as contetx manager)
  60. '''

  

3.从生成器到上下文管理器

  1. import contextlib
  2.  
  3. '''
  4. 采用传统方式创建上下文管理器并不难,只需要包含一个__enter__方法和一个__exit__方法的类即可。
  5. 不过某些时候,如果只有很少的上下文需要管理,那么完整地写出所以代码便会成为额外的负担。
  6. 在这些情况下,可以使用contextmanager修饰符将一个生成器函数转换为上下文管理器。
  7. 代码结构:
  8. @contextlib.contextmanager
  9. def foo():
  10. print(123)
  11. yield 456
  12. print(789)
  13.  
  14. with foo() as f:
  15. print(f)
  16.  
  17. 123
  18. 456
  19. 789
  20.  
  21. 只要给函数加上这个装饰器,那么便可以使用with as 语句。
  22. 当中的yield相当于将代码块分隔为两个战场,yield上面的代码相当于__exter__会先执行,然后将yield的值交给f,然后执行yield下面的代码块
  23. '''
  24.  
  25. @contextlib.contextmanager
  26. def bar(name, age):
  27. print(f"name is {name}, age is {age}")
  28. yield list
  29. print("我是一匹狼,却变成了狗")
  30.  
  31. with bar("mashiro", 16) as b:
  32. print(b("abcde"))
  33. '''
  34. name is mashiro, age is 16
  35. ['a', 'b', 'c', 'd', 'e']
  36. 我是一匹狼,却变成了狗
  37. '''
  38. # 先执行yield上面的内容,然后yield list,那么b = list,最后执行yield下面的内容
  39.  
  40. # contextmanager返回的上下文管理器排成子ContextDecorator,所以也可以被用作函数修饰符
  41. @bar("satori", 16)
  42. def foo():
  43. print("猜猜我会在什么地方输出")
  44.  
  45. foo()
  46. '''
  47. name is satori, age is 16
  48. 猜猜我会在什么地方输出
  49. 我是一匹狼,却变成了狗
  50. '''
  51. # bar中含有yield,肯定是一个生成器,所以直接@bar("satori", 16)是不会输出的。当我执行foo的时候,还会先执行bar里面yield上面的内容,
  52. # 然后执行foo代码的内容,最后执行yield下面的内容

  

4.关闭打开的句柄

  1. import contextlib
  2.  
  3. '''
  4. file类直接支持上下文管理器API,但另外一些表示打开句柄的对象却并不支持。
  5. 为了确保关闭句柄,要是用closing为它创建一个上下文管理器
  6. '''
  7.  
  8. class Door:
  9. def __init__(self):
  10. print("__init__()")
  11. self.status = "open"
  12.  
  13. def close(self):
  14. print("close()")
  15. self.status = "closed"
  16.  
  17. with contextlib.closing(Door()) as door:
  18. print(f"{door.status}")
  19. # 先不急看结果,先来分析一下。首先contextlib.closing本身就是一个上下文管理器
  20. '''
  21. class closing(AbstractContextManager):
  22. def __init__(self, thing):
  23. self.thing = thing
  24. def __enter__(self):
  25. return self.thing
  26. def __exit__(self, *exc_info):
  27. self.thing.close()
  28. '''
  29. # 可以看到当我with contextlib.closing(Door()) as door的时候,直接将Door的实例对象传入了closing这个类中
  30. # 然后enter返回了self.thing也就是我们传进去的Door的实例对象,__enter__返回self.thing交给door
  31. # 然后执行我们的逻辑,最后__exit__函数再调用self.thing.close函数,所以我们定义的类中一定要实现close函数
  32.  
  33. # 执行结果
  34. '''
  35. __init__()
  36. open
  37. close()
  38. '''
  39. # 先执行__init__函数,再执行我们自己的逻辑,打印"open",最后执行close函数,将状态改为"closed"。
  40. # 怎么证明这一点呢?
  41. print(door.status) # closed
  42.  
  43. # 如果出现了异常怎么办呢?不用怕,依旧会执行close语句.
  44. # 由于contextlib.closing的__exit__函数并没有返回布尔类型为True的值,所以最后还是会抛出异常,我们手动捕获一下
  45. try:
  46. with contextlib.closing(Door()) as boy_next_door:
  47. print(123)
  48. 1/0
  49. print(456)
  50.  
  51. except Exception:
  52. pass
  53.  
  54. print(boy_next_door.status)
  55. '''
  56. __init__()
  57. 123
  58. close()
  59. closed
  60. '''
  61. # 最后还是打印了"closed",所以还是执行了close()方法

  

5.忽略异常

  1. import contextlib
  2.  
  3. '''
  4. 很多情况下,忽略库产生的异常很有用,因为这个错误可能会显示期望的状态已经被实现,否则该错误就可以被忽略。
  5. 要忽略异常,最常用的办法就是利用一个try except语句。
  6. 但是在我们此刻的主题中,try except也可以被替换成contextlib.suppress(),以更显示地抑制with块中产生的异常
  7. '''
  8. def foo():
  9. print(123)
  10. 1 / 0
  11. print(456)
  12.  
  13. with contextlib.suppress(ZeroDivisionError):
  14. foo()
  15. print(789)
  16. '''
  17. 123
  18. '''
  19. # 最终只输出了123,可以看到不仅1/0中下面的456没有被打印,连foo()下面的789也没有被打印
  20.  
  21. # 可以传入多个异常
  22. with contextlib.suppress(ZeroDivisionError, BaseException, Exception):
  23. foo()
  24. '''
  25. 123
  26. '''
  27. # 出现异常之后,会将异常全部丢弃

  

6.重定向到输出流

  1. import contextlib
  2. import io
  3. import sys
  4.  
  5. '''
  6. 设计不当的代码可能会直接写sys.stdout或sys.stderr,而没有提供参数来配置不同的输出目标。
  7. 可以用redirect_stdout和redirect_stderr上下文管理器从这些函数中捕获输出,因为无法修改这个函数的源代码来接收新的输出参数
  8. '''
  9.  
  10. def func(a):
  11. sys.stdout.write(f"stdout :{a}")
  12. sys.stderr.write(f"stderr :{a}")
  13.  
  14. capture = io.StringIO()
  15. '''
  16. 我们执行func本来是要往sys.stdout和sys.stderr里面写的
  17. 但这是在with语句contextlib.redirect_stdout(capture), contextlib.redirect_stderr(capture)下面,
  18. 因此可以理解往sys.stdout和sys.stderr里面写的内容就被捕获到了,然后会将捕获到的内容输入到capture里面,因为我们指定了capture
  19. '''
  20. with contextlib.redirect_stdout(capture), contextlib.redirect_stderr(capture):
  21. func("蛤蛤蛤蛤")
  22.  
  23. print(capture.getvalue()) # stdout :蛤蛤蛤蛤stderr :蛤蛤蛤蛤
  24.  
  25. '''
  26. redirect_stdout和redirect_stderr会修改全局状态,替换sys模块中的对象,可以想象gevent里面的patch_all会将Python里面socket,ssl等都换掉。
  27. 因此要使用这两个函数,必须要注意。这些函数并不保证线程安全,所以在多线程应用中调用这些函数可能会有不确定的结果。
  28. 如果有其他希望标准输出流关联到终端设备,那么redirect_stdout和redirect_stderr将会干扰和影响那些操作。
  29. '''

  

7.动态上下文管理器栈

  1. import contextlib
  2.  
  3. '''
  4. 大多数上下文管理器都一次处理一个对象,如单个文件或数据库句柄。
  5. 在这些情况下,对象是提前已知的,并且使用上下文管理器的代码可以建立这一对象上。
  6. 另外一些情况下,程序可能需要在一个上下文中创建未知数目的对象,控制流退出这个上下文时所有这些对象都要清理,ExitStack就是用来处理这些更动态的情况。
  7.  
  8. ExitStack实例会维护清理回调的一个栈数据结构,这些回调显示地填充在上下文中,在控制流退出上下文时会以逆序调用所有注册的回调。
  9. 结果类似于有多个嵌套的with语句,只不过它们是动态建立的。
  10. '''
  11.  
  12. # 可以使用多种方法填充ExitStack,比如
  13. @contextlib.contextmanager
  14. def make_context(i):
  15. print(f"{i}: entering")
  16. yield {}
  17. print(f"{i}: exiting")
  18.  
  19. def variable_stack(n, msg):
  20. with contextlib.ExitStack() as stack:
  21. for i in range(n):
  22. stack.enter_context(make_context(i))
  23. print(msg)
  24.  
  25. variable_stack(2, "inside stack")
  26. '''
  27. contextlib.ExitStack()相当于创建了上下文管理器栈
  28. stack.enter_context将上下文管理器放入到栈中,注意此时已经执行了
  29. 会先输出:
  30. 0: entering
  31. 1: entering
  32. 等于是把yield之后的结果压入栈中
  33. 然后执行后面的代码,所以会打印出msg
  34. 当里面的代码执行完毕之后,会继续执行栈里面的数据,但是栈是后入先出的。i=1后入栈,所以先执行
  35. 随意最后输出:
  36. 1: exiting
  37. 0: exiting
  38. '''
  39. # 输出结果
  40. ''''
  41. 0: entering
  42. 1: entering
  43. inside stack
  44. 1: exiting
  45. 0: exiting
  46. '''

  

4.Python3标准库--算法的更多相关文章

  1. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  2. Python3 标准库

    Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...

  3. python023 Python3 标准库概览

    Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...

  4. python3标准库总结

    Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...

  5. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  6. 1.Python3标准库--前戏

    Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...

  7. 比较两个文件的异同Python3 标准库difflib 实现

    比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...

  8. Python3标准库:heapq堆排序算法

    1. heapq堆排序算法 堆(heap)是一个树形数据结构,其中子节点与父节点有一种有序关系.二叉堆(binary heap)可以使用一个有组织的列表或数组表示,其中元素N的子元素位于2*N+1和2 ...

  9. 3.Python3标准库--数据结构

    (一)enum:枚举类型 import enum ''' enum模块定义了一个提供迭代和比较功能的枚举类型.可以用这个为值创建明确定义的符号,而不是使用字面量整数或字符串 ''' 1.创建枚举 im ...

随机推荐

  1. Linux查看PCIe版本及速率

    Linux查看PCIe版本及速率 PCIE有四种不同的规格,通过下图来了解下PCIE的其中2种规格 查看主板上的PCI插槽 # dmidecode | grep --color "PCI&q ...

  2. [洛谷P5057][CQOI2006]简单题

    题目大意:有一个长度为$n$的$01$串,两个操作: $1\;l\;r:$把区间$[l,r]$翻转($0->1,1->0$) $2\;p:$求第$p$位是什么 题解:维护前缀异或和,树状数 ...

  3. Ubuntu安装teamviewer注意事项。

    Ubuntu安装teamviewer注意事项. 首先通过浏览器到官方下载ubuntu对应teamviewer的安装包 但是通过dpkg –i安装之后发现安装过程出问题,安装好的包打开之后也闪退. 这个 ...

  4. Mysql Fabric实现学习笔记

    Mysql Fabric用来管理mysql服务,提供扩展性和容易使用的系统,管理mysql分片和高可用部署(当前实现了两个特性:高可用和使用数据分片的横向扩展,能单独使用或结合使用这两个特性.). 架 ...

  5. NOIP2017金秋冲刺训练营杯联赛模拟大奖赛第一轮Day2题解

    上星期打的...题有点水,好多人都AK了 T1排个序贪心就好了 #include<iostream> #include<cstring> #include<cstdlib ...

  6. Wireshark中TCP segment of a reassembled PDU的含义

    By francis_hao    Sep 16,2017   在用Wireshark抓包的时候,经常会看到TCP segment of a reassembled PDU,字面意思是要重组的协议数据 ...

  7. Codeforces Round #332 (Div. 2)B. Spongebob and Joke

    B. Spongebob and Joke time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  8. dubbo在项目中的应用

    关于dubbo的使用,我们举个简单例子: 存在2个系统,A系统和B系统,A系统调用B系统的接口获取数据,用于查询用户列表. 在上一篇博文介绍了dubbo的创建,zookeeper的创建完成后,我们可以 ...

  9. Linux 守护进程创建原理及简易方法

    1:什么是Linux下的守护进程 Linux daemon是运行于后台常驻内存的一种特殊进程,周期性的执行或者等待trigger执行某个任务,与用户交互断开,独立于控制终端.一个守护进程的父进程是in ...

  10. bzoj 2654 tree 二分+kruskal

    tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 2739  Solved: 1126[Submit][Status][Discuss] Des ...