龙空技术网

python元类介绍-看懂了,你就完全明白了python中的类

HyRer 69

前言:

目前你们对“python经典类”大概比较关切,小伙伴们都需要剖析一些“python经典类”的相关内容。那么小编也在网络上汇集了一些有关“python经典类””的相关文章,希望姐妹们能喜欢,各位老铁们一起来学习一下吧!

本文很烧脑,建议将本文中的代码敲一遍运行看看

Python中的类

记住一句话:在Python中万事万物皆对象

python中的类也是对象,当一个对象具有创建对象的能力时,就称该对象为类。既然类也是对象,那他就有一下属性

可以将它赋值给其他变量可以给他添加属性它可以作为函数的参数传递以及作为返回值返回

class Person(object):    def __init__(self,name):        self.name = name    def say(self):        print('hello,{}'.format(self.name))# 赋值给其他变量xm = Personxiaomigng = xm('xiaoming')print(xiaomigng.name)xiaomigng.say()# 添加属性print(hasattr(Person, 'country'))Person.country = 'china'print(hasattr(Person, 'country'))
类的几个常用方法
class Person(object):    def __init__(self, name, age):        self.name = name        self.age = age        print(self)        print('this is __init___')    def __call__(self, *args, **kwargs):        print('this is __call___')    def __new__(cls, name, age):        print(cls)        print('this is __new___')        return super(Person, cls).__new__(cls)person = Person('ctz', 22)person()'''<class '__main__.Person'>this is __new___<__main__.Person object at 0x00000286F4C70E80>this is __init___this is __call___'''
__ new __方法

__ new __ 方法接受的参数和 __ init __ 一样,但 __ init __ 是在类实例创建之后调用,而 __ new __ 方法正是创建这个类实例的方法。 __ init __ 方法里面的self 实际就是 __ new __ 所创建的实例, __ new __ 返回值就是创建的实例,属于类级别的方法

__ init __ 方法

.__ init __ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。无返回值

__ call __ 方法

构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于

__ call __ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()使用type动态的创建类

type是所有新式类的类,所有类都可以说是type创建的

object是所有新式类的父类

print(object.__class__)print(object.__bases__)print(object.__class__)print(type.__bases__)'''<class 'type'>   # object类是一个type元类所创建()               # 说明 object类已经处于继承链条的顶端,是所有类的父类。<class 'type'>   #   type自身的类就是type,就是说type元类也就是由type自身创建的。(<class 'object'>,)   # type这一元类的父类是object。'''
type动态创建类

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

def say(self):  print('hello,{}' .format(self.name))def sayChinese(self):  print('你好,{}'.format(self.name))address = input('input your country:').strip()name = input('your name:').strip()dic = {}dic['name'] = nameif address == 'china':  dic['country'] = '中国'  dic['say'] = sayChineseelse:  dic['county'] = 'other'  dic['say'] = sayPerson = type('Person', (object,), dic)print(Person)person = Person()print(person.name)person.say()
也可以继承其他类
class Animal(object):    def __init__(self, name, age):        self.name = name        self.age = age    def walk(self):        print('{} is walking'.format(self.name))def eat(self):    print('{} is eatting'.format(self.name))Dog = type('Dog', (Animal,), {'eat': eat})dog = Dog('aa', 2)print(dog.name)dog.eat()dog.walk()
Python中的元类

元类就是用来创建这些类(对象)的,元类就是类的类,我们上面用了type来创建类,因为type就是一个元类,我们可以看下面代码

a = 5b = 'bb'c = Truedef fun():    passclass Person(object):    def __init__(self, name, age):        self.name = name        self.age = ageprint(a.__class__.__class__)print(b.__class__.__class__)print(fun.__class__.__class__)print(Person.__class__)'''<class 'type'><class 'type'><class 'type'><class 'type'>'''

type就是Python在背后用来创建所有类的元类

__ metaclass __ 属性

class Foo(object):    __metaclass__ = something…

Python就会用元类来创建类Foo。首先我们写下class Foo(object),但是类对象Foo还没有在内存中创建。Python会在类的定义中寻找metaclass属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类

class Foo(Bar):    pass

Python做了如下的操作:

Foo中有 __ metaclass __ 这个属性吗?如果是,Python会在内存中通过__ metaclass __创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到 __ metaclass __,它会继续在Bar(父类)中寻找 __ metaclass __属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到 __metaclass __,它就会在模块层次中去寻找 __metaclass __,并尝试做同样的操作。如果还是找不到 __ metaclass __,Python就会用内置的type来创建这个类对象。

现在的问题就是,你可以在 __ metaclass __中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。

# 1.对象是类创建,创建对象时候类的__new__和__init__方法自动执行,对象()执行类的 __call__ 方法# 2.类是type创建,创建类时候type的__new__,__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)# 第0步: 执行type的 __new__和__init__ 方法【类是type的对象】class Foo(object):    def __init__(self):        print('类的__init__')        pass    def __call__(self, *args, **kwargs):        print('类的__call__')        pass# 第1步: 执行type的 __call__ 方法#        1.1  调用 Foo类(是type的对象)的 __new__方法,用于创建对象。#        1.2  调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。obj = Foo()# 第2步:执行Foo类 __call__ 方法obj()
示例一
class MyType(type):    def __init__(self, *args, **kwargs):        print('MyType创建类__init__',self)        super(MyType, self).__init__(*args, **kwargs)    def __call__(self, *args, **kwargs):        obj = super(MyType, self).__call__(*args, **kwargs)        print('类创建对象__init__', self, obj)        return obj    def __new__(cls, *args, **kwargs):        print('Mytype __new__', cls)        return super(MyType, cls).__new__(cls, *args, **kwargs)class Foo(object,metaclass=MyType):    user = 'ctz'    age = 18obj = Foo()'''Mytype __new__ <class '__main__.MyType'>MyType创建类 <class '__main__.Foo'>类创建对象 <class '__main__.Foo'> <__main__.Foo object at 0x00000227D23BE630>
示例二
class MyType(type):    def __init__(self, *args, **kwargs):        print('MyType __init__', self, '----')        super(MyType, self).__init__(*args, **kwargs)    def __call__(cls, *args, **kwargs):        v = dir(cls)        obj = super(MyType, cls).__call__(*args, **kwargs)        print('MyType __call__', cls, obj, '****')        return obj    def __new__(cls, *args, **kwargs):        print('Mytype __new__',cls)        return super(MyType,cls).__new__(cls, *args, **kwargs)class Foo(MyType('Bar', (object,), {})):    user = 'ctz'    age = 18    def __init__(self, *args, **kwargs):        super(Foo, self).__init__(*args, **kwargs)obj = Foo()print(Foo.__bases__)print(Foo.__class__)'''D:\Python36\python.exe D:/test/python高效编程技巧/元类介绍/元类示例2.pyMytype __new__ <class '__main__.MyType'>MyType __init__ <class '__main__.Bar'> ----Mytype __new__ <class '__main__.MyType'>MyType __init__ <class '__main__.Foo'> ----MyType __call__ <class '__main__.Foo'> <__main__.Foo object at 0x0000016BE87DEAC8> ****(<class '__main__.Bar'>,)<class '__main__.MyType'>'''

上述相当于我们用MyType创建了一个类Bar,然后用Foo继承Bar,当创建Foo类的时候我们在Foo中找不到__ metaclass __ 属性,再去Bar里面找,Bar里面的 __ metaclass __指向MyType,所以MyType也是Foo的元类,用它来创建Foo

示例三

class MyType(type):    def __init__(self, *args, **kwargs):        print(self,'------')        super(MyType, self).__init__(*args, **kwargs)    def __call__(cls, *args, **kwargs):        v = dir(cls)        obj = super(MyType, cls).__call__(*args, **kwargs)        print(cls,obj,'****')        return objdef with_metaclass(arg,base):    return MyType('MyType', (base,), {})class Foo(with_metaclass(MyType,object)):    user = 'ctz'    age = 18obj = Foo()'''<class '__main__.MyType'> ------<class '__main__.Foo'> ------<class '__main__.Foo'> <__main__.Foo object at 0x000001FBD9E63710> ****'''

这种和上面第二种没啥区别,知识封装了一下,不过查看Flask,wtforms源码可知,实例化Form就是通过这种方法做的

wtforms源码参考

def with_metaclass(meta, base=object):    return meta("NewBase", (base,), {})class Form(with_metaclass(FormMeta, BaseForm)):    """    Declarative Form base class. Extends BaseForm's core behaviour allowing    fields to be defined on Form subclasses as class attributes.    In addition, form and instance input data are taken at construction time    and passed to `process()`.    """    Meta = DefaultMeta    def __init__(self, formdata=None, obj=None, prefix='', data=None, meta=None, **kwargs):        """        :param formdata:            Used to pass data coming from the enduser, usually `request.POST` or            equivalent. formdata should be some sort of request-data wrapper which            can get multiple parameters from the form input, and values are unicode            strings, e.g. a Werkzeug/Django/WebOb MultiDict        :param obj:            If `formdata` is empty or not provided, this object is checked for            attributes matching form field names, which will be used for field            values.        :param prefix:            If provided, all fields will have their name prefixed with the            value.        :param data:            Accept a dictionary of data. This is only used if `formdata` and            `obj` are not present.        :param meta:            If provided, this is a dictionary of values to override attributes            on this form's meta instance.        :param `**kwargs`:            If `formdata` is empty or not provided and `obj` does not contain            an attribute named the same as a field, form will assign the value            of a matching keyword argument to the field, if one exists.        """        meta_obj = self._wtforms_meta()        if meta is not None and isinstance(meta, dict):            meta_obj.update_values(meta)        super(Form, self).__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
元类实现单例模式
import threadingclass Singleton(type):    _instance_lock = threading.Lock()  # 为了实现支持多线程的单例模式    def __call__(cls, *args, **kwargs):        with cls._instance_lock:            if not hasattr(cls,'_instance'):                cls._instance=super(Singleton, cls).__call__(*args, **kwargs)        return cls._instanceclass Foo(metaclass=Singleton):    def __init__(self, name):        self.name = nameobj1 = Foo('ctz')obj2 = Foo('ztc')print(obj1, obj2)'''<__main__.Foo object at 0x000002155BBDE940> <__main__.Foo object at 0x000002155BBDE940>'''
自定义元类

示例1

class UpperTest(type):    def __new__(cls, myclass, parentclass, myattrs):        attrs = ((name, value) for name, value in myattrs.items() if not name.startswith('__'))        attrs_dic = dict((k.upper(), v) for k, v in attrs)        return type(myclass, parentclass, attrs_dic)class MyTest(object, metaclass=UpperTest):    name = 'ctz'    age = 22print(hasattr(MyTest, 'name'))print(hasattr(MyTest, 'age'))print(hasattr(MyTest, 'NAME'))print(hasattr(MyTest, 'AGE'))'''D:\Python36\python.exe D:/test/python高效编程技巧/元类介绍/自定义元类1.pyFalseFalseTrueTrue'''

示例2

class MetaList(type):    def __new__(cls, myclassname, myparentname,attrs):        attrs['add'] = lambda self, value: self.append(value)        return type.__new__(cls, myclassname, myparentname, attrs)class MyList(list, metaclass=MetaList):    passl = MyList()l.add(1)l.add(2)print(l)

标签: #python经典类