day29学习整理-Python面向对象(进阶)

2019/09/03 学习整理

python面向对象(进阶)

一、元类

1.什么是元类?

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

Person类也是个对象,那他一定是由一个类实例化得到,这个类,就叫元类
type是内置的一个元类,所有的类都是由type实例化得到

2.为什么用元类?

  • 元类是负责产生类的,所以我们学习元类或者自定义元类的目的:是为了控制类的产生过程,还可以控制对象的产生过程
    就元类本身而言,它们其实是很简单的:

1)   拦截类的创建

2)   修改类

3)   返回修改之后的类

元类主要适用于以下场合:

值的域限制
隐式转换自定义类的值(您可能希望向用户隐藏编写类的所有这些复杂方面)
执行不同的命名约定和样式准则(比如,“每种方法都应有一个文档字符串”)
向类添加新的属性

3.如何找到元类

print(type(p))
#同理:type类是产生所有类的元类

二、class底层原理分析

class 类名 会把类构造出来
实际上是:元类实例化产生类 这个对象
类实例化产生对象,一定是: 类名()
Person 类是由type实例化产生,传一堆参数
type() 调用类的__init__方法

type()语法

type(object_or_name, bases, dict)
object_or_name:类的名字,是个字符串
bases:是它的所有父类,基类
dict:名称空间,是一个字典

通过type来直接产生类,不用class关键字了

补充:内置函数exec

cmd = """
x=1
print('exec函数运行了')
def func(self):
    pass
"""
class_dic = {}
# 执行cmd中的代码,然后把产生的名字丢入class_dic字典中
exec(cmd, {}, class_dic)


#  exec函数运行了


print(class_dic)


#  {'x': 1, 'func': <function func at 0x10a0bc048>}

class 底层就是调用type来实例化产生类(对象)

class People:  # People=type(...)
    country = 'China'

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

    def eat(self):
        print('%s is eating' % self.name)
print(type(People))
 #  <class 'type'>

三、通过元类来控制类的产生

自定义元类 ;来控制类的产生:可以控制类名,可以控制类的继承父类,控制类的名称空间

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        print(self)  # self是People
        print(args)  # args = ('nick',)
        print(kwargs)  # kwargs = {'age':18}
        # return 123
        # 1. 先造出一个People的空对象,申请内存空间
        # __new__方法接受的参数虽然也是和__init__一样,但__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
        obj = self.__new__(self)  # 虽然和下面同样是People,但是People没有,找到的__new__是父类的
        # 2. 为该对空对象初始化独有的属性
        self.__init__(obj, *args, **kwargs)
        # 3. 返回一个初始化好的对象
        return obj
  • People = Mymeta(),People()则会触发__call__
class People(object, metaclass=Mymeta):
    country = 'China'

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

    def eat(self):
        print('%s is eating' % self.name)


#     在调用Mymeta的__call__的时候,首先会找自己(如下函数)的,自己的没有才会找父类的
#     def __new__(cls, *args, **kwargs):
#         # print(cls)  # cls是People
#         # cls.__new__(cls) # 错误,无限死循环,自己找自己的,会无限递归
#         obj = super(People, cls).__new__(cls)  # 使用父类的,则是去父类中找__new__
#         return obj
  • 类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制
  • 分析:调用Pepole的目的
    1. 先造出一个People的空对象
    2. 为该对空对象初始化独有的属性
    3. 返回一个初始化好的对象
obj = People('nick', age=18)
<class '__main__.People'>
('nick',)
{'age': 18}
print(obj.__dict__)
{'name': 'nick', 'age': 18}

四、通过元类来控制类的调用过程

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

 class Mymeta(type):
     def __call__(self, *args, **kwargs):
         # print('xxx')

         return 1

 class Person(object,metaclass=Mymeta):
     school='oldboy'
     def __init__(self,name):
         self.name=name
     def score(self):
         print('分数是100')

 p=Person('nick')
 print(p.name)

把对象所有的属性都变成私有

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        obj=object.__new__(self)
        obj.__init__(*args, **kwargs)
        # print(obj.__dict__)
        obj.__dict__={ f'_{self.__name__}__{k}':v for k,v in obj.__dict__.items()}
        # print(obj.__dict__)
        return obj

class Person(object, metaclass=Mymeta):
    school = 'oldboy'
    def __init__(self, name):
        self.name = name
    def score(self):
        print('分数是100')
p = Person(name='nick')
print(p.__dict__)
print(p.name)
# print(p)
# print(p.name)

五、有了元类之后的属性查找

类的属性查找顺序:

先从类本身中找

--->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('egon',18) #触发OldboyTeacher的类中的__call__方法的执行,进而执行self.__new__开始查找
print(OldboyTeacher.n)
# print(o.n)

转载于:https://www.cnblogs.com/Wunsch/p/11453059.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值