广州番禺Python, Java小班周末班培训
薯条老师在广州做Python和Java的小班培训,一个班最多10人,学员的平均就业薪资有11K。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。培训的课程有Python爬虫,Python后端开发,Python办公自动化,Python大数据分析,Python量化投资,Python机器学习,Java中高级后端开发。授课详情请点击:http://chipscoco.com/?cate=6
16.10.1 一切皆对象
在Python中一切皆对象,迄今学过的简单数据类型,复合数据类型,函数等都是对象,甚至连类本身也是对象。Python中的类是用来创建对象的对象。在前面的内容中,我们使用type来输出对象的类型。对于类,同样可以使用type来输出其类型。现在进入Python的交互模式,在交互模式中进行验证:
>>> class Test:... pass...>>> type(Test)<class 'type'>
在交互模式中,我们定义了一个Test类,在执行type函数时,输出的结果为 <class 'type'>,type正是类的类型。在Python中,type类型是类类型的metaclass,metaclass的中文释义即为元类。使用元类可以动态地创建类。
16.10.2 type元类
关于type元类的定义和用法,可以在交互模式中执行help('type')来进行查找:
>>> help(type)Help on class type in module builtins:class type(object)| type(object_or_name, bases, dict)| type(object) -> the object's type| type(name, bases, dict) -> a new type|
在help的输出中可知,type本身也是一个类,它的父类是object。
在16.7节中讲到了MRO,在MRO的输出中,我们可以分析出object是所有类类型的顶层基类。
在type类中,可以通过函数type(name, bases, dict)来创建一个新的类类型。其中参数name表示类类型的名称,必须是字符串类型。bases用来定义该类型的基类,是一个元祖类型。参数dict是一个字典类型,对应的是该类型的命名空间,用来定义类类型的类属性和方法,在这个字典中,键名是属性名或方法名,键值对应的是具体的属性值或函数。
代码实例:
# __desc__ = 使用type来动态地创建类 # 1.执行type来创建一个Cat类,并定义了一个类属性species Cat = type("Cat", (), {"species":"cat"}) # 通过type来创建Cat类,通过Cat类来实例化一个对象 kitty = Cat() print(kitty.species) """ 程序的输出为: cat """ # 2.执行type来创建一个Babby类,Babby类的基类是Cat类 Babby = type("Babby", (Cat,),{}) # 通过type来创建Babby类,Babby类继承于Cat类 # 现在通过Babby类来实例化一个对象 lisa = Babby() print(lisa.species) """ 程序的输出为: cat """在上面的代码实例中,为类类型添加的是类属性,由于type中的dict参数是一个字典类型,所以在添加类方法,静态方法,对象方法时,方法需提前进行定义,然后将其作为键值。类方法,静态方法须遵循相应的规范,比如定义类方法时,须通过@classmethod进行修饰。
代码实例:
# __desc__ = 使用type来动态地创建类 # 定义一个catch_mice函数,参数为cls @classmethod def catch_mice(cls): print("a cat that doesn't catch a mouse is not a good cat") # 1.执行type来创建一个Cat类,并将catch_mice作为类方法 Cat = type("Cat", (), {"catch_mice": catch_mice}) Cat.catch_mice() """ 程序的输出为: a cat that doesn't catch a mouse is not a good cat """
16.10.3 自定义元类
在16.9.2节中,系直接通过type类型来创建一个类类型,但这样的做法有一个很大的弊端,不能控制类类型的创建过程。继承是面向对象编程的重要特征之一,通过面向对象中的继承,我们可以从type中派生出一个新的元类。
在对type进行继承之前,需要先理解并掌握type中的四个魔术方法:
(1) type.__new__(mcs, name, bases, dict)
__new__方法是一个静态方法,用来构造一个类类型, 并返回该类实例。元类中的__new__方法用来构造一个类,类中的__new__方法用来构造一个对象。__new__方法中的参数与type方法中的参数基本一致,但多了一个mcs, 参数mcs表示元类的类型。由于__new__方法是静态方法,所以必须显式的传递元类类型 。
(2) type.__prepare__(mcs, name, bases)
__prepare__方法是一个类方法,默认返回一个空的dict对象。该方法的参数同__new__方法中的参数。__prepare__方法用来创建类的命名空间,即type中的dict参数所对应的命名空间。在__new__方法中接收一个dict参数,而__new__方法是自动被Python调用的,由此可推断Python解释器会先调用__prepare__方法,然后将已构造好的命名空间对象传递给__new__方法。
(3) type.__init__(self, name, bases, dict)
__init__方法用来对类实例进行初始化,参数与__new__方法基本一致,参数self表示元类的实例对象。__init__方法在__new__方法之后被调用。
(4) type.__call__(self, *args, **kwargs)
在之前的内容中有介绍过__call__方法,__call__方法使得对象变成可调用对象。在type元类的__call__方法中,默认返回类的实例。现在我们来对type进行继承:
# __desc__ = 对type类进行继承 #定义一个CatType,该元类负责创建Cat类 class CatType(type): @classmethod def __prepare__(mcs, name, bases): print("Cat type is creating namespace") # 调用父类type的__prepare__方法,返回一个命名空间 return super().__prepare__(name, bases) @staticmethod def __new__(mcs, name, bases, dict) print("Cat type is creating Cat Class") # 调用父类type的__new__方法 return super().__new__(mcs, name, bases, dict) def __init__(self, name, bases, dict) print("Cat type is initializing Cat Class") # 调用父类type的__init__方法 super().__init__(name, bases, dict) print("Cat Class initialized")对type进行继承以后,就得到了一个自定义的元类,我们可以用这个自定义的元类来控制类的创建过程。在Python3中定义一个类时,通过关键字参数metaclass来指定元类。指定元类的基本语法:
class ClassName(metaclass=type): passmetaclass的默认值是type,即默认使用内置的type元类来创建类类型。现在我们通过自定义的元类CatType来控制Cat类的创建过程。那么具体该如何控制呢?很简单,把控制逻辑写入到元类的这几个魔术方法当中。同学们须理解这几个魔术方法的作用,以改写对应的魔术方法。现在通过自定义的元类来控制每次对类实例化时,获取的都是同一个对象:
# __desc__ = 对type类进行继承 # 定义一个CatType,该元类负责创建Cat类 class CatType(type): @classmethod def __prepare__(mcs, name, bases): return super().__prepare__(name, bases) @staticmethod def __new__(mcs, name, bases, dict): print("__new__") return super().__new__(mcs, name, bases, dict) def __init__(self, name, bases, dict): print("__init__") # 在元类中为类创建一个类属性__instance # 用__instance来保存类的实例对象 self.__instance = None super().__init__(name, bases, dict) def __call__(self, *args, **kwargs): print("__call__") # 判断__instance属性是否为空 if self.__instance is None: # 如果为空,则调用父类type的__call__方法来返回类的实例对象 self.__instance = super().__call__(*args, **kwargs) # 由于__instance已经非空,所以直接返回__instance return self.__instance class Cat(metaclass=CatType): pass kitty = Cat() # 第二次调用Cat()时,由于Cat类已经构造并且初始化,所以会先调用__call__方法 # 在__call__方法中直接返回已实例化的对象,所以每次获取到的都是同一个对象 lisa = Cat() # 使用is操作符来判断是否为同一个对象 print(lisa is kitty) """ 程序的输出为: __new__ __init__ __call__ __call__ True """
16.10.4 知识要点
(1) 在Python中一切皆对象,迄今学过的简单数据类型,复合数据类型,函数等都是对象,甚至连类本身也是对象。Python中的类是用来创建对象的对象。(2) type是类的元类,通过类来创建对象,而通过元类来创建类。(3) 自定义元类时,须通过关键字参数metaclass来指定元类
16.10.5 最具实力的小班培训
薯条老师在广州做Python和Java的小班培训,一个班最多10人。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。打算参加小班培训的同学,必须遵守薯条老师的学习安排,认真做作业和项目。把知识学好,学扎实,那么找到一份高薪的工作就是很简单的一件事。
(1) Python后端工程师高薪就业班,月薪11K-18K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,免费领取课程大纲
(3) Java后端开发工程师高薪就业班,月薪11K-20K, 免费领取课程大纲
(4) Python大数据分析,量化投资就业班,月薪12K-25K,免费领取课程大纲
扫码免费领取Python学习资料: