接上篇
迭代器
Iterable 形容词! 可以迭代的。类型(对象)
迭代是访问集合元素(如 list、tuple、dict、set、str 等类型的元素值)的一种方式。迭代器(Iterator)是一个可以记住遍历位置的对象。迭代器对象(Iterable)从集合的第一个元素开始访问,直到所有元素被访问至结束,且需要注意的是迭代器只能往前计算而不会向后计算。(过河卒)
通常情况下,可认定为可迭代对象的特点主要有能使用 for 循环遍历的几种数据类型,如下:
(1)集合数据类型,如 list、tuple、dict、set、str 等;
(2)生成器(generator)类型,包括生成器(generator)类型和有 yield 的函数–生成器。
以上这些可直接应用于 for 循环的对象,统称为可迭代对象,即 Iterable。当然,若要判断一个对象是否为可迭代对象,需要使用到 collections 模块下的 Iterable,导包如:from collections import Iterable,且可使用如下函数:
isinstance(x, y)----- 判断一个对象是否是 Iterable 对象,若为可迭代对象,则返回 True,否则为 False。参数 x 为对象名,参数 y 设置为 Iterable 即可。
from collections import Iterable
a=(1,2,3,4,5)
print(isinstance(a,Iterable))

版本为3.10使用pycharm会报错不能导入,此时需要在collection后边加.abc,版本3.6之前的不需要
# coding:utf-8
#版本为最新版本3.10 所以需要加.abc
from collections.abc import Iterable
a=(1,2,3,4,5)
#print("列表是否是可迭代对象:",isinstance([12,11],Iterable))
print("是否是可迭代对象:",isinstance(a,Iterable))

2.迭代器对象
通常情况下,能调用出 next()函数–生成器且能返回下一个值的对象,称为迭代器对象,即 Iterator。对于迭代器对象,也可以使用 isinstance()函数进行判断,下面分别判断列表、元组、字符串、生成器对象、数字是否为迭代器对象
# coding:utf-8
#版本为最新版本3.10 所以需要加.abc
from collections.abc import Iterator
print("元组是否迭代器对象:",isinstance((1,2,3),Iterator))
print("列表是否迭代器对象:",isinstance([1,2,3],Iterator))
print("数字是否迭代器对象:",isinstance(100,Iterator))
print("字符串是否迭代器对象:",isinstance("hello",Iterator))
print("是否迭代器对象:",isinstance((i for i in range(10)),Iterator))

值得注意的是,生成器都是迭代器(Iterator)对象,但列表(list)、元组(tuple)、字符串(str)等,虽然是可迭代对象(Iterable),却不是迭代器(Iterator)对象。若要把列表(list)、元组(tuple)、字符串(str)等可迭代对象(Iterable)变为迭代器(Iterator)对象,则可使用如下函数:
# coding:utf-8
#版本为最新版本3.10 所以需要加.abc
from collections.abc import Iterator
print(isinstance(iter([12,34]),Iterator))

对于上述的迭代器内容,需要注意以下几点:
(1)可使用 for 循环进行遍历的对象,都属于 Iterable 类型;(可迭代对象)
(2)可使用 next()函数获取下一个值的对象,都属于 Iterator 类型;(迭代器对象)
(3)集合数据类型如 list、tuple、dict、set、str 等是 Iterable 类型,而不是 Iterator 类型,但可通过 iter()函数将 Iterable 对象转换为一个 Iterator 对象。
闭包
1.基本使用
外部函数名(...参数):
(参数)
内部函数:
在内部函数中,要使用到参数。
return 内部函数名
# coding:utf-8
#定义函数
def test():
print("haha")
test()
print(test) #所有的方法都有一个地址值
#赋值
show=test
#调用
show()
print(id(test))
print(id(show))

通常情况下,在函数内部再定义一个函数,且这个函数用到了外边函数的变量,那么将整个函数及用到的一些变量称为闭包。
# coding:utf-8
#定义函数
def test(a):
print("---------test()----------")
def add(b):
print("-------------add()-------------")
sum=a+b
print("两个数之和=",sum)
return add #返回结果;结束函数
get_sum=test(11)
get_sum(25)

2.深入理解
# coding:utf-8
#定义函数
def test(num=0): #缺省函数
def add():
num+=1
print("num=0,再加1等于:",num)
return add
#调用
sums=test()
sums()

程序把num当成一个局部变量,若要修改上述错误,需要先使用nonlocal关键字来声明num变量
# coding:utf-8
#定义函数
def test(num=0): #缺省函数
def add():
#内部函数要访问num 声明变量 用nonlocal
nonlocal num
num+=1
print("num=0,再加1等于:",num)
return add
#调用
sums=test()
sums()

接下来,通过一个应用案例来深入理解闭包的实际作用,例如,使用函数来完成数学中的一元一次方程式“ax+b”的求解。
# coding:utf-8
#定义函数 y=ax+b
def get_y_value(x):
def receive_ab(a,b):
#求解y
return a*x+b
return receive_ab
#调用
get_value=get_y_value(10)
#调用内部函数
result=get_value(3,4)
print("y的值为:",result)
result=get_value(5,6)
print("y的值为:",result)

在这个例子中,get_x()函数与变量 a,b 形成了闭包。在创建闭包时,通过receive_ab的参数 a,b 传递这两个变量的取值,因此,就确定了函数的最终形式(如 y =2 x + 5)。在内部函数的调用时,只需要变换参数 a,b,就可以获得不同的直线表达函数。
由此,可以看到,闭包也具有提高代码可复用性的作用。若不使用闭包,则需要每次创建函数时,同时说明a,b,x。采用这种方式,就需要传递更多的参数值,也减少了代码的可移植性。在这里,总结闭包的特点:
(1)闭包可以优化变量,需要类对象来完成的工作,闭包也可以完成;
(2)闭包引用了外部函数的局部变量,而外部函数的局部变量没有及时释放内存,因此,采用闭包的方式相对而言更加消耗内存空间
**
装饰器
**
# coding:utf-8
def test_a(arg):
print("------test_a-----")
arg()
# #装饰器
# @test_a
def test():
print("----test------")

对于上述案例中的test_a,就相当于test_a(test)
对一串字符串进行处理,对字体加粗、对字体变
为斜体:<i><b>...(一串字符串)</b></i>
# coding:utf-8
def make_font_bold(fn):
def inner():
return "<b>"+fn()+"</b>"
return inner
#字体变为斜体
def make_font_italic(fn):
def inner():
return "<i>"+fn()+"</i>"
return inner
#设置字体变粗,斜体
@make_font_italic
@make_font_bold
def say_hello():
return "你好"
#调用
print(say_hello())

用处:在不改变原有代码的前提下,再新增了一些功能。
装饰器是一个非常著名的设计模式,常用于有注解需求的场景(如之前的静态方法@staticmethod、类方法
@classmethod 等),较为经典的应用有插入日志–查看代码如何运行(添加日志、debug)、函数执行时间统计、加入事务处理等。装饰器是解决这类问题的绝佳方案,有了装饰器,就可以抽离出大量函数中与函数功能本身无关的类似代码并继续复用。概括地说,装饰器的作用就是为已经存在的对象添加额外的功能。
# coding:utf-8
#计算一段代码执行的花费时间!0-1000 所花费的时间!
import time
#起始时间
start=time.time()
#执行代码
i=0
while i < 1000:
print(i)
i+=1
#结束时间
end=time.time()
print("花费的时间为%f秒"%(end-start))

对于装饰器的定义,相对而言较为抽象
# coding:utf-8
import time
#执行时间
def execute():
i=0
while i<1000:
print(i)
i+=1
#测试代码执行时间
def test_block(block): #传递引用 block相当于形参
#起始时间
start = time.time()
#执行代码片段
block()
#结束时间
end=time.time()
print("花费时间为%f秒."%(end-start))
#调用执行
test_block(execute)
上述代码看起来逻辑上没有问题,也能正常运行,但是,却修改了调用部分的代码,如原本是这样调用的:execute(),修改后变为:test_block(execute)。这样的话,若 excute()需要被调用 n 次,此时就不得不去修改这n 次的代码。既然如此,我们就要想办法要不修改调用的代码;若不修改调用代码处,则需要在调用 execute()达到test_block(execute)的效果。
# coding:utf-8
import time
#采用闭包完成
def test_block(block):
def inner():
#起始时间
start = time.time()
#执行代码片段
block()
#结束时间
end=time.time()
print("花费时间为%f秒."%(end-start))
#将内部函数的引用返回
return inner
#测试的代码片段
@test_block
def execute():
i = 0 # 代码片段修改即可
while i < 1000:
print("HelloWorld")
print(i)
i += 1
execute()
#@test_block相当于下边代码
# test=test_block(execute)
# test()

@test_block,在定义 execute()函数时加上这行与编写 test = test_block(execute)功能完全一致,此外,千万不要以为@有特别的魔力,这里除字符输入少一些外,还有一个其他好处,即这样看上去更有装饰器的样式。
1.
内置装饰器
对于内置装饰器,在 Python 中有三个,分别是@staticmethod、@classmethod 和@property,作用分别是把类中定义的普通方法变为静态方法、类方法和类属性。
例如,一个有名称属性的猫类有吃、睡觉的行为并编写内置装饰器。
# coding:utf-8
class Cat(object):
"""
1.静态方法:吃
2.类方法:睡觉
3.name -->封装! @property
"""
def __init__(self):
self.__name = ""
#公有属性
@property
def name(self):
return self.__name
@name.setter
def name(self,name):
self.__name=name
@staticmethod
def eat():
print("静态方法eat()")
@classmethod
def sleep(cls):
print("类方法sleep")
#调用 不用实例化 直接类名.方法
Cat.eat()
Cat.sleep()
#也可以实例化用对象名.方法
cat=Cat()
cat.sleep()
cat.eat()
#属性
cat.name="小猫"
print(cat.name)

2.案例分析
对于装饰器的案例,我们通过无参数的函数、被装饰的函数有参数、被装饰的函数有不定长参数、装饰器中有 return、装饰器带参数、类装饰器这几个案例来分别讲解。
(1) 无参数的函数
# coding:utf-8
def test(func): #闭包
def inner():
print("装饰器无参数的函数")
func()
return inner
@test
def show():
print("hello")
#调用
show()

上边的执行步骤可以理解为:
show= test(show)
#show 先作为参数赋值给 func 后,show 接收指向 test 返回的 inner
show()
也可通俗的理解上述代码,如:调用 show(),即等价于调用 inner(),只是内部函数 inner()被引用为 show,而外部函数的 func 变量(即自由变量)并没有释放,而 func 里保存的是原 show()函数对象。
(2)被装饰的函数有参数
# coding:utf-8
def test(func):
def inner(x,y):
print("-------test()--------")
print("数值x=%d,数值y=%d"%(x,y))
func(x,y)
return inner
@test
def sum(a,b):
print("-------sum()---------")
print("和为%d"%(a+b))
#调用
sum(11,22)

(3)被装饰的函数有不定长参数
# coding:utf-8
def timefun(func):
def wrapped(*args,**kwargs):
print("-----------timefun()-wrapped--------------")
func(*args,**kwargs)
return wrapped
@timefun
def test(a,b,c,**name):
#输出字典的values值
for temp in name.values():
print(temp)
print("和为%d"%(a+b+c))
test(1,2,3,name="求和:")

(4)装饰器中有return
# coding:utf-8
def timefun(func):
def wrapped():
print("-----------timefun()-wrapped--------------")
func()
return wrapped
@timefun
def test():
return "hello"
test()
print("*************")
print(test())

None --------callble对象为None
(5)装饰器带参数
# coding:utf-8
def timefun_arg(a):
def timefun(func):
def wrapped():
print("--------wrapped--{}------------".format(a))
return func()
return wrapped
return timefun
@timefun_arg("hello")
def test():
print("******test()******")
test()

上述案例代码中调用的test()可以理解为:
timefun_arg("hello")(test)()
(6)类装饰器
class Test(object):
def __init__(self):
print("hello")
test=Test()
test()

类装饰器其实有这样一个接口约束,它必须接受一个 callable 对象作为参数,然后返回一个 callable 对象。
在 Python 中,一般 callable 对象都是函数,而只要某个类重写了 __call__()方法,那么这个类对象就是 callable 对象。
# coding:utf-8
class Test(object):
def __call__(self, *args, **kwargs):
print("hello")
test=Test()
test() #自动调用__call__()

对于上述案例代码,需要注意的是:
(1)当用 Test 类来做为装饰器并对 test 函数进行装饰时,首先会创建 Test 的实例对象,同时会把 test 这个函数名自动传递到__init__方法中;
(2) test 函数相当于指向了用 Test 创建出来的对象;
(3)当在使用 test()进行调用时,就相当于调用“对象()”,因此会调用这个对象的__call__()方法。
元类(type类)
1.类可以使对象
在面向对象的计算机编程语言里,类其实就是用来描述如何生成一个具体实体或对象的代码段
# coding:utf-8
class Test:
pass
t=Test()
print(t)
#查看类型
print(type(t))

‘’‘’
在这里,若要查看一个类中是否具有某个属性,则可以使用如下函数判断,如:
hasattr(x,y) ----判断类 x 中是否有属性 y,若含有,则返回 True,否则为 False。其中,参数 x 表示类名,参数 y 表示属性名。
# coding:utf-8
class Test:
pass
t=Test()
print(t)
print(type(t))
print("类中是否有属性name",hasattr(Test,"name"))
Test.name="测试"
print("类中是否有属性name",hasattr(Test,"name"))

当然,Python 中的类(Test–>类名.类属性)还可以当成对象(对象名.属性)使用,值得注意的是,只要开发者在 Python 程序中使用 class 关键字修饰类,则 Python 解释器在执行程序时,就会在内存中创建一个对象,而上述案例的这个对象名字就是 Test,只不过该对象较为特殊,该对象(即类对象 Test)可用于创建对象(或实例),而 Test 的本质上仍是一个对象。与正常创建出来的对象类似
(1)可直接输出类,且输出的内容即为该类的类型;
(2)可将类赋值给一个变量; --show()
(3)可为类添加属性;
(4)可直接将类作为参数进行传递。
# coding:utf-8
class Test:
pass
print("------1------")
t=Test()
print(t)
print("t的类别:",type(t))
print("------2------")
print(Test)
print("Test的类别:",type(Test))

2.动态的创建类
因为类也是对象,所以也可以像对象那样在运行过程中即可动态的创建类(对象想使用时就创建),这个操作过程特别像之前学习过程中的简单工厂模式。通常情况下,要想动态的创建类,则需要在函数中创建类,并使用class 关键字修饰该类。
# coding:utf-8
def create_class(flag):
#在执行过程中,要创建不同的类
if flag=="dog":
class Dog:
pass
return Dog
elif flag=="cat":
class Cat:
pass
return Cat
else:
class Dog:
pass
return Dog
#创建
new_class=create_class("dog")
print(type(new_class))
print(new_class)

对于上述代码,也许这还不够动态,因为在这仍然需要编写整个类的内部代码内容。需要注意的是因为类也是对象,因此可以猜测类应该也是通过什么内容来生成的。–对象是通过类名()创建生成。
当使用 class 关键字来修饰类时,Python 解释器会自动创建这个类对象,当然,Python 中也给开发者提供了
手动创建对象的方式,即“对象名 = 类名()”
在这里,不得不说一下之前学习过的内建函数 type(),我们都知道它可以检测出某个对象的具体类型是什么,如下:
type(变量名)
<class 'type'>
type创建类
1.基本使用
其实,在 Python 中,type 还有一种与上述 type()函数不同的功能,那就是可以动态的创建 Python 类。
type 可以接受一个类的所有描述信息(如类名、属性名、方法名等)并将它们作为参数值进行传递,然后再返
回一个 Python 类,这种方式主要是为了让 Python 以后的版本升级有更好的兼在这里插入代码片容性,type 语法格式如下:
type( 类名, 由父类名称组成的元组(针对继承的情况,可以为空), 包含属性名与值的字典)
即 type("类名",(),{key1:value1,key2:value2,...})
# coding:utf-8
#创建Dog类,使用class修饰
class Dog:
pass
#创建对象
dog=Dog()
print(dog)

利用上述的type在IDLE工具里创建一个Dog类
对于上述的相关代码,我们是使用 type()的第一个参数作为类名,且可以看出 Dog 类没有任何属性或方法。
接下来,我们可以使用 help()函数来查看 Dog 类–文档说明,如下:help()查看文档
2. 使用type创建带有属性的类
当然,对于上述的 Dog 类,我们会发现它是没有属性的,接下来,就给它添加两个属性:名称、是否为公的,代码如下:
#使用 type 创建 Dog 类
Dog = type("Dog",(),{"name":"旺财","is_man":True})
代码可以理解为:
# coding:utf-8
#创建Dog类
class Dog:
#属性
name="旺财"
is_man=True
此时,就可以把 Dog 类当成一个普通类来使用了,如下:
#使用 type 创建 Dog 类
Dog = type("Dog",(),{"name":"旺财","is_man":True})
#输出类
print(Dog)
#创建对象
dog = Dog()
print(dog)

也可以给Dog类编写其他子类,代码
#子类 LittleDog 继承自 Dog 类
class LittleDog(Dog):
pass
若使用 type 来完成继承过程,如下:
LittleDog = type("LittleDog",(Dog,),{})
对于 Dog 类,我们知道在上述过程中,我们给 Dog 类添加了两个属性:name、is_man,而 LittleDog 是继承自 Dog 类,因此它也会具有这两个属性,示例代码如下:
#使用 type 创建 Dog 类
Dog = type("Dog",(),{"name":"旺财","is_man":True})
#输出类
print(Dog)
#创建对象
dog = Dog()
print(dog)
#创建Dog的子类
LittleDog = type("LittleDog",(Dog,),{})
#输出子类的属性
print(LittleDog.name)
print(LittleDog.is_man)

需要注意以下几点,如下:
(1)type()的第二个参数,属于元组类型,且是表示继承的父类名;
(2)type()的第三个参数,属于字典类型,添加的属性内容是类属性,而不是实例属性。
3.使用type创建带有方法的类
若要给类添加方法,也是可以通过 type()来完成的。下面分别给 Child 类添加普通方法、静态方法、类方法,添加方法的语法格式如下:
类名 = type(类名, (), {属性名 1: 方法名 1, 属性名 2:方法名 2, ...})
(1)添加普通方法
下面通过给 Child 类添加一个普通方法 play()来进行讲解,示例代码如下:
#使用 type 创建 Dog 类
def play(self):
print("----添加普通方法")
print("喜欢玩耍")
#使用type()创建类,且添加普通方法
Child=type("Child",(),{"play":play})
#测试是否有play属性
print(hasattr(Child,"play"))
#创建对象
child=Child()
child.play()

(2)添加静态方法
下面通过给 Child 类添加一个静态方法 drink()来进行讲解,示例代码如下:
@staticmethod
def drink():
print("--添加静态方法--")
print("渴了,知道要喝水")
#使用 type()创建类,且添加静态方法
Child=type("Child",(),{"drink":drink})
print(hasattr(Child,"drink"))
child=Child()
child.drink()

(3)添加类方法
下面通过给 Child 类添加一个类方法 sleep()来进行讲解,示例代码如下:
@classmethod
def sleep(cls): #类方法中有一个参数为cls
print("--添加类方法--")
print("困了,想要睡觉")
#使用 type()创建类,且添加类方法
Child=type("Child",(),{"sleep":sleep})
print(hasattr(Child,"sleep"))
child=Child()
child.sleep()

理解元类
1.基本理解(__class__属性)
通过上述的相关案例,我们可以得出结论:元类(type(…))就是用来创建类的一种方式。通俗地,元类就是类的类(根,老祖宗),即 type,如创建一个 MyClass 类,如下:
MyClass = type("MyClass", (), {})
注意,函数 type 实际上就是一个元类,type 就是 Python 解释器在背后用来创建所有类的元类。对于 type为何采用小写形式而不采用 Type(类:所有单词首字母大写,其他字母均小写!)呢?其实,这更多的是与其他类型保持一致性,如 list、dict、tuple、str 是用来创建字符串对象的类,而 int 是用来创建整数对象的类等,而 type就是创建类对象的类。
在 Python 中,通过检查__class__属性来查看到“type 就是创建类对象的类”。对于 Python 面向对象的特性,要注意“一切皆对象”,包括数字、字符串、列表、类等等,它们都是从一个类创建而来,这个类就是 type。
下面通过数字、字符串、类来了解__class__属性,示例代码如下:
#类
class User:
pass
user=User()
print(user.__class__)
#数字
age=18
print(age.__class__)
#字符串
name="xiaoming"
print(name.__class__)

接下来,继续来思考,对于任何一个__class__的__class__属性又是什么呢?示例代码如下:

从上述结果看,元类就是创建类这种对象的方式而 type 是属于 Python 中的内建元类。
2.__metaclass__属性
除了元类的上述内容,还需要了解一个知识点,那就是__metaclass__属性,语法格式如下:
class 类名(object):
__metaclass__ = 值 -->Python2 中可以使用;Python3 变量: metaclass
......
若按照上述语法格式编写类,则 Python 就会用元类来创建“类名(object)”。首先,写下“class 类名(object):”,但“类名(object)”还没在内存中创建成功,此时 Python 就会在类的定义中寻找__metaclass__属性,若找到了,Python 则会使用该属性来创建“类名(object)”;若没找到,则会用内建元类 type 来创建这个“类名(object)”。
接下来通过下面这段代码来理解元类,代码如下
class MyClass(object):
pass
对于上述代码,Python 会做如下操作:
(1)MyClass 中有__metaclass__属性吗?若有,则 Python 会通过__metaclass__属性创建一个名为 MyClass 的类(或对象);
(2)若 Python 未找到__metaclass__属性,则会继续在 object(父类)中寻找__metaclass__属性,并尝试做上一步相同的操作;
(3)若还是找不到__metaclass__属性,则 Python 就会用内置的 type 来创建这个类对象。
到这里,需要了解在__metaclass__中设置些什么属性值呢?答案就是:type,或任何使用到 type 或者子类化 type 的内容都行。
自定义元类
元类的主要目的就是为了在创建类时,能够自动地改变类的属性或方法。通常情况下,开发者希望为已有的
Python API 中创建出符合当前应用场景的 Python 类。
假设开发者想在自己编写的模块里让所有类的属性名称都变为大写形式,在这里,就可以通过在模块级别中设置__metaclass__属性,采用这种方式,这个模块中的所有类都会通过这个元类来创建,此时只需要编写相关代码让元类把所有的属性都改成大写形式就完成了。
幸运的是,__metaclass__属性实际上是可以被任意调用的,且它并不需要一个真正的类。因此,我们这里就先以一个简单的函数作为例子来进行了解。当然,在 Python 不同版本之间是对于元类是存在一些差异性的,下面分别从 python2 和 python3 来简要分析。
1.python2版本
在 python2 版本中,使用元类完成将所有属性名转变为大写形式的案例代码如下:
#coding:utf-8
#将所有属性名变为大写
#参数 1:类名; 参数 2:父类名; 参数 3:属性名
def change_upper_attr(class_name,parents,attrs):
# 遍历属性字典,把不是__开头的属性名字全转变为大写形式
new_attrs={}
for name,value in attrs.items():
#以__开头
if not name.startswith("__"):
# 全转换为大写的再赋属性值
new_attrs[name.upper()]=value
#调用type来创建一个类
return type(class_name,parents,new_attrs)
class Book(object):
# __metaclass__属性
__metaclass__ = change_upper_attr # 设置 Book 类的元类为 upper_attr
# 出版年份
year = 2018
#是否含有 year 属性
print(hasattr(Book, "year"))
#是否含有 YEAR 属性
print(hasattr(Book, "YEAR"))
#创建对象
book = Book()
print(book.YEAR)

2.python3版本
在 python3 版本中,使用元类完成将所有属性名转变为大写形式的案例代码如下:
#将所有属性名变为大写
#参数 1:类名; 参数 2:父类名; 参数 3:属性名
def change_upper_attr(class_name,parents,attrs):
# 遍历属性字典,把不是__开头的属性名字全转变为大写形式
new_attrs={}
for name,value in attrs.items():
#以__开头
if not name.startswith("__"):
# 全转换为大写的再赋属性值
new_attrs[name.upper()]=value
#调用type来创建一个类
return type(class_name,parents,new_attrs)
class Book(object,metaclass=change_upper_attr): ##设置 Book 类的元类为 upper_attr
# 出版年份
year = 2018
#是否含有 year 属性
print(hasattr(Book, "year"))
#是否含有 YEAR 属性
print(hasattr(Book, "YEAR"))
#创建对象
book = Book()
print(book.YEAR)

对于上述 python2 与 python3 版本的不同,我们会发现__metaclass__属性有一些使用上的不同,python2 版本中需要将“__metaclass__属性”放在 Python 类中进行赋值,而 python3 版本中将“__metaclass__属性”以“metaclass = 属性值”的形式写在继承类的后面即可。
对于 Python 中的元类,基本内容就是这样,仅需要了解即可。但就元类本身知识点而言,是很简单的,基本步骤主要有:
(1)拦截类的创建; class…:…
(2)修改类,或修改类的属性及方法;
(3)返回修改后的类。
在这里,引用 Python 界的领袖 Tim Peters 的一句话作为元类知识的结束语!