参考 点击打开链接
在python中类也是一个对象,创建类的几种方法
(1)可以在运行时动态创建,就像其他任何对象一样。
首先,在函数中创建类,然后返回类,后面的其他地方可以调用这个函数来返回这个类,赋值给类名,再根据这个类名实例化对象。
(2)内建函数type的另外一种用法,他可以动态创建类,
type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
Foo = type('Foo', (), {'bar':True})
FooChild = type('FooChild', (Foo,),{}) #继承了Foo类
这里type实际就是一个元类,就是Python在背后创建所有类对象的元类,其他的类实际就是元类的实例化对象。
str是用来创建字符串对象的类,Int是用来创建整数对象的类,type就是用来创建类对象的类。
Python中所有的东西,注意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来。
__class__指的应该是显示某个一对象的类的名称,比如:
age = 35 name = 'bob'
age.__class__ name.__class__
<type 'int'> <type 'str'>
对于任何一个__class__的__class__属性都可以看到是 age.__class__.__class__ 都是<type 'type'>
因此,元类就是创建这种type这样的东西,可以将元类叫做‘类工厂’,type就是python的内建元类。
我们所需要做的就是创建自己数据库的元类,因为后面的每一个表对应一个类,再由这个对象实例具体的表(对象),这里用来创建的类和内置的类不太一样,不能只是单纯的继承内置的type元类,应该自己设计自己的元类。
(3)创建元类
__metaclass__的使用
class Foo(object):
__metaclass__ = something...
上面的这段代码,产生的效果是用元类来创建Foo。当写下class Foo(object):时,类对象Foo还没有在内存中创建。python会在类的定义(在哪里)中寻找metaclass属性,如果找到了,就用它创建类Foo,如果没有找到,就会用内建的type来创建这个类。
class Foo(Bar):
pass
上面的代码python做了如下操作,查看Foo中有没有__metaclass__属性,如果有,python会在内存中通过__metaclass__创建一个名为Foo的类对象。如果python没有找到,他会在Bar(父类)中继续寻找__metaclass__属性。如果在任何一个父类中都找不到。它就会在模块层次去寻找__metaclass__,并尝试做同样操作。如果还是找不到,就会用内置的type来创建这个类对象。
所以当我们定义映射表的类时,这个类和一般创建类的方法不一样,他要通过专门的__metaclass__创建这个类对象。所以会在__metaclass__后面指示也就是元类的名称,这样现在创建的这个class就会根据元类来创建。创建类都比较简单,所以我们需要做的就是创建这个元类。也就是__metaclass__后面的这个里面放置的代码。就是type,或者任何使用type或者子类化type的东东都可以。
__metaclass__ = upper_attr # 这会作用到这个模块中的所有类,upper_attr方法是将所有类的属性的名称都改为大写
class Foo(object):
# 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中
bar = 'bip'
这里就是所有的类方法都会使用__metaclass__后的upper_attr方法,这里方法就是元类,不过元类并不需要是一个正式的类,所以比如这里可以是一个方法。
__new__是在__init__之前调用的特殊方法,是用来创建类对象并返回修改之后的方法,如果希望能够控制对象的创建(比如创建的类中的属性小写改为大写,比如为要创建的类对象增加属性方法),这个创建的对象是类,我们希望自定义他,就需要改写__new__。
关于__new__中的几种不同的返回方式,返回后的就是修改之后的创建类的方式,
1、return type(future_class_name, future_class_parents, uppercase_attr),type是父类,这样是直接调用了type,并且没有改写父类的__new__方法。没有OOP编程的思想。
2、return type.__new__(upperattr_metaclass,future_class_name, future_class_parents, uppercase_attr)这个就是加了一个额外的参数,upper_metaclass,类方法的第一个参数总是表示当前的实例,就像在普通的类方法中的self参数一样。当然了,为了清晰起见,这里的名字我起的比较长。但是就像self一样,所有的参数都有它们的传统名称。因此,在真实的产品代码中一个元类应该是像这样的:
3、return type.__new__(cls,name,bases,uppercase_attr)这也是通常定义一个元类需要传入的参数,
cls:当前准备创建的类的对象;所以上面才说第一个参数表示当前的实例。
name:类的名字;就是当前的实例的名字,这个实例是一个类。
base:类继承的父类的集合,是作为这个实例的一个传入参数
attr:类的方法的集合
4、return super(UpperAttrMetaclass,cls).__new__(cls,name,bases,uppercase_attr)使用super方法的话,我们还可以使它变得更清晰一些,这会缓解继承(是的,你可以拥有元类,从元类继承,从type继承)
元类的作用:
1) 拦截类的创建
2) 修改类
3) 返回修改之后的类
元类就是在类的定义的最开始做个标记__metaclass__,表示在创建这个类的实例对象的时候去查找这个属性后面的方法、函数、类,去修改这个类,比如增加些类的方法或者修改些类的方法,修改后再返回修改之后的类。
(4)为什么用元类
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters
元类主要用处是创建API。一个典型的例子是Django ORM。见Dajongo学习—没看
(5)动态修改类
虽然元类可以修改类的定义,但是大多数情况下,没有像需要大量使用这种元类的时候,可以通过使用以下两种技术修改类:
2) class decorators