一、反射实战案例

1.加载配置文件纯大写配置

小写的直接忽略,组织成字典

import settings

new_dict = {}
# print(dir(settings))  # dir获取括号中对象可以调用的名字
# ['AGE', 'INFO', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'desc', 'name']
for i in dir(settings):
    if i.isupper():  # 如果名字是纯大写 那么获取该大写名字对应的值   'AGE'   'INFO'
        v = getattr(settings, i)
        new_dict[i] = v
print(new_dict)

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('请输入您的命令>>>:')
    if hasattr(obj, cmd):
        cmd_name = getattr(obj, cmd)
        cmd_name()
    else:
        print('%s 不是内部或外部命令,也不是可运行的程序或批处理文件' % cmd)

二、面向对象的魔法方法

1.简介

魔法方法其实就是类中定义的双下方法,这些方法都是到达某个条件自动触发,无需调用

eg:__ init__方法在给对象设置独有数据的时候自动触发(实例化)

2.常用魔法方法

魔法方法 功能、触发条件
__init__ 实例化对象的时候自动触发
__str__ 对象被执行打印操作的时候会自动触发
__call__ 对象加括号调用时 自动触发该方法
__getattr__ 当对象获取一个不存在的属性名自动触发
__setattr__ 当对象操作属性值的时候自动触发
__del__ 当对象在被删除(主动 被动)的时候自动触发
__getattribute__ 无论这个属性存不存在,对象获取属性的时候自动触发
__enter__ 对象被with 语法执行上下文操作的时候自动触发
__exit__ 对象被with语法执行并运行完with子代码后 自动触发
__new__ 产生对象时自动触发,在双下init之前

3.代码示例

3.1.实例化对象时自动触发

class MyClass(object):
    def __init__(self, name):
        """实例化对象的时候自动触发"""
        # print('__init__方法')
        # pass
        self.name = name

3.2.对象被执行打印操作时自动触发

该方法必须返回一个字符串,返回什么字符串打印对象之后就展示什么字符串

class MyClass(object):
    # print('__str__方法')
        # print('这是类:%s 产生的一个对象')
        # return '对象:%s'%self
        return '对象:%s'%self.name

3.3.对象加括号自动触发

class MyClass(object):
    def __call__(self, *args, **kwargs):
        """对象加括号调用 自动触发该方法"""
        print('__call__方法')
        print(args)
        print(kwargs)

3.4.当对象获取一个不存在的属性名时自动触发

该方法返回什么,对象获取不存在的属性名就会得到什么,形参item就是对象想要获取的不存在的属性名

class MyClass(object):
    ef __getattr__(self, item):
        print('__getattr__', item)
        return '您想要获取的属性名:%s不存在'%item

3.5.对象操作属性值的时候自动触发

对象.属性名=属性值

class MyClass(object):
    def __setattr__(self, key, value):
        # print("__setattr__")
        # print(key)
        # print(value)
        super().__setattr__(key, value)

3.6.对象在被删除时自动触发

对象在被主动删除或被动删除时自动触发

class MyClass(object):
    def __del__(self):
        # print('__del__')
        pass

3.7.对象获取属性时自动触发

无论这个属性存不存在,对象获取属性时自动触发,当类中既有__ getattr__ 又有__ getattribute__的时候 只会走后者

class MyClass(object):
    def __getattribute__(self, item):
        # print('__getattribute__')
        # return super(MyClass, self).__getattribute__(item)  复杂写法
        return super().__getattribute__(item)  # 简便写法

3.8.对象被with语法执行时自动触发

该方法返回什么 as关键字后面的变量名就能得到什么

class MyClass(object):
    def __enter__(self):
        print('__enter__')

3.9.对象被with语法执行并运行完with子代码之后自动触发

class MyClass(object):
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__')

4.魔法方法实践

"""补全以下代码 执行之后不报错"""
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()

三、元类

Python中,一切皆对象,我们定义的数字、字符串、函数、列表等都是对象,对象是类(class)的是实例,而类(class)其实也是对象,是type的实例。这个type就是Python中的元类(metaclass)。所谓元类就是用于创建所有类型的类,Python中的所有新式类以及Python3中的所有类都是type元类的实例

1.元类简介

1.1.推导过程

基础阶段我们使用type来查找数据的数据类型

s1 = '哈哈哈 今天下午终于可以敲代码了!!!'
l2 = [60, 80, 100, 120, 150, 200]
d = {'name': '死给我看', 'age': 18}
print(type(s1))  # <class 'str'>
print(type(l2))  # <class 'list'>
print(type(d))  # <class 'dict'>

学了面向对象之后,发现查看的不是数据类型而是数据所属的类

我们定义的数据类型,其实本质还是通过各个类产生了对象

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'>

1.2.结论

自定义的类都是由type类产生的,我们将产生类的类称之为元类

2.创建类的两种方式

学习元类其实就是掌握了类的产生过程 我们就可以在类的产生过程中高度定制化类的行为

  • 类名必须首字母大写

上述需求就需要使用元类来控制类的产生过程,在过程中校验

2.1.class关键字

class aaa:
    pass
print(aaa)

2.2.利用元类type

type(类名,类的父类,类的名称

3.元类的基本应用

3.1.只有继承了type的类才可以称之为是元类

class MyMetaClass(type):
    pass

3.2.代码示例

class MyMetaClass(type):
    def __init__(self,what, bases=None, dict=None):
        # print('别晕')
        # print('what', what)  类名
        # print('bases', bases) 类的父类
        # print('dict', dict) 类的名称空间
        if not what.istitle():
            # print('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
            raise Exception('首字母必须大写 你会不会写python 面向对象学过吗 lowB')
        super().__init__(what, bases, dict)

3.3.切换产生类的元类不能使用继承,必须使用关键字metaclass声明

class aaa(metaclass=MyMetaClass):
    pass

4.元类进阶

元类不单单可以控制类的产生过程,也可以控制对象

4.1.对象加括号执行产生该对象类里面的__ call__

class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        print('__call__')
        if args:
            raise Exception('必须用关键字参数传参')
        super().__call__(*args, **kwargs)

4.2.类加括号执行产生该类的元类里面的双下__ init__

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


# 需求:实例化对象 所有的参数都必须采用关键字参数的形式
obj = MyClass('jason', 18)
# obj = MyClass(name='jason', age=18)

4.3.总结

  • 如果我们想高度定制对象的产生过程,可以操作元类里面的__ call__
  • 如果我们想高度定制类的产生过程,可以操作元类里面的__ init__

5.元类的双下new方法

类产生对象的步骤:

  1. 产生一个空对象
  2. 自动触发__ init__方法实例化对象
  3. 返回实例化好的对象

__ new__方法:专门用于产生空对象
__ init__方法:专门用于给对象添加属性

 posted on 2022-07-31 18:09  念白SAMA  阅读(25)  评论(0编辑  收藏  举报