函数的使用方式
将函数视为“一等公民”
- 函数可以赋值给变量
- 函数可以作为函数的参数
- 函数可以作为函数的返回值
高阶函数的用法(filter、map以及它们的替代品)
| 1 2 | items1 = list(map(lambda x: x ** 2, filter(lambda x: x % 2, range(1, 10)))) items2 = [x ** 2 for x in range(1, 10) if x % 2] | 
位置参数、可变参数、关键字参数、命名关键字参数
参数的元信息(代码可读性问题)
匿名函数和内联函数的用法(lambda函数)
闭包和作用域问题
- Python搜索变量的LEGB顺序(Local –> Embedded –> Global –> Built-in)
- global和nonlocal关键字的作用
- global:声明或定义全局变量(要么直接使用现有的全局作用域的变量,要么定义一个变量放到全局作用域)。
- nonlocal:声明使用嵌套作用域的变量(嵌套作用域必须存在该变量,否则报错)。
 
装饰器函数(使用装饰器和取消装饰器)
例子:输出函数执行时间的装饰器。
| 1 2 3 4 5 6 7 8 9 10 11 | def record_time(func):     """自定义装饰函数的装饰器"""     @wraps(func)     def wrapper(*args, **kwargs):         start = time()         result = func(*args, **kwargs)         print(f'{func.__name__}: {time() - start}秒')         return result     return wrapper | 
如果装饰器不希望跟print函数耦合,可以编写带参数的装饰器。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | from functools import wraps from time import time def record(output):     """自定义带参数的装饰器""" 	def decorate(func): 		@wraps(func) 		def wrapper(*args, **kwargs): 			start = time() 			result = func(*args, **kwargs) 			output(func.__name__, time() - start) 			return result 		return wrapper 	return decorate | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from functools import wraps from time import time class Record():     """自定义装饰器类(通过__call__魔术方法使得对象可以当成函数调用)"""     def __init__(self, output):         self.output = output     def __call__(self, func):         @wraps(func)         def wrapper(*args, **kwargs):             start = time()             result = func(*args, **kwargs)             self.output(func.__name__, time() - start)             return result         return wrapper | 
例子:用装饰器来实现单例模式。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from functools import wraps def singleton(cls):     """装饰类的装饰器"""     instances = {}     @wraps(cls)     def wrapper(*args, **kwargs):         if cls not in instances:             instances[cls] = cls(*args, **kwargs)         return instances[cls]     return wrapper @singleton class President():     """总统(单例类)"""     pass | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from functools import wraps from threading import Lock def singleton(cls):     """线程安全的单例装饰器"""     instances = {}     locker = Lock()     @wraps(cls)     def wrapper(*args, **kwargs):         if cls not in instances:             with locker:                 if cls not in instances:                     instances[cls] = cls(*args, **kwargs)         return instances[cls]     return wrapper | 
面向对象相关知识
三大支柱:封装、继承、多态
例子:工资结算系统。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | """ 月薪结算系统 - 部门经理每月15000 程序员每小时200 销售员1800底薪加销售额5%提成 """ from abc import ABCMeta, abstractmethod class Employee(metaclass=ABCMeta):     """员工(抽象类)"""     def __init__(self, name):         self.name = name     @abstractmethod     def get_salary(self):         """结算月薪(抽象方法)"""         pass class Manager(Employee):     """部门经理"""     def get_salary(self):         return 15000.0 class Programmer(Employee):     """程序员"""     def __init__(self, name, working_hour=0):         self.working_hour = working_hour         super().__init__(name)     def get_salary(self):         return 200.0 * self.working_hour class Salesman(Employee):     """销售员"""     def __init__(self, name, sales=0.0):         self.sales = sales         super().__init__(name)     def get_salary(self):         return 1800.0 + self.sales * 0.05 class EmployeeFactory():     """创建员工的工厂(工厂模式 - 通过工厂实现对象使用者和对象之间的解耦合)"""     @staticmethod     def create(emp_type, *args, **kwargs):         """创建员工"""         emp_type = emp_type.upper()         emp = None         if emp_type == 'M':             emp = Manager(*args, **kwargs)         elif emp_type == 'P':             emp = Programmer(*args, **kwargs)         elif emp_type == 'S':             emp = Salesman(*args, **kwargs)         return emp def main():     """主函数"""     emps = [         EmployeeFactory.create('M', '曹操'),          EmployeeFactory.create('P', '荀彧', 120),         EmployeeFactory.create('P', '郭嘉', 85),          EmployeeFactory.create('S', '典韦', 123000),     ]     for emp in emps:         print('%s: %.2f元' % (emp.name, emp.get_salary())) if __name__ == '__main__':     main() | 
类与类之间的关系
- is-a关系:继承
- has-a关系:关联 / 聚合 / 合成
- use-a关系:依赖
例子:扑克游戏。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | """ 经验:符号常量总是优于字面常量,枚举类型是定义符号常量的最佳选择 """ from enum import Enum, unique import random @unique class Suite(Enum):     """花色"""     SPADE, HEART, CLUB, DIAMOND = range(4)     def __lt__(self, other):         return self.value < other.value class Card():     """牌"""     def __init__(self, suite, face):         """初始化方法"""         self.suite = suite         self.face = face     def show(self):         """显示牌面"""         suites = ['♠️', '♥️', '♣️', '♦️']         faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']         return f'{suites[self.suite.value]} {faces[self.face]}'     def __str__(self):         return self.show()     def __repr__(self):         return self.show() class Poker():     """扑克"""     def __init__(self):         self.index = 0         self.cards = [Card(suite, face)                       for suite in Suite                       for face in range(1, 14)]     def shuffle(self):         """洗牌(随机乱序)"""         random.shuffle(self.cards)         self.index = 0     def deal(self):         """发牌"""         card = self.cards[self.index]         self.index += 1         return card     @property     def has_more(self):         return self.index < len(self.cards) class Player():     """玩家"""     def __init__(self, name):         self.name = name         self.cards = []     def get_one(self, card):         """摸一张牌"""         self.cards.append(card)     def sort(self, comp=lambda card: (card.suite, card.face)):         """整理手上的牌"""         self.cards.sort(key=comp) def main():     """主函数"""     poker = Poker()     poker.shuffle()     players = [Player('东邪'), Player('西毒'), Player('南帝'), Player('北丐')]     while poker.has_more:         for player in players:                 player.get_one(poker.deal())     for player in players:         player.sort()         print(player.name, end=': ')         print(player.cards) if __name__ == '__main__':     main() | 
对象的复制(深复制/深拷贝/深度克隆和浅复制/浅拷贝/影子克隆)
垃圾回收、循环引用和弱引用
Python使用了自动化内存管理,这种管理机制以引用计数为基础,同时也引入了标记-清除和分代收集两种机制为辅的策略。
| 1 2 3 4 5 6 | typedef struct_object {     /* 引用计数 */     int ob_refcnt;     /* 对象指针 */     struct_typeobject *ob_type; } PyObject; | 
| 1 2 3 4 5 6 7 8 | /* 增加引用计数的宏定义 */ #define Py_INCREF(op)   ((op)->ob_refcnt++) /* 减少引用计数的宏定义 */ #define Py_DECREF(op) \ //减少计数     if (--(op)->ob_refcnt != 0) \         ; \     else \         __Py_Dealloc((PyObject *)(op)) | 
导致引用计数+1的情况:
- 对象被创建,例如a = 23
- 对象被引用,例如b = a
- 对象被作为参数,传入到一个函数中,例如f(a)
- 对象作为一个元素,存储在容器中,例如list1 = [a, a]
导致引用计数-1的情况:
- 对象的别名被显式销毁,例如del a
- 对象的别名被赋予新的对象,例如a = 24
- 一个对象离开它的作用域,例如f函数执行完毕时,f函数中的局部变量(全局变量不会)
- 对象所在的容器被销毁,或从容器中删除对象
引用计数可能会导致循环引用问题,而循环引用会导致内存泄露,如下面的代码所示。为了解决这个问题,Python中引入了“标记-清除”和“分代收集”。在创建一个对象的时候,对象被放在第一代中,如果在第一代的垃圾检查中对象存活了下来,该对象就会被放到第二代中,同理在第二代的垃圾检查中对象存活下来,该对象就会被放到第三代中。
# 循环引用会导致内存泄露 - Python除了引用技术还引入了标记清理和分代回收
# 在Python 3.6以前如果重写__del__魔术方法会导致循环引用处理失效
# 如果不想造成循环引用可以使用弱引用
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)
以下情况会导致垃圾回收:
- 调用gc.collect()
- gc模块的计数器达到阀值
- 程序退出
如果循环引用中两个对象都定义了__del__方法,gc模块不会销毁这些不可达对象,因为gc模块不知道应该先调用哪个对象的__del__方法,这个问题在Python 3.6中得到了解决。
也可以通过weakref模块构造弱引用的方式来解决循环引用的问题。
魔法属性和方法(请参考《Python魔法方法指南》)
有几个小问题请大家思考:
- 自定义的对象能不能使用运算符做运算?
- 自定义的对象能不能放到set中?能去重吗?
- 自定义的对象能不能作为dict的键?
- 自定义的对象能不能使用上下文语法?
混入(Mixin)
例子:自定义字典限制只有在指定的key不存在时才能在字典中设置键值对。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class SetOnceMappingMixin:     """自定义混入类"""     __slots__ = ()     def __setitem__(self, key, value):         if key in self:             raise KeyError(str(key) + ' already set')         return super().__setitem__(key, value) class SetOnceDict(SetOnceMappingMixin, dict):     """自定义字典"""     pass my_dict= SetOnceDict() try:     my_dict['username'] = 'jackfrued'     my_dict['username'] = 'hellokitty' except KeyError:     pass print(my_dict) | 
元编程和元类
例子:用元类实现单例模式。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import threading class SingletonMeta(type):     """自定义元类"""     def __init__(cls, *args, **kwargs):         cls.__instance = None         cls.__lock = threading.Lock()         super().__init__(*args, **kwargs)     def __call__(cls, *args, **kwargs):         if cls.__instance is None:             with cls.__lock:                 if cls.__instance is None:                     cls.__instance = super().__call__(*args, **kwargs)         return cls.__instance class President(metaclass=SingletonMeta):     """总统(单例类)"""     pass | 
面向对象设计原则
- 单一职责原则 (SRP)- 一个类只做该做的事情(类的设计要高内聚)
- 开闭原则 (OCP)- 软件实体应该对扩展开发对修改关闭
- 依赖倒转原则(DIP)- 面向抽象编程(在弱类型语言中已经被弱化)
- 里氏替换原则(LSP) – 任何时候可以用子类对象替换掉父类对象
- 接口隔离原则(ISP)- 接口要小而专不要大而全(Python中没有接口的概念)
- 合成聚合复用原则(CARP) – 优先使用强关联关系而不是继承关系复用代码
- 最少知识原则(迪米特法则,LoD)- 不要给没有必然联系的对象发消息
- 说明:上面加粗的字母放在一起称为面向对象的SOLID原则。
GoF设计模式
- 创建型模式:单例、工厂、建造者、原型
- 结构型模式:适配器、门面(外观)、代理
- 行为型模式:迭代器、观察者、状态、策略
例子:可插拔的哈希算法。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class StreamHasher():     """哈希摘要生成器(策略模式)"""     def __init__(self, alg='md5', size=4096):         self.size = size         alg = alg.lower()         self.hasher = getattr(__import__('hashlib'), alg.lower())()     def __call__(self, stream):         return self.to_digest(stream)     def to_digest(self, stream):         """生成十六进制形式的摘要"""         for buf in iter(lambda: stream.read(self.size), b''):             self.hasher.update(buf)         return self.hasher.hexdigest() def main():     """主函数"""     hasher1 = StreamHasher()     with open('Python-3.7.1.tgz', 'rb') as stream:         print(hasher1.to_digest(stream))     hasher2 = StreamHasher('sha1')     with open('Python-3.7.1.tgz', 'rb') as stream:         print(hasher2(stream)) if __name__ == '__main__':     main() | 
本文来自这个系列长期转载Python-100-Days ,本文观点不代表蓝洛水深立场,转载请联系原作者。
 
                
 微信扫一扫
                                                            微信扫一扫                                                     支付宝扫一扫
                                                            支付宝扫一扫                                                     
            