简要

  • python中所有创建的类都是由元类(type)创建而来。
  • class 创建一个类,和用type()创建没有区别。
  1. type(参数1(str), 参数2(tuple), 参数3(dict)),参数名意义:类名,父类,属性及方法名的引用。
  2. type()一般看来是判断数据类型的作用,在python中,传入参数数量不同所做的事情不同(目的不同),本身是一件很傻的行为。但是python的开发者们肯定是有自己的考虑,所以就只能这样了。
  • 创建类的时候有 metaclass这样一个参数(在python2中它是一个魔法属性),这个参数可以是一个函数也可以是一个类,参数对应的函数或者类可以理解为“元类”(我们自己可以指定),默认是type。
  • 理解元类及为什么要自定义元类,可以参考装饰器(装饰器文章链接)
  • 可以用一个函数充当“元类”(参考代码片1)
  • 也可以用类来充当元类。(参考代码片2)

代码1:函数当元类

# -*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):
    '''把类中的属性名都变成大写'''
    # 遍历属性字典,把不是__开头的属性名字变为大写
    new_attr = {}
    for name, value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()] = value # upper(): 小写字母变为大写

    # 调用type来创建一个类
    return type(class_name, class_parents, new_attr)  # 参数名意义(类名,父类,属性及方法名的引用) 


class Foo(object, metaclass=upper_attr):  # metaclass :创建类的函数。默认是type()
    bar = 'bip'


print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))

f = Foo()
print(f.BAR)
# print(f.bar)

# 元类起到的作用是 在创建基本类之前,多添加点自己想要的“东西”(对比于装饰器而言,这是给类加功能,装饰器是给执行函数之前加功能)

代码2:类来当元类

# coding=utf-8
class UpperAttrMetaClass(type):  # 继承type类
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回之的方法
    # 而__init__只是用来将传入的参数初始化给对象
    # 你很少用到__new__,除非你希望能够控制对象的创建(比如单例)
    # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
    def __new__(cls, class_name, class_parents, class_attr):
        # 遍历属性字典,把不是__开头的属性名字变为大写
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value

        # 方法1:通过'type'来做类对象的创建
        return type(class_name, class_parents, new_attr)

        # 方法2:复用type.__new__方法
        # 这就是基本的OOP编程,没什么魔法。
        # return type.__new__(cls, class_name, class_parents, new_attr)


# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):  # 分配空间的时候就会调用__new__方法,达到“元类”的功能
    bar = 'bip'


# python2的用法
# class Foo(object):
#     __metaclass__ = UpperAttrMetaClass
#     bar = 'bip'


print(hasattr(Foo, 'bar'))  # hasattr() 函数用于判断对象是否包含对应的属性。
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:'bip'

补充

不要过分纠结元类,当你纠结的时候,说明你根本就用不到它(这不是我说的,是那个谁谁谁说的-。-)