Python学习——元类

元类

  MetaClass(元类),元类创建了Python中所有的对象。简单的理解,就是创建类的类,即创建类之后,再由类来创建实例进行应用。使用元类可以在创建类时动态修改类定义。为了使用元类动态修改类定义,程序需要先定义元类。简单理解为:元类就是用来创建类的东西
  注意,不要从字面上去理解元类的含义,事实上,MetaClass 中的 Meta 这个词根,起源于希腊语词汇 meta,包含“超越”和“改变”的意思。
  在python 中 类同样表示一种对象,这个对象拥有创建对象(创建实例)的能力, 它本质是一个对象,于是乎,可以对它做如下操作

  • 1、可以将它赋值给一个变量
    2、可以拷贝它
    3、可以为它增加属性
    4、可以将他作为函数的属性传递
动态创建类

因为类也是对象,所以可以再运行的时候创建他们,就像其他任何对象一样,可以在函数中创建类,使用关键字即可

def create_class(name):
    if name == "foo":
        class Foo(object):  # 当使用class关键字时,Python解释器自动创建这个对象。
            pass
        return Foo  # 返回的是类  不是实例
    else:
        class Bar():
            pass
        return Bar

myClass = create_class("foo")
print(myClass)  # <class '__main__.create_class.<locals>.Foo'>
my = myClass()  # 创建实例对象
print(my)  # <__main__.create_class.<locals>.Foo object at 0x0000022B9C5AA390>
type 回顾
查看类型
print(type(1))   # <class 'int'>
print(type("aaa")) # <class 'str'>
print(type(myClass)) # <class 'type'>   
print(type(my)) #<class '__main__.create_class.<locals>.Foo'>
# 可以发现  type(myClass) 的类型为 type    继续测试
class aaa(object):
    pass
class bbb(object):
    pass
print(type(aaa)) # <class 'type'>
print(type(bbb)) # <class 'type'>

# 可以发现 通过 type 查看所有的类的类型  都是 type 类型
type 的另一个作用
  •  动态创建类
     type可以接受一个类的描述作为参数,返回一个类
     格式:type(类名,由父类名称组成的元祖(针对继承的情况 可以为空),包含属性的字典(名称和值))
     例:
ccc = type("Ccc",(),{"name":"chase"})
print(ccc) # <class '__main__.Ccc'>
print(ccc().name)   # chase
print(type(ccc))  # <class 'type'>
help(ccc)  # 使用help 查看ccc类  输出结果如下

"""
Help on class Ccc in module __main__:

class Ccc(builtins.object)
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  name = 'chase'
"""

使用创建带由父类的示例

ccc = type("Ccc",(),{"name":"chase"})
ddd = type("Ddd",(ccc,),{})  # type中的第二个参数是父类的引用名称,不是字符串
class Eee(object):
    eName = "EEE"
    pass
fff = type("Fff",(Eee,),{"name":"FFF"})
print(fff.eName) # EEE
print(fff.name)  # FFF
help(fff)
"""
Help on class Fff in module __main__:

class Fff(Eee)
 |  Method resolution order:
 |      Fff
 |      Eee
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  
 |  name = 'FFF'
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Eee:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Eee:
 |  
 |  eName = 'EEE'
"""

使用type 创建带有方法的类

def run(self):
    print("实例方法")

@staticmethod
def static_run():
    print("静态方法")

@classmethod
def class_run(cls):
    print("类方法,name为:%s" % cls.name)

Foo = type("Foo",(),{"name":"fooName","run":run,"static_run":static_run,"class_run":class_run})
foo = Foo()
foo.run() # 实例方法
foo.static_run() # 静态方法
Foo.class_run() # 类方法,name为:fooName
help(Foo)
"""
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |  
 |  run(self)
 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  class_run() from builtins.type
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  static_run()
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  name = 'fooName'
"""
type 元类

函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
元类就是创建类这种对象的东西。type就是Python的内建元类,当然了,你也可以创建自己的元类。

__metaclass__属性

当执行如下代码时间

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__。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。
幸运的是,__metaclass__实际上可以被任意调用,它并不需要是一个正式的类。所以,我们这里就先以一个简单的函数作为例子开始。
来源:网络

  • python2 中
#-*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):

    # class_name 会保存类的名字 Foo
    # class_parents 会保存类的父类 object
    # class_attr 会以字典的方式保存所有的类属性

    # 遍历属性字典,把不是__开头的属性名字变为大写
    new_attr = {}
    for name, value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()] = value

    # 调用type来创建一个类
    return type(class_name, class_parents, new_attr)

class Foo(object):
    __metaclass__ = upper_attr # 设置Foo类的元类为upper_attr
    bar = 'bip'

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

f = Foo()
print(f.BAR)
  • python3中
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

    #调用type来创建一个类
    return type(class_name, class_parents, new_attr)

class Foo(object, metaclass=upper_attr):
    bar = 'bip'

print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True
f = Foo()
print(f.BAR) # bip
  • 用一个真正的class来当做元类。
class UpperAttrMetaClass(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):
    bar = 'bip'

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


print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:'bip'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值