元类引入

在多数语言中,类就是一组用来描述如何生成对象的代码段,在python中同样如此,但是在python中把类也称为类对象,是的,你没听错,在这里你只要使用class关键字定义了类,其解释器在执行时就会创建一个对象,但是这个对象比较特殊,它可以创建自己的实例对象(像其他语言一样)。你可以对它进行下面的操作:

1. 你可以将它赋值给⼀个变量

2. 你可以拷⻉它

3. 你可以为它增加属性

4. 你可以将它作为函数参数进⾏传递

动态创建类

听起来python在这方面跟一些语言的差别了吧,没错它还可以在运行时动态地创建它们,你可以在函数中创建类,用class关键字即可。

def choose_class(name):
if name == 'foo':
class Foo(object):
pass
return Foo # 返回的是类, 不是类的实例
else:
class Bar(object):
pass
return Bar

如果你想知道python中的变量或者数值的类型,你可以用万能而强大的type,如下(注意它们的返回值)

>>> print type(1) #数值的类型
<type 'int'>
>>> print type("1") #字符串的类型
<type 'str'>
>>> print type(ObjectCreator()) #实例对象的类型
<class '__main__.ObjectCreator'>
>>> print type(ObjectCreator) #类的类型
<type 'type'>

使用type创建类

创建格式:type(类名, 由⽗类名称组成的元组( 针对继承的情况, 可以为空) ,包含属性的字典( 名称和值) )
可以⼿动像这样创建:
Test2 = type("Test2",(),{}) #定了⼀个Test2类
In [5]: Test2() #创建了⼀个Test2类的实例对象
Out[5]: <__main__.Test2 at 0x10d406b38>

上面等价于

class Test2:
pass

使⽤type创建带有属性的类

Foo = type('Foo', (), {'bar':True})

可以翻译为

>>> class Foo(object):
… bar = True

这个类跟普通创建的类一样使用,如继承这个类,你可以用下面的方法

>>> FooChild = type('FooChild', (Foo,),{})
>>> print FooChild
<class '__main__.FooChild'>
>>> print FooChild.bar # bar属性是由Foo继承⽽来
True

同样等价于

>>> class FooChild(Foo):
… pass

注意:添加的属性都是类属性,第二个参数是继承自哪儿,采用元组的形式,也要知道在python中元组中只有一个参数表示方法只能是(xx,),而不能是(xx)

使⽤type创建带有⽅法的类

如果你想为你的类增加方法,那么你创建一个签名函数,然后添加其为属性赋值即可。

添加实例方法

In [46]: def echo_bar(self): #定义了⼀个普通的函数
...: print(self.bar)
...:
In [47]: FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
In [48]: hasattr(Foo, 'echo_bar') #判断Foo类中, 是否有echo_bar这个属性
Out[48]: False
In [49]:
In [49]: hasattr(FooChild, 'echo_bar') #判断FooChild类中, 是否有echo_bar这个
Out[49]: True
In [50]: my_foo = FooChild()
In [51]: my_foo.echo_bar()
True

添加类方法

In [42]: @classmethod
...: def testClass(cls):
...: print(cls.bar)
...:
In [43]:
In [43]: Foochild = type('Foochild', (Foo,), {"echo_bar":echo_bar,"testClass":testClass})
In [44]:
In [44]: fooclid = Foochild()
In [45]: fooclid.testClass()
True

添加静态方法

In [36]: @staticmethod
...: def testStatic():
...: print("static method ....")
...:
In [37]: Foochild = type('Foochild', (Foo,), {"echo_bar":echo_bar,“testStatic”:testStatic})
In [38]: fooclid = Foochild()
In [39]: fooclid.testStatic
Out[39]: <function __main__.testStatic>
In [40]: fooclid.testStatic()
static method ....
In [41]: fooclid.echo_bar()
True

看到这么多实现动态类的方法,你该明白python是怎么做到的,在这里就涉及到元类,元类就是用来创建类的东西,而创建类就是为了创建类的实例对象,所以可以这样理解,元类就是为了创建类对象的,而type实际上就是一个元类,传统类的元类就是types.classType,在python中元类的介绍中也介绍了元类,有兴趣的读者可以去看看。

SO,结论就是Python中所有的东⻄, 注意, 我是指所有的东⻄——都是对象。 这包括整数、 字符串、 函数以及类。 它们全部都是对象,⽽且它们都是从⼀个类创建⽽来, 这个类就是type。

__metaclass__属性

你也可以定义自己的元类,用到的就是上面的属性,首先,你可以在定义⼀个类的时候为其添加__metaclass__属性。
class Foo(object):
__metaclass__ = something…
#...省略...

那么当python解释器看到下面代码时

class Foo(Bar):
pass

python做了如下的操作:

1. Foo中有__metaclass__这个属性吗? 如果是, Python会通过__metaclass__创建⼀个名字为Foo的类(对象)

2. 如果Python没有找到__metaclass__, 它会继续在Bar( ⽗类) 中寻找__metaclass__属性, 并尝试做和前⾯同样的操作。

3. 如果Python在任何⽗类中都找不到__metaclass__, 它就会在模块层次中去寻找__metaclass__, 并尝试做同样的操作。

4. 如果还是找不到__metaclass__,Python就会⽤内置的type来创建这个类对象。

在这个__metaclass__中可以放一些什么代码呢?------可以做任何涉及到类操作的事情,用type或者其子类来完成。
下面是用自定义类来当做元类
#coding=utf-8
class UpperAttrMetaClass(type):
# __new__ 是在__init__之前被调⽤的特殊⽅法
# __new__是⽤来创建对象并返回之的⽅法
# ⽽__init__只是⽤来将传⼊的参数初始化给对象
# 你很少⽤到__new__, 除⾮你希望能够控制对象的创建
# 这⾥, 创建的对象是类, 我们希望能够⾃定义它, 所以我们这⾥改写__new__
# 如果你希望的话, 你也可以在__init__中做些事情
# 还有⼀些⾼级的⽤法会涉及到改写__call__特殊⽅法, 但是我们这⾥不⽤
def __new__(cls, future_class_name, future_class_parents, future_clas
#遍历属性字典, 把不是__开头的属性名字变为⼤写
newAttr = {}
for name,value in future_class_attr.items():
if not name.startswith("__"):
newAttr[name.upper()] = value
# ⽅法1: 通过'type'来做类对象的创建
# return type(future_class_name, future_class_
parents, newAttr)
# ⽅法2: 复⽤type.__new__⽅法
# 这就是基本的OOP编程, 没什么魔法
# return type.__new__(cls, future_class_name, future_class_parent
# ⽅法3: 使⽤super⽅法
return super(UpperAttrMetaClass, cls).__new__(cls, future_class_n
#python2的⽤法
class Foo(object):
__metaclass__ = UpperAttrMetaClass
bar = 'bip'
# python3的⽤法
# class Foo(object, metaclass = UpperAttrMetaClass):
# bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'
其实简单地来讲,python中的元类用处一般就是下面三个

1. 拦截类的创建

2. 修改类

3. 返回修改之后的类

哈哈,我想说的是对于元类咱们99%的人不会用到。

最新文章

  1. [Cordova] 无法编译Visual Studio项目里Plugin副本的Native Code
  2. friend class
  3. EF中限制字段显示长度
  4. jdk 1.5
  5. 配置nginx,支持php的pathinfo路径模式
  6. HDU5047Sawtooth(java大数)
  7. Java 5 的新标准语法和用法详解集锦
  8. c# 面相对象3-之继承性
  9. 在PADS LAYOUT中修改所有元件字体的大小,怎么修改?
  10. RabbitMQ安装记录(CentOS)
  11. Java多线程基础(二)
  12. SQL Server 中如何做到连续时间段的拆分?
  13. .net core 使用IIS作为宿主Web服务器,部署常见问题
  14. 将jar包安装到本地repository中
  15. vue 深拷贝
  16. Qt5 在添加 Q_OBJECT 后发现编译出错的原因
  17. css控制继承
  18. LeetCode(79): 单词搜索
  19. (mysql数据库报错)The user specified as a definer (&#39;root&#39;@&#39;%&#39;) does not exist
  20. kafka讲解

热门文章

  1. C#/VB.NET 给Excel添加、删除数字签名
  2. 【老孟Flutter】6种极大提升Flutter开发效率的工具包
  3. 论文解读 - Relational Pooling for Graph Representations
  4. HTML图片点击放大---关闭
  5. ptmalloc tcmalloc jemalloc 总结的总结 及覆盖原理
  6. ceph写osd的配置文件/etc/ceph/ceph.conf
  7. 自动化测试_移动端测试(一) ----- Appium环境搭建
  8. C语言复习系列-转义字符
  9. Poem Codes - 攻防世界(Decrypt-the-Message)
  10. 精益求精!Spring Boot 知识点全面回顾,带你重新细读源码!