1 Python里的拷贝
1.1 顶层对象为不可变数据类型
1.1.1 子元素都为不可变数据类型

import copy
a = ((1, 2), (3, 4))
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
1.1.2 子元素存在可变数据类型

import copy
a = ((1, 2), [3, 4])
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
1.2 顶层对象为可变数据类型
1.2.1 子元素都为不可变数据类型

import copy
a = [(1, 2), (3, 4)]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)

1.2.2 子元素存在可变数据类型
import copy
a = [(1, 2), [3, 4]]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
2 闭包
2.1 匿名函数、函数、闭包、对象当做实参时的区别
- 匿名函数能够完成基本的简单功能,传递的是这个函数的引用(只有功能)
- 函数能够完成较为复杂的功能,传递的是这个函数的引用(只有功能)
- 闭包能够完成较为复杂的功能,传递的是这个闭包中的函数以及数据(功能+数据),相比对象占用极少空间
- 对象封装较为复杂的数据和功能,传递很多数据和很多功能(功能+数据)
2.2 闭包形成的条件
当一个内嵌函数引用其外部作用域的变量,我们就会得到一个闭包. 总结一下,创建一个闭包必须满足以下几点:
- 必须有一个内嵌函数
- 内嵌函数必须引用外部函数中的变量
- 外部函数的返回值必须是内嵌函数
2.3 闭包简单使用
def config_name(name):
def inner(msg):
print(name + ':' + msg)
return inner
tom = config_name('tom') # name = 'tom'会被保存在tom这个函数引用中,只需要赋值一次
jerry = config_name('jerry') # name = 'jerry'会被保存在jerry这个函数引用中,只需要赋值一次
tom('你好') # tom:你好
jerry('Hello') # jerry:Hello
tom('我叫tom') # tom:我叫tom
jerry('我叫jerry') # jerry:我叫jerry
2.4 闭包内层函数修改外层函数的变量
如果闭包内层函数需要修改外层函数的变量,要用nonlocal关键字,如下:
def warp():
num = 1
def inner():
nonlocal num
print(num )
num = 2
print(num )
return inner
inner()()
# 1
# 2
如果去掉上述代码中nonlocal num语句,那么程序在print(num)处就会报错,因为解释器会把内层inner函数中num = 2看成是定义的一个局部变量,而在定义局部变量num前打印其值会报变量未定义的错误,此处需留意
3 装饰器
3.1 简单装饰器
def decorator(fun):
def wrapper():
print("方法执行前")
fun()
print("方法执行后")
return wrapper
@decorator
# 相当于my_fun = decorator(my_fun)
def my_fun():
print("需要装饰的函数")
my_fun()
# 输出:
# 方法执行前
# 需要装饰的函数
# 方法执行后
3.2 通用装饰器
def decorator(fun):
def wrapper(*args, **kwargs):
print("方法执行前")
result = fun(*args, **kwargs)
print("方法执行后")
return result
return wrapper
@decorator
def my_fun1():
print("需要装饰的函数")
@decorator
def my_fun2(a, b):
return a + b
my_fun1()
# 输出:
# 方法执行前
# 需要装饰的函数
# 方法执行后
print(my_fun2(1, 2))
# 输出:
# 方法执行前
# 方法执行后
# 3
3.3 多个装饰器
多个装饰器装饰同一个函数时,由下向上一层层装饰
def make_div(fun):
def wrapper():
return '<div>' + fun() + '</div>'
return wrapper
def make_p(fun):
def wrapper():
return '<p>' + fun() + '</p>'
return wrapper
@make_div
@make_p
def content():
return "内容"
print(content()) # <div><p>内容</p></div>
3.4 带参数的装饰器
def decorator_out(flag):
def decorator_in(fun):
def wrapper(a, b):
if flag == "+":
print("执行加法操作")
else:
print("执行减法操作")
fun(a, b)
return wrapper
return decorator_in
@decorator_out("+")
# 相当于两步
# temp = decorator_out("+")
# my_fun = temp(my_fun)
def add(a, b):
print(a + b)
add(1, 2)
# 输出
# 执行加法操作
# 3
3.5 类装饰器
class MyDecorator:
def __init__(self, fun):
self.__fun = fun
def __call__(self, *args, **kwargs):
# 类的call方法允许实例化对象进行自身调用,python中每一个函数都实现了call方法
print('函数执行前')
self.__fun()
print('函数执行后')
@MyDecorator
# 相当于my_fun = MyDecorator(my_fun)
def my_fun():
print("需要装饰的函数")
my_fun()
# 输出:
# 方法执行前
# 需要装饰的函数
# 方法执行后
装饰器会在程序编译时就开始装饰,所有装饰器都会执行装饰操作,而不是在函数调用时才去装饰,不受函数调用的影响
4 super().方法名()与类名.方法名()的区别
4.1 类名.方法名()
class Parent:
def __init__(self, name):
print("Parent init start")
self.name = name
print("Parent init end")
class Son1(Parent):
def __init__(self, name, age):
print("Son1 init start")
self.age = age
Parent.__init__(self, name)
print("Son1 init end")
class Son2(Parent):
def __init__(self, name, gender):
print("Son2 init start")
self.gender = gender
Parent.__init__(self, name)
print("Son2 init end")
class GrandSon(Son1, Son2):
def __init__(self, name, age, gender):
print("GrandSon init start")
Son1.__init__(self, name, age)
Son2.__init__(self, name, gender)
print("GrandSon init end")
grand_son = GrandSon('zhangsan', 7, 0)
# 控制台输出如下:
# GrandSon init start
# Son1 init start
# Parent init start
# Parent init end
# Son1 init end
# Son2 init start
# Parent init start
# Parent init end
# Son2 init end
# GrandSon init end
导致Parent中
__init__
方法被调用两次
4.2 super().方法名()
class Parent:
def __init__(self, name, *args, **kwargs):
print("Parent init start")
self.name = name
print("Parent init end")
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs):
print("Son1 init start")
self.age = age
super().__init__(name, *args, **kwargs) # super()代表Son2
print("Son1 init end")
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs):
print("Son2 init start")
self.gender = gender
super().__init__(name, *args, **kwargs) # super()代表Parent
print("Son2 init end")
class GrandSon(Son1, Son2):
def __init__(self, name, age, gender):
print("GrandSon init start")
super().__init__(name, age, gender) # super()代表Son1
print("GrandSon init end")
print(GrandSon.__mro__)
grand_son = GrandSon('zhangsan', 7, 0)
# 控制台输出如下:
# (<class '__main__.GrandSon'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
# GrandSon init start
# Son1 init start
# Son2 init start
# Parent init start
# Parent init end
# Son2 init end
# Son1 init end
# GrandSon init end
super()在复杂的多继承中不是简单的指向父类,而是指向调用类的
__mro__
元组中该类的下一个类,Python3中MRO元组顺序为按继承关系自左向右广度遍历
5 property属性
5.1 装饰器方式
class Student:
def __init__(self):
self.__age = 0
@property
def age(self):
print("获取年龄")
return self.__age
@age.setter
def age(self, value): # 函数名要与property装饰的函数名保持一致
print("设置年龄")
self.__age = value
student = Student()
print(student.age)
student.age = 200
print(student.age)
# 控制台输出:
# 获取年龄
# 0
# 设置年龄
# 获取年龄
# 200
5.2 类属性方式
class Student:
def __init__(self):
self.__age = 0
def get_age(self):
print("获取年龄")
return self.__age
def set_age(self, value):
print("设置年龄")
self.__age = value
age = property(get_age, set_age)
student = Student()
print(student.age)
student.age = 200
print(student.age)
# 控制台输出:
# 获取年龄
# 0
# 设置年龄
# 获取年龄
# 200
6 上下文管理器
6.1 with语句
with open("test.txt", "w") as f:
f.write("hello")
with语句既简单又安全,并且with语句执行完毕之后会自动调用关闭文件操作,即使其代码块中出现异常也会自动调用关闭文件操作。with语句之所以这么强大,是因为其背后是由上下文管理器做支撑的
6.2 自定义上下文管理器(类方式)
一个类只要实现了__enter__
和__exit__
这两个方法,通过该类创建的对象我们就称之为上下文管理器
class File:
def __init__(self, name, model):
self.name = name
self.model = model
def __enter__(self):
print("上文方法")
self.file = open(self.name, self.model)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
print("下文方法")
self.file.close()
with File("test.txt", "r") as f:
# print(f.read())
f.write("test")
# 控制台输出:
# 上文方法
# 下文方法
# 报错信息io.UnsupportedOperation: not writable
上述程序是在test.txt文件存在的情况下执行报错(没有写权限),上下文管理器即使发生异常也会执行
__exit__
方法,如果test.txt文件不存在,则执行报错(没有找到文件),这种异常不会执行__exit__
方法
6.3 自定义上下文管理器(装饰器方式)
from contextlib import contextmanager
@contextmanager
def my_open(name, model):
try:
print("上文方法")
file = open(name, model)
yield file
except Exception as e:
print(e)
finally:
print("下文方法")
file.close()
with my_open("test.txt", "r") as f:
# print(f.read())
f.write("test")
# 控制台输出:
# 上文方法
# not writable
# 下文方法
上述程序无论test.txt文件是否存在,都会执行
__exit__
方法,但test.txt文件不存在时,程序执行最后还会报UnboundLocalError: local variable 'file' referenced before assignment的错
7 生成器
生成器根据规则循环生成数据,数据不是一次性全部生成,而是使用一个生成一个,可以节省大量内存
7.1 简单生成器
my_generator = (i ** 2 for i in range(3))
print(my_generator) # <generator object <genexpr> at 0x000002012773CB48>
# 遍历方法一
while True:
try:
print(next(my_generator))
except: # 当next方法取到生成器最后一个元素,继续使用next方法取值会报错
break
# 遍历方法二
for i in my_generator:
print(i)
7.2 复杂生成器
def my_generator():
for i in range(3):
print("开始生成数据")
yield i # 当程序执行的yield时,程序暂停并把结果返回,再次启动生成器时会在暂停的位置继续向下执行
print("上一次数据生成完毕")
result = my_generator()
print(result) # <generator object my_generator at 0x000001347AE17AC8>
print(next(result))
# 控制台输出:
# 开始生成数据
# 0
print(next(result))
# 控制台输出:
# 上一次数据生成完毕
# 开始生成数据
# 1
遍历方法同简单生成器
7.3 生成器使用场景
def fibonacci(num):
a = 0
b = 1
current_index = 0
while current_index < num:
result = a
a, b = b, a + b
current_index += 1
yield result
fib = fibonacci(5)
for i in fib:
print(i)
8 单例模式
8.1 使用__new__
方法
class Singleton(object):
_instance = None
def __new__(cls, *args, **kw):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
singleton = Singleton()
8.2 共享属性
创建实例时把所有实例的__dict__
指向同一个字典,这样它们具有相同的属性和方法.
class Borg:
_state = {}
def __new__(cls, *args, **kw):
ob = super().__new__(cls)
ob.__dict__ = cls._state
return ob
borg = Borg()
8.3 装饰器版本
def singleton(cls):
instance = None
def getinstance(*args, **kwargs):
nonlocal instance # 修改外部装饰器函数中变量instance,注意不能使用global
if instance is None:
instance = cls(*args, **kwargs)
return instance
return getinstance
@singleton
class MyClass:
...
8.4 import方法
作为python的模块是天然的单例模式
# mysingleton.py
class My_Singleton:
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
9 元类(type)
元类(type)用来动态创建类,类用来动态实例化对象,type使用方法如下:
type(类名, 由父类名称组成的元组(针对继承的情况,可以为空),包含属性的字典(属性和方法))
9.1 简单使用
class A:
def print_num(self):
print(self.num)
def __init__(self):
self.num = 100
@staticmethod
def print_static():
print("static method")
@classmethod
def print_class(cls):
print(cls.attr)
B = type("B", (A,), {"attr": "class_attr", "__init__": __init__, "print_static": print_static, "print_class": print_class})
b = B()
b.print_num() # 100
b.print_static() # static method
b.print_class() # class_attr
print(B.__mro__) # (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
print(B.__class__) # <class 'type'>
print(b.__class__) # <class '__main__.B'>
9.2 元类使用场景
9.2.1 函数方式
def upper_attr(class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr): # 或class Foo(metaclass=upper_attr):
bar = "bip"
print(hasattr(Foo, "bar")) # False
print(hasattr(Foo, "BAR")) # True
f = Foo()
print(f.BAR) # bip
9.2.2 类方式
class UpperAttrMetaClass(type):
def __new__(cls, class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value
# 方法一:通过type来做类对象的创建
return type(class_name, class_parents, new_attr)
# 方法二:复用type.__new__方法
# return type.__new__(cls, class_name, class_parents, new_attr)
class Foo(metaclass=UpperAttrMetaClass):
bar = "bip"
print(hasattr(Foo, "bar")) # False
print(hasattr(Foo, "BAR")) # True
f = Foo()
print(f.BAR) # bip
函数定义好可以使用装饰器为函数增加功能,类定义好可以使用元类为类增加功能
网友评论