ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

元类

2022-04-12 01:31:05  阅读:128  来源: 互联网

标签:__ name self 元类 print class def


目录

反射实例案例

对于面向对象之反射,我的理解是你通过输入的方式给出一个指令,我不需要知道你给出的是哪个对象,其中的指令有哪些,我只要管自己输入要执行的指令,有我就执行,没有我就返回指令不存在的提示。

class WinCmd(object):
    def ls(self):
        print('windows系统正在执行ls命令')

    def dir(self):
        print('windows系统正在执行dir命令')

    def cd(self):
        print('windows系统正在执行cd命令')


class LinuxCmd(object):
    def ls(self):
        print('Linux系统正在执行ls命令')

    def dir(self):
        print('Linux系统正在执行dir命令')

    def cd(self):
        print('Linux系统正在执行cd命令')


obj = WinCmd()
obj1 = LinuxCmd()
'''反射提供了一种不需要代码的前提下,操作数据和功能'''


def run(obj):
    while True:
        cmd = input('请输入您的指令>>>:')
        if hasattr(obj,cmd):
            func_name = getattr(obj, cmd)
            func_name()
        else:
            print('cmd command not found')


run(obj1)
run(obj)

面向对象的双下方法

面向对象的双下方法被一些人称为魔法方法,因为一些面向对象双下方法在达到某个条件的时候会自动触发,不需要手动调用

# __str__
class person(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        print('__str__执行')
        return '打印时执行__str__'


obj1 = person('king')
print(obj1)
print(person)

'''
在对象被执行打印(print、前端展示)操作的时候自动触发
该方法必须返回字符串类型的数据,不然会报错
主要用于精准的描述对象
'''

# __del__
class person(object):
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print(self.name)

obj1 = person('king')

# 执行完成代码为被动
# print(obj1)
# print('哈哈')

# 主动
print(obj1)
del obj1  
print('哈哈')

'''
对象被执行(被动、主动)删除操作之后自动执行
被动删除:python解释器会在程序执行完成之后,自动删除内容
主动删除:使用del等删除的关键字手动删除
'''

# __getattr__
class person(object):
    def __init__(self, name):
        self.name = name

    def __getattr__(self, item):
        print(f'{item}对象查找不存在')


obj1 = person('king')
print(obj1.age)  # None,__getattr__的执行在这个结果出现之前
'''
对象查找(使用)不存在的名字的时候自动触发
'''

# __setattr__
# 主要用于给对象添加属性用的,当对象执行添加属性操作的时候自动触发  >>> obj.变量名=变量值

class person(object):
    def __init__(self, name):
        self.name = name

    def __setattr__(self, key, value):
        print('执行了__setattr__')
        super().__setattr__(key, value)
'''
当你对__setattr__方法进行操作添加的时候要记得继续再继承一下父类的方法__setattr__不然你的属性添加不到对象的名称空间中
'''

obj1 = person('king')
obj1.age = 18
# print(obj1.age)
print(obj1.__dict__)

# __call__

class person(object):
    def __init__(self, name):
        self.name = name

    def __call__(self, *args, *kwargs):
        print('hahaha', args, kwargs)
        return 'sdaadssd'


obj1 = person('king')
obj1(1)

'''
用于对象加括号调用的时候自动触发,如果想接受实参,加上形参即可
'''

# __enter__

class person(object):
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('执行__enter__')

    def __exit__(self, exc_type, exc_val, exc_tb):  # 一定要加上后面三个参数,在看不到的地方自动传入了四个参数
        print('执行__exit__', exc_type, exc_val, exc_tb)  # 执行__exit__ None None None


obj1 = person('king')
with obj1 as f:  # with程序开始,自动执行__enter__
    print('123')  # with程序结束,自动执行__exit__
print('321')

'''
__enter__和__exit__必需配合使用
'''

# __getattribute__

class person(object):
    def __init__(self, name):
        self.name = name

    def __getattribute__(self, item):
        print(f'{item}',item)


obj1 = person('king')
print(obj1.__dict__)  # None   只要一看到对象查找名字(调用数据),就运行__getattribute__
print(obj1.age)  # None
print(obj1.name)  # None

'''
只要对象查找名字无论名字是否存在都会执行该方法
如果类中有__getattribute__方法 那么就不会去执行__getattr__方法
用了这个方法,就算有这个属性,print打印的结果也是None
'''

笔试题讲解

# 让字典具备据点符查找值的功能
# 1.定义一个类继承字典
class MyDict(dict):
    # 做到可以句点符取值
    def __getattr__(self, item):
        return self.get(item)
    
    # 做到句点符赋值
    def __setattr__(self, key, value):
        self[key] = value  # 对象名称空间中是正常的属性=属性值,而字典中是键值队的形式,因此赋值方式要更改一下
    
    
'''对于这个题目要做到区分是名称空间的名字还是数据k:v键值对'''
obj = MyDict({'name': 'jason', 'age': 18})
# 1.具备句点符取v
# print(obj.name)
obj.pwd = 123  # 相当于 正常字典的obj['gender'] = 'male'
'''给字典名称空间添加名字,不是数据k:v'''
print(obj)

2.补全下列代码 使其运行不报错
# 补全下列代码 使其运行不报错
class Context:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        pass

    def do_something(self):
        pass


with Context() as ctx:
    ctx.do_something()
'''
对于with 对象 as 变量名: 来说对象所属的类中一定要有双下enter和双下exit
对于对象内容所变成的do_something来说,对象内要有do_something方法
'''

元类简介

# 元类
即产生类的类

class MyClass(object):
    pass


obj = MyClass()
print(type(obj))  # <class '__main__.MyClass'> type查看的其实是当前对象所属的类名称
print(type(MyClass))  # <class 'type'>


class Student:
    pass


print(type(Student))  # <class 'type'>


class Teacher(MyClass):
    pass


print(type(Teacher))  # <class 'type'>
'''type就是所有类默认的元类'''

产生类的两种表现形式(本质是一种)

1.class关键字
	class C1(object):
        pass
    print(C1)  # <class '__main__.C1'>
    
2.type元类
	type(类名,父类,类的名称空间)
    res = type('C1', (), {})
    	print(res)  # <class '__main__.C1'>

'''
学习元类的目的
	元类能够控制类的创建 也就意味着我们可以高度定制类的行为
	eg:掌握了物品的生产过程 就可以在过程中做任何的额外操作
	
	比如:要求类的名字必须首字母大写
		思考在哪里编写定制化代码
			类的产生过程目前还比较懵 	  元类里面的__init__方法
			对象的产生过程呢 			     类里面的__init__方法
		方法:由已知推未知
'''

元类的基本使用

'''元类是不能通过继承的方式直接指定的'''
通过关键字参数metaclass修改该类的元类,C1的创建受自己元类的影响
class C1(metaclass=MyTypeClass):
    pass


class MyTypeClass(type):  # 元类用来定制类的行为(样式)
    def __init__(cls, cls_name, cls_bases, cls_dict):  # 必须写明4个形参,因为默认传入4个实参
        # print(cls, cls_name, cls_bases, cls_dict)
        if not cls_name.istitle():
            raise Exception("类名的首字母必须大写 你个sd")
        super().__init__(cls_name)


class C1(metaclass=MyTypeClass):
    school = "清华大学"


class a(metaclass=MyTypeClass):
    school = '清华大学'

元类进阶操作

1.回想__call__方法
	对象加括号会自动执行产生该对象的类里面的__call__,并且该方法返回什么对象加括号就会得到什么
  推导:类加括号会执行元类的里面的__call__该方法返回什么其实类加括号就会得到什么
"""类里面的__init__方法和元类里面的__call__方法执行的先后顺序"""
class MyTypeClass(type):
    def __call__(self, *args, **kwargs):
        print('__call__ run')
        print(args, kwargs)
        super(MyTypeClass, self).__call__(*args, **kwargs)


class MyClass(metaclass=MyTypeClass):
    def __init__(self, name):
        print('__init__')
        self.name = name
        
        
obj = MyClass('jason')
# call在init前运行

# 定制对象的产生过程
class MyTypeClass(type):
    def __call__(self, *args, **kwargs):
        if args:  # 若args有值表示输入的不是关键字参数
            raise Exception("必须全部采用关键字参数")
        super().__call__(*args, **kwargs)


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

'''只要为了展示,传入的值目前拿不出来'''
'''强制规定:类在实例化产生对象的时候 对象的独有数据必须采用关键字参数'''
obj2 = MyClass(name='jason')  # 关键字参数是放在kwargs里的
print(type(obj2))
'''
如果你想高度定制类的产生过程
	那么编写元类里面的__init__方法
如果你想高度定制对象的产生过程
	那么编写元类里面的__call__方法
'''

双下new方法

__new__用于产生空对象(类)			骨架
__init__用于实例化对象(类)		血肉
class MyTypeClass(type):
    # def __new__(cls, *args, **kwargs):
    #     print('__new__ run')
    #     return super().__new__(cls, *args, **kwargs)
    #
    # def __init__(cls,cls_name, cls_bases, cls_dict):
    #     print('__init__ run')
    #     super().__init__(cls_name, cls_bases, cls_dict)

    def __call__(cls, *args, **kwargs):
        # 1.产生一个空对象
        obj = object.__new__(cls, *args, **kwargs)
        # 2.调用init方法实例化
        return obj


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

obj = MyClass('jason')
print(obj)
"""
注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
	如果是在元类的__new__里面 可以直接调用
class Meta(type):
      def __new__(cls, *args, **kwargs):
          obj = type.__new__(cls,*args,**kwargs)
          return obj
	如果是在元类的__call__里面 需要间接调用
class Mate(type):
    def __call__(self, *args, **kwargs):
    	obj = object.__new__(self) # 创建一个空对象
    	self.__init__(obj,*args,**kwargs) # 让对象去初始化
         return obj
"""

标签:__,name,self,元类,print,class,def
来源: https://www.cnblogs.com/smallking-keep/p/16133326.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有