函数的使用方式

  • 将函数视为“一等公民”
    • 函数可以赋值给变量
    • 函数可以作为函数的参数
    • 函数可以作为函数的返回值
  • 高阶函数的用法( filtermap 以及它们的替代品)

    1. items1 = list(map(lambda x : x ** 2, filter(lambda x : x % 2, range(1, 10)))))
    2. items2 = [x ** 2 for x in range(1, 10) if x % 2]
  • 位置参数、可变参数、关键字参数、命名关键字参数

  • 参数的元信息(代码可读性问题)
  • 匿名函数和内联函数的用法(lambda函数)
  • 闭包和作用域问题
    • Python搜索变量的LEGB顺序(Local >>> Embedded >>> Global >>> Built-in)
    • globalnonlocal关键字的作用
      global:声明或定义全局变量(要么直接使用现有的全局作用域的变量,要么定义一个变量放到全局作用域)。
      nonlocal:声明使用嵌套作用域的变量(嵌套作用域必须存在该变量,否则报错)
  • 装饰器函数(使用装饰器和取消装饰器)

例子:输出函数执行时间的装饰器 https://www.runoob.com/w3cnote/python-func-decorators.html

  1. from time import time
  2. from functools import wraps
  3. def record_time(func):
  4. @wraps(func)
  5. def wrapper(*args, **kwargs):
  6. start = time()
  7. result = func(*args, **kwargs)
  8. print(f'{func.__name__}: {time() - start}s')
  9. return result
  10. return wrapper

如果装饰器不希望跟print函数耦合,可以编写可以参数化的装饰器

  1. from functools import wraps
  2. from time import time
  3. def record(output):
  4. """可以参数化的装饰器"""
  5. def decorate(func):
  6. @wraps(func)
  7. def wrapper(*args, **kwargs):
  8. start = time()
  9. result = func(*args, **kwargs)
  10. output(func.__name__, time() - start)
  11. return result
  12. return wrapper
  13. return decorate
  1. from functools import wraps
  2. from time import time
  3. class Record():
  4. """通过定义类的方式定义装饰器"""
  5. def __init__(self, output):
  6. self.output = output
  7. def __call__(self, func):
  8. @wraps(func)
  9. def wrapper(*args, **kwargs):
  10. start = time()
  11. result = func(*args, **kwargs)
  12. self.output(func.__name__, time() - start)
  13. return result
  14. return wrapper

说明:由于对带装饰功能的函数添加了@wraps装饰器,可以通过func.__wrapped__方式获得被装饰之前的函数或类来取消装饰器的作用

例子:用装饰器来实现单例模式

  1. from functools import wraps
  2. def singleton(cls):
  3. """装饰类的装饰器"""
  4. instances = {}
  5. @wraps(cls)
  6. def wrapper(*args, **kwargs):
  7. if cls not in instances:
  8. instances[cls] = cls(*args, **kwargs)
  9. return instances[cls]
  10. return wrapper
  11. @singleton
  12. class President:
  13. """总统(单例类)"""
  14. pass

提示:上面的代码中用到了闭包(closure),不知道你是否已经意识到了。还没有一个小问题就是,上面的代码并没有实现线程安全的单例,如果要实现线程安全的单例应该怎么做呢?

线程安全的单例装饰器

  1. from functools import wraps
  2. from threading import RLock
  3. def singleton(cls):
  4. """线程安全的单例装饰器"""
  5. instances = {}
  6. locker = RLock()
  7. @wraps(cls)
  8. def wrapper(*args, **kwargs):
  9. if cls not in instances:
  10. with locker:
  11. if cls not in instances:
  12. instances[cls] = cls(*args, **kwargs)
  13. return instances[cls]
  14. return wrapper

上面的代码用到了with上下文语法来进行锁操作,因为锁对象本身就是上下文管理器对象(支持__enter____exit__魔术方法)。在wrapper函数中,我们先做了一次不带锁的检查,然后再做带锁的检查,这样做比直接加锁检查性能要更好,如果对象已经创建就没有必须再去加锁而是直接返回该对象就可以了

面向对象

  • 类与类之间的关系
    • is-a关系:继承
    • has-a关系:关联 / 聚合 / 合成
    • use-a关系:依赖

例子:扑克游戏。

  1. """
  2. 经验:符号常量总是优于字面常量,枚举类型是定义符号常量的最佳选择
  3. """
  4. from enum import Enum, unique
  5. import random
  6. @unique
  7. class Suite(Enum):
  8. """花色"""
  9. SPADE, HEART, CLUB, DIAMOND = range(4)
  10. def __lt__(self, other):
  11. return self.value < other.value
  12. class Card():
  13. """牌"""
  14. def __init__(self, suite, face):
  15. """初始化方法"""
  16. self.suite = suite
  17. self.face = face
  18. def show(self):
  19. """显示牌面"""
  20. suites = ['♠︎', '♥︎', '♣︎', '♦︎']
  21. faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
  22. return f'{suites[self.suite.value]}{faces[self.face]}'
  23. def __repr__(self):
  24. return self.show()
  25. class Poker():
  26. """扑克"""
  27. def __init__(self):
  28. self.index = 0
  29. self.cards = [Card(suite, face)
  30. for suite in Suite
  31. for face in range(1, 14)]
  32. def shuffle(self):
  33. """洗牌(随机乱序)"""
  34. random.shuffle(self.cards)
  35. self.index = 0
  36. def deal(self):
  37. """发牌"""
  38. card = self.cards[self.index]
  39. self.index += 1
  40. return card
  41. @property
  42. def has_more(self):
  43. return self.index < len(self.cards)
  44. class Player():
  45. """玩家"""
  46. def __init__(self, name):
  47. self.name = name
  48. self.cards = []
  49. def get_one(self, card):
  50. """摸一张牌"""
  51. self.cards.append(card)
  52. def sort(self, comp=lambda card: (card.suite, card.face)):
  53. """整理手上的牌"""
  54. self.cards.sort(key=comp)
  55. def main():
  56. """主函数"""
  57. poker = Poker()
  58. poker.shuffle()
  59. players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]
  60. while poker.has_more:
  61. for player in players:
  62. player.get_one(poker.deal())
  63. for player in players:
  64. player.sort()
  65. print(player.name, end=': ')
  66. print(player.cards)
  67. if __name__ == '__main__':
  68. main()
  69. """ output
  70. 东邪: [♠︎A, ♠︎3, ♠︎4, ♠︎6, ♠︎Q, ♥︎2, ♥︎5, ♥︎9, ♣︎2, ♣︎3, ♣︎9, ♦︎8, ♦︎10]
  71. 西毒: [♠︎9, ♥︎A, ♥︎4, ♥︎6, ♥︎7, ♥︎8, ♥︎10, ♣︎7, ♣︎10, ♦︎A, ♦︎3, ♦︎6, ♦︎J]
  72. 南帝: [♠︎J, ♥︎J, ♥︎Q, ♥︎K, ♣︎4, ♣︎6, ♣︎8, ♣︎J, ♣︎Q, ♦︎4, ♦︎5, ♦︎9, ♦︎Q]
  73. 北丐: [♠︎2, ♠︎5, ♠︎7, ♠︎8, ♠︎10, ♠︎K, ♥︎3, ♣︎A, ♣︎5, ♣︎K, ♦︎2, ♦︎7, ♦︎K]
  74. """