ICode9

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

面向对象魔法方法与元类

2022-07-30 17:31:44  阅读:117  来源: 互联网

标签:__ 触发 self 魔法 元类 面向对象 print type def


反射实战案例

1.加载配置文件中所有纯大写的配置
import src  # AA = '是大写', aa = '是小写'

new_dict = {}
print(dir(src))  # dir用于获取括号中对象可以调用的名字
# ['AA', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'aa']
for i in dir(src):
    if i.isupper():  # 判断名字是不是纯大写
        v = getattr(src, i)
        new_dict[i] = v  # 将纯大写的名字加入字典
print(new_dict)
# {'AA': '是大写'}

2.模拟操作系统cmd终端执行用户命令
class WinCmd(object):
    def dir(self):
        print('dir获取当前目录下所有的文件名称')

    def ls(self):
        print('ls获取当前路径下所有的文件名称')

    def ipconfig(self):
        print('ipconfig获取当前计算机的网卡信息')


obj = WinCmd()
while True:
    cmd = input('输入命令>>>:').strip()
    if hasattr(obj, cmd):  # 判断对象是否含有字符串对应的属性
        cmd_name = getattr(obj, cmd)  # 获取对象字符串对应的属性
        cmd_name()
    else:
        print(f'{cmd}不是内部或外部命令,也不是可运行的程序或批处理文件')

面向对象魔法方法

'''
魔法方法其实就是类中定义的双下方法,之所以叫魔法方法是因为这些方法都是达到某个条件就会自动触发,也就是对象实例化
eg:__init__
'''
class MyClass(object):
    def __init__(self):
        '实例化对象的时候触发'
        print('触发__init__')
        # self.name = name
        pass

    def __str__(self):
        '''对象被执行打印操作的时候会触发
        该方法必须返回一个字符串
        返回什么字符串打印对象之后就展示什么字符串'''
        print('触发__str__')
        return ''

    def __call__(self, *args, **kwargs):
        '对象加括号调用时自动触发'
        print('触发__call__')
        print(args)
        print(kwargs)

    def __getattr__(self, item):
        '''对象获得一个不存在的属性名时自动触发
        对象获取的不存在的属性名会获取该方法的返回值
        形参item就是对象获取的不存在的属性名'''
        print('触发__getattr__')
        return f'属性名:{item}不存在'

    def __setattr__(self, key, value):
        '对象操作属性值时自动触发(对象.属性名=属性值)'
        print('触发__setattr__')

    def __del__(self):
        '对象在被删除的时候自动触发触发'
        print('触发__del__')

    def __getattribute__(self, item):
        '''对象获取属性的时候自动触发
        无论这个属性存不存在
        当类中既有__getattr__又有__getattribute__时只会走后者'''
        print('触发__getattribute__')

    def __enter__(self):
        '对象被with语法执行时自动触发,该方法返回什么,as关键字后面的变量名就能得到什么'
        print('触发__enter__')
        return '对象被with语法执行'

    def __exit__(self, exc_type, exc_val, exc_tb):
        '对象被with语法执行并运行子代码之后自动触发'
        print('触发__exit__')

        
res = MyClass()  # 触发__init__
print(res)  # 触发__str__
res(1, 2, name='barry', age=20)  # 触发__call__
# (1, 2)
# {'name': 'barry', 'age': 20}
print(res.name)  # 触发__getattr__
# 属性名:name不存在
res.name = 'barry'  # 触发__setattr__
del res  # 触发__del__
print(res.name)  # 触发__getattribute__
# None
with res as f:
    print(f)
# 触发__enter__
# 对象被with语法执行
# 触发__exit__
img

魔法方法笔试题

class Context:
    def __enter__(self):
        pass

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


with Context() as f:
    f.do_something()
    
    
"""补全以上代码 执行之后不报错"""


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 f:
    f.do_something()

元类简介

s1 = '字符串'
l1 = ['列表']
d1 = {'这是': '字典'}
print(type(s1))  # <class 'str'>
print(type(l1))  # <class 'list'>
print(type(d1))  # <class 'dict'>
'''
我们以前一直用type来查看数据类型
但其实查看的不是数据类型而是数据所属的类

我们定义的数据类型本质还是通过类产生的对象
class str:
    pass
h = 'hello'   str('hello')

可以理解为type用于查看当前对象的类是谁
'''


class MyClass:
    pass


obj = MyClass()
print(type(obj))  # 查看产生对象obj的类:<class '__main__.MyClass'>
print(type(MyClass))  # 查看产生对象MyClass的类:<class 'type'>
"由此,我们可以得出结论,自定义的类都是由type类产生的,我们将产生类的类称为'元类'"
img

产生类的两种方式

1.class 关键字
class 类名:
    pass
    
2.利用元类type
type(类名,类的父类,类的名称空间)

'利用元类type来产生类虽然更繁琐,但可以帮我们高度定制产生类的过程'

元类的使用

class MyMetaClass(type):
    pass
    '只有继承了type的类才可以称之为是元类'


class MyClass(metaclass=MyMetaClass):
    pass
    '使用关键字metaclass声明才可以切换产生类的元类'

    
'''
类中的__init__用于实例化对象
元类中__init__用于实例化类
'''
class MyMetaClass(type):
    def __init__(self, what, bases=None, dict=None):
        print('使用自定义的元类')
        # 使用自定义的元类
        print(what)  # 类名
        # MyClass
        print(bases)  # 类的父类
        # ()
        print(dict)  # 类的名称空间
        # {'__module__': '__main__', '__qualname__': 'MyClass'}
        if not what.istitle():  # 判断类名首字母是否大写
            raise Exception('首字母必须大写')  # 首字母不是大写则报错
        super().__init__(what, bases, dict)  # 首字母大写则产生类
    '只有继承了type的类才可以称之为是元类'


class Myclass(metaclass=MyMetaClass):
    pass


class abc(metaclass=MyMetaClass):
    pass
# 报错:Exception: 首字母必须大写
img

元类进阶

'元类不止可以控制类的产生,还可以控制对象的产生'
class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        print('触发__call__')
        if args:
            raise Exception('必须使用关键字传参')
        super().__call__(*args, **kwargs)


class Myclass(metaclass=MyMetaClass):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('触发__init__')


obj = Myclass('barry', 20)
# 报错:Exception: 必须使用关键字传参
obj = Myclass(name='barry', age=20)
# 触发__call__
# 触发__init__
'''
我们可以操作元类里面的__call__来定制对象的产生过程
我们可以操作元类里面的__init__来定制类的产生过程
'''

双下new方法

'''
类产生对象的步骤
1.产生一个空对象
2.自动触发__init__方法实例化对象
3.返回实例化好的对象
'''
__new__方法专门用于产生空对象
__init__方法专门用于给对象添加属性

标签:__,触发,self,魔法,元类,面向对象,print,type,def
来源: https://www.cnblogs.com/riuqi/p/16535429.html

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

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

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

ICode9版权所有