推荐观看:推荐几个学习Python的免费网站一、Python中的类在理解元类之前,你需要先掌握Python中的类。Python借用SmallTalk语言特性来实现类。在大多数语言中,类一般就是一段生成对象的代码,在Python中也是如此。classObjectCreator(object):...pass...my_object=ObjectCreator()print(my_object)<__main__.ObjectCreatorobjectat0x8974f2c>在Python中,类也是一种对象。执行以下代码时,Python会申请一块内存来保存名为ObjectCreator的对象。classObjectCreator(object):...pass...生成的对象(类)具有创建对象(实例)的能力,所以称为类。作为对象,它可以像对象一样操作:可以给变量赋值,可以复制,可以添加属性,可以把它作为函数参数传递print(ObjectCreator)#可以打印一个类,因为它是一个objectdefecho(o):...print(o)...echo(ObjectCreator)#你可以传递一个类作为参数print(hasattr(ObjectCreator,'new_attribute'))FalseObjectCreator.new_attribute='foo'#你可以添加attributestoaclassprint(hasattr(ObjectCreator,'new_attribute'))Trueprint(ObjectCreator.new_attribute)fooObjectCreatorMirror=ObjectCreator#你可以将一个类分配给一个变量print(ObjectCreatorMirror.new_attribute)fooprint(ObjectCreatorMirror())<__main__.ObjectCreatorobjectat0x8997b4c>2。动态生成的类可以像对象生成一样动态生成。先用class关键字定义类defchoose_class(name):...ifname=='foo':...classFoo(object):...pass...returnFoo#返回类,不返回一个实例...else:...classBar(object):...pass...returnBar...MyClass=choose_class('foo')print(MyClass)#该函数返回一个类,而不是一个实例print(MyClass())#youcancreateanobjectfromthisclass<__main__.Fooobjectat0x89c6d4c>上面的方法不是那么动态,因为你需要自己定义整个类。而类本身作为一个对象可以被别人生成,Python允许手动定义类----通过使用type关键字来完成类的定义print(type(1))print(type("1"))print(type(ObjectCreator))print(type(ObjectCreator()))上面是通过type关键字检查类型,但是type还有另外一个完全不同的能力——创建类。输入类的描述参数,生成对应的类(为什么type会根据输入的参数显示两个完全不同的功能,主要是需要满足Python的向下兼容)下面是type的使用方法,需要类的名称,可能是继承的父类祖先,包含属性键值对的字典三个输入参数类型(类的名称,父类的元组(对于继承,可以为空),包含属性名称和值的字典)classMyShinyClass(object):...pass%可以用另一种方式代替:MyShinyClass=type('MyShinyClass',(),{})#返回一个类对象print(MyShinyClass)print(MyShinyClass())#创建一个instancewiththeclass<__main__.MyShinyClassobjectat0x8997cec>手动创建类时,使用MyShinyClass作为类名,同样的名字也用来引用类。这两个名字可以不同,比如a=type('MyShinyClass',....),但是没必要写的复杂。type接受一个字典来定义类中的属性classFoo(object):...bar=True%可以转化为:Foo=type('Foo',(),{'bar':True})%可以作为普通类使用:print(Foo)print(Foo.bar)Truef=Foo()print(f)<__main__.Fooobjectat0x8a9b84c>print(f.bar)True这样的类也可以继承:classFooChild(Foo):...pass%可以写成:FooChild=type('FooChild',(Foo,),{})print(FooChild)print(FooChild.bar)#bar在需要的时候继承自FooTrue给你的类添加一个方法(属性)的时候,通过函数段定义,传递给类型输入属性参数。defecho_bar(self):...print(self.bar)...FooChild=type('FooChild',(Foo,),{'echo_bar':echo_bar})hasattr(Foo,'echo_bar')Falsehasattr(FooChild,'echo_bar')Truemy_foo=FooChild()my_foo.echo_bar()True以便您可以动态地将您需要的属性添加到创建的类中。3.那么什么是元类?元类是创建类的元素。我了解到可以通过类来创建实例对象,因此可以使用元类来创建类对象,类对象是类的类。MyClass=MetaClass()my_object=MyClass()结合上面通过type创建MyClass,我们可以理解type其实是一个元类,type作为Python中所有类的元类。可以通过__class__属性查看类。Python中的一切都是对象,无论是整数、字符串、函数还是类。但是追根溯源,type是python中所有对象的元类,下面的代码解释了这个机制。age=35age.__class__name='bob'name.__class__deffoo():passfoo.__class__classBar(object):passb=Bar()b.__class__age.__class__.__class__name.__class__.__class__foo.__class__.__class__b.__class__.__class__type在里面内置,但您可以创建自己的元类。__metaclass__属性在Python2中,可以在创建类的时候给类加上一个__metaclass__属性,Python会使用这个元类属性来创建类对象FooclassFoo(object):metaclass=something...当执行classFoo(object),Python首先在__metaclass__中寻找类定义,如果有,就会用来创建类对象Foo,如果没有找到,Python会调用type方法创建类对象Foo。执行如下代码时,Python的编译过程如下:classFoo(Bar):pass判断Foo中是否有__metaclass__属性?如果是,则分配内存并使用__metaclass__属性创建一个名为Foo的类对象;如果没有找到,Python会在当前模块中寻找该属性;如果没有找到,它将使用父类Bar的元类(可能是默认类型)来创建类对象。这里需要注意的是,Foo继承自Bar,但没有继承Bar的__metaclass__属性。如果Bar使用type()作为__metaclass__机制来创建子类,那么子类就不会继承这种创建机制。在Python3.x中,元类语法不同于2.x。classFoo(object,metaclass=something):...__metaclass__属性被传递给类对象的关键字参数所取代,但元类的其他行为在很大程度上是相同的。3.x的新功能是可以根据关键字参数将属性传递给元类,如下:classFoo(object,metaclass=something,kwarg1=value1,kwarg2=value2):...4.自定义元分类器主要类的作用是在创建类的时候自动改变类的一些属性。在进行类似于调用API的操作时,需要创建相应的匹配类。例如,如果要将模块中所有类的属性名称都大写,实现这一点的方法之一是使用元类定义并设置__metaclass__。你只需要告诉元类你需要将属性转换为大写,这样在创建类对象的时候就可以自动满足了。如下一个简单示例:#元类将自动传递与您通常传递给typedefupper_attr(future_class_name,future_class_parents,future_class_attr)相同的参数#:"""返回一个类对象,其属性列表变为大写。"""#选择任何不以'__'开头且大写的属性uppercase_attr={}forname,valinfuture_class_attr.items():ifnotname.startswith('__'):uppercase_attr[name.upper()]=valelse:uppercase_attr[name]=val#lettypedotheclasscreationreturntype(future_class_name,future_class_parents,uppercase_attr)metaclass=upper_attr#thiswillaffectallclassesinthemodule注意这一步代码,会影响当前模块中的所有类classFoo():#globalmetaclass不会与“object”一起工作#但是我们可以在这里定义元类而不是只影响这个类#这将与“object”一起工作childrenbar='bip'print(hasattr(Foo,'bar'))#Out:Falseprint(hasattr(Foo,'BAR'))#Out:Truef=Foo()print(f.BAR)#Out:'bip'现在我们换成另一种方式,定义一个元类:#记住type实际上是一个像str和int这样的类#所以你可以从它继承classUpperAttrMetaclass(type):#new是在init之前调用的方法#它是创建对象并返回它的方法#而init只是初始化作为参数传递的对象#你很少使用__new__,除非你想控制对象的创建方式##这里创建的对象是类,我们想要定制它#所以我们覆盖新的#如果你愿意,你也可以在init中做一些事情#一些高级用途也涉及覆盖调用,但我们不会#看到这个def__new__(upperattr_metaclass,future_class_name,future_class_parents,future_class_attr):uppercase_attr={}forname,valinfuture_class_attr.items():ifnotname.startswith('__'):uppercase_attr[name.upper()]=valelse:uppercase_attr[name]=valreturntype(future_class_name,future_class_parents,uppercase_attr)这个方式不太符面朝象编程序的准则,这里我们直接调使用了类型法而没有重写或使用父类的__new__方法让我们来改变它:name.upper()]=valelse:uppercase_attr[name]=val#reusethetype.__new__method#这是基本的OOP,returntype.__new__(upperattr_metaclass,future_class_name,future_class_parents,uppercase_attr)在这里你会发现更多upperattr_metaclass参数,这是因为__new__方法总是接受它定义的类作为第一个参数,类似于普通类定义中的self,为简单起见可以用cls代替。通常可以使用较短的参数名称,如下所示:'__'):uppercase_attr[name.upper()]=valelse:uppercase_attr[name]=valreturntype.__new__(cls,clsname,bases,uppercase_attr)当然我们也可以使用super让类继承更简洁。类UpperAttrMetaclass(type):def__new__(cls,clsname,bases,dct):uppercase_attr={}forname,valindct.items():ifnotname.startswith('__'):uppercase_attr[name.upper()]=valelse:uppercase_attr[name]=valreturnsuper(UpperAttrMetaclass,cls).__new__(cls,clsname,bases,uppercase_attr)返回元类在Python3.x中的使用:classFoo(object,metaclass=Thing,kwarg1=value1):...%可以转换成如下:classThing(type):def__new__(class,clsname,bases,dct,kwargs1=default):...元类的引入也差不多。元类在实践中最重要的应用是生成API。典型应用是Django的ORM(转载:csdn)
