课后练习 第一阶段:Python开发基础 day29 面向对象相关练习第一题

1.什么是元类

在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类,即元类可以简称为类的类

type是内置的一个元类,所有的类都是由type实例化得到,type类是产生所有类的元类

# 先class 一个类
class Person:
    def __init__(self,name):
        self.name = name

# 用刚才的类实例化一个对象
forever = Person('forever')

# 打印一下这个实例化对象的类型
print(type(forever))  # <class '__main__.Person'>
print(type(Person))   # <class 'type'>

运行结果:

<class 'main.Person'>
<class 'type'>

一切皆对象,对象也可以是类,从我们这打印的结果可以看出来,Person的元类就是type

2.Class底层原理实现

  • 创建类的3个要素:类名,基类,类的名称空间

  • People = type(类名,基类,类的名称空间)

  • type(object_or_name, bases, dict)
    
  • 通过type来直接产生类,不用class关键字了

代码:

dic = {}
exec(
'''
def __init__(self,name,age):
    self.name = name
    self.age = age
def ku(self):
    print('forever kukudi')   
''',{},dic
)
# 定义一个类
Forever = type('Forever',(object,),dic)
# 实例化一个对象
forever = Forever('forever',18)
# 取出类中的值
print(f'''forever`s name:{forever.name} forever`s age :{forever.age}''')
# 打印类的父类
print(Forever.__bases__)

运行结果:

forever`s name:forever forever`s age :18
(<class 'object'>,)

3.自定义元类控制类的产生

可以控制类名,可以控制类的继承父类,控制类的名称空间

自定义元类必须继承type,写一个类继承type 这种类都叫元类

代码如下:

class MyClass(type):
    def __init__(self,name,bases,dic):
        print(name)
        if 'name' not in name.lower():
            raise Exception('类名中没有name字段')

class MyDemo(object,metaclass=MyClass):
    def __init__(self,name):
        self.name = name

输出结果:

MyDemo
报错信息:
raise Exception('类名中没有name字段')
Exception: 类名中没有name字段

不报错的定义代码:

class Name(object,metaclass=MyClass):
    def __init__(self,name):
        self.name = name

运行结果:

Name

4.自定义元类控制类的执行过程

_call_

控制类的调用过程,实际上在控制:对象的产生

程序代码:

class MyClass(type):
    def __call__(self, *args, **kwargs):
        obj=object.__new__(self)
        obj.__init__(*args, **kwargs)

        obj.__dict__={ '_%s__%s'%(self.__name__,k):v for k,v in obj.__dict__.items()}

        return obj

class MyDemo(object, metaclass=MyClass):
    def __init__(self, name):
        self.name = name

demo = MyDemo(name='forever')
print(demo.__dict__)
print(demo.name)
print(demo._MyDemo__name)

运行结果:

print(demo._MyDemo__name)

{'_MyDemo__name': 'forever'}
forever

print(demo.name)

Traceback (most recent call last):
{'_MyDemo__name': 'forever'}
File "F:/shpython11/pycharmwork/first_project/study_start/day29/homework.py", line 75, in
print(demo.name)
AttributeError: 'MyDemo' object has no attribute 'name'

5.属性查找

  • 类的属性查找顺序:先从类本身中找--->mro继承关系去父类中找---->去自己定义的元类中找--->type中--->报错
  • 对象的属性查找顺序:先从对象自身找--->类中找--->mro继承关系去父类中找--->报错

程序代码:

class Mymeta(type):
    n=444

    def __call__(self, *args, **kwargs): #self=<class '__main__.OldboyTeacher'>
        obj=self.__new__(self)
        # print(self.__new__ is object.__new__) #True
        obj.__init__(*args, **kwargs)
        return obj


class Bar(object):
    # n=333
    pass

    # def __new__(cls, *args, **kwargs):
    #     print('Bar.__new__')

class Foo(Bar):
    # n=222
    pass

    # def __new__(cls, *args, **kwargs):
    #     print('Foo.__new__')

class OldboyTeacher(Foo,metaclass=Mymeta):
    # n=111

    school='oldboy'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s says welcome to the oldboy to learn Python' %self.name)


    # def __new__(cls, *args, **kwargs):
    #     print('OldboyTeacher.__new__')


o=OldboyTeacher('forever',18) #触发OldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找
print(OldboyTeacher.n)
posted @ 2019-09-03 18:21  foreversun92  阅读(212)  评论(0编辑  收藏  举报