python学习Day34

Day 34

今日内容概要

  • 反射实战案例
  • 面向对象魔法方法(双下方法)
    • 魔法方法实战演练
  • 元类简介
    • 创建类的两种方式
    • 元类的基本使用
    • 元类的进阶
    • 元类的双下new方法

今日内容详细

1.反射实战案例

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

#配置文件加载:获取配置文件中所有大写名的配置组成字典,忽略小写的
import settings
dict={}
for i in dir(settings):#dir()获取括号里对象可以调用的名字并转成字符串
    if i.isupper():#判断字符串是不是纯大写
        # print(i)#打印所有大写的字符串名字
        v=getattr(settings,i)#反射方法 getattr(对象,名字)
        # print(v)#打印所有符合反射方法对应的值(大写名字的值)
        dict[i]=v #把符合的写入空字典中
print(dict)#{'AGE':'大写名的18','CAR':'大写名的车'}
2.模拟操作系统cmd终端执行用户命令

#模拟各个系统的cmd终端
class WinCmd(object):#创建一个类 不继承东西就用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):#判断对象中是否有对应的命令hasatter(对象,名字)
        cmd_name=getattr(obj,cmd)()#获取字符串中对应的属性赋值给变量名加括号调用
    else:
        print(f'{cmd}不是内部或外部命令')

2.面向对象魔法方法(双下方法)重点

魔法方法其实就是类中定义的双下方法
	就是'到达某个条件自动触发','不需要调用'
class MyClass(object):#创建一个类 不继承用object(兼容好)
    def __init__(self,name):
        """
 1.     给对象设置独有数据时自动触发(实例化对象)
        """
        # print('__init__方法')
        self.name=name
#产生一个对象
# obj=MyClass('jason')#__init__方法
# print(obj.name)#jason
    def __str__(self):
        """
 2.     对象被执行打印操作时自动触发 且必须返回一个字符串
        返回什么字符串打印对象之后就展示什么字符串
        """
        print('__str__方法')
        return '%s'%self.name
#产生一个对象
# obj=MyClass('jason')
# print(obj)#__str__方法   jason
    def __call__(self,*args,**kwargs):
        """
 3.     对象加括号调用时自动触发
        加了该方法的对象同时拥有了函数、对象的功能
        """
        print('__call__方法')
        print(args)#(1, 2)
        print(kwargs)#{'name':'张三'}
#产生一个对象
# obj=MyClass('jason')
# obj(1,2,name='张三')
    def __getattr__(self, item):
        """
 4.     对象获取一个不存在的属性名时自动触发
        该方法返回什么,不存在的属性名就得到什么
        形参item就是不存在的属性名
        """
        print('__getattr__方法',item)
        return '属性名%s不存在'%item
#产生一个对象
# obj=MyClass('jason')
# print(obj.xxx)#__getattr__方法 xxx   属性名xxx不存在
    def __setattr__(self, key, value):
        """
 5.     对象操作属性值时自动触发(对象.属性名=属性值)
        无论在什么地方,只要触发该语法都会执行setattr
        """
        # print('__setattr__方法')
        # print(key)
        # print(value)
        #由于魔法方法都是父类object里有的,在类中调用都是在重写,需重新调用一下
        super().__setattr__(key,value)
#产生一个对象
# obj=MyClass('jason')
# print(obj.__dict__)#{'name': 'jason'}
# print(obj.name)#jason
    def __del__(self):
        """
 6.     对象被删除的时候自动触发
        1.人为主动删除
        2.程序运行结束要释放内存空间,也会删除
        """
        # print('__del__')
#产生一个对象
# obj=MyClass('jason')
# del obj
    def __getattribute__(self, item):
        """
 7.     对象获取任意存在或不存在属性时自动触发
        如果类里写了getattr和getattribute则只会执行后者
        """
        print('__getattribute__')
        #return super(MyClass, self).__getattribute__(item)复杂写法
        return super().__getattribute__(item)#简单写法
#产生一个对象
# obj=MyClass('jason')
# # obj.name
# # obj.xxx
# # print(obj.name)#由于重写了该方法 想拿到name需super调父类的该方法
    def __enter__(self):
        """
 8.     对象被with语法执行时自动触发
        该方法返回什么as关键字后的变量名就得到什么
        """
        print('__enter__')
        return 123
    def __exit__(self, exc_type, exc_val, exc_tb):
        """
 9.     对象被with语法执行并运行完with子代码后自动触发
        """
        print('__exit__')
#产生一个对象
# obj=MyClass('jason')
# with obj as f:
#     print(f)

魔法方法 触发条件
__init__(self): 给对象 <设置独有数据时> 自动触发(实例化对象)
__str__(self): 对象被执行 <打印操作时> 自动触发且必须返回一个字符串
返回什么字符串打印对象之后就展示什么字符串
__call__(self,*args,**kwargs): 对象 <加括号调用时> 自动触发
加了该方法的对象同时拥有了函数、对象的功能
__getattr__(self,item): 对象 <获取一个不存在的属性名时> 自动触发
该方法返回什么,不存在的属性名就得到什么
形参item就是不存在的属性名
__setattr__(self,key,value): 对象 <操作属性值时> 自动触发 (对象.属性名=属性值)
无论在什么地方,只要触发该语法都会执行setattr
__del__(self): 对象 <被删除时> 自动触发
1.人为主动删除
2.程序运行结束要释放内存空间,也会删除
__getattribute__(self,item): 对象 <获取任意存在或不存在属性时> 自动触发
如果类里写了getattr和getattribute则只会执行后者
__enter__(self): 对象 <被with语法执行时> 自动触发
该方法返回什么as关键字后的变量名就得到什么
__exit__(self,exc_type,exc_val,exc_tb): 对象 <被with语法执行并运行完with子代码后> 自动触发

2.1.魔法方法实战演练

eg:补全一下代码 执行后不报错
class Context:
    pass
with Context() as f:
    f.do_something()
1.首先看到对象在with语法里 则需要用到__enter__和__exit__
2.看到f.do_something() 想到enter返回什么f就得到什么,所以返回一个self
3.由于返回的是对象self 所以加一个def do_something(self):
#把Context()看做是obj尝试,obj=Context()

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()

3.元类简介

s1='哈哈哈哈哈哈哈'
l1=[60,70,80,100]
print(type(s1))#<class 'str'>
print(type(l1))#<class 'list'>
'''
基础阶段用type查看数据类型
学了面向对象后发现其实是在看数据所属的类

我们定义的数据类型本质上还是通过各个类产生对象
    class str:(由于str是关键字所以没有大写)
        pass
    name='张三'本质就是str('张三')

可以理解为type用于查看产生当前对象的类是谁
'''
#验证:
class MyClass:
    pass
obj=MyClass()
#查看产生对象obj的类
print(type(obj))#<class '__main__.MyClass'>
#查看产生对象MyClass的类
print(type(MyClass))#<class 'type'>
"""
通过上述验证推导得出:
    自定义的类都是由type类产生的
    我们将产生类的类称之为【元类】
"""

3.1.创建类的两种方式

1.class 关键字
	class MyClass:
        pass
2.利用元类type
	type(类名,类的父类,类的名称空间)
 
推荐第一种简单   第二种有点花里胡哨还难
"""
学习元类其实就是掌握类的产生过程 可以在类的产生过程中定制类的行为
  eg:
	类名必须首字母大写
    该需求需要使用元类来控制类的产生过程,在过程中校验
"""

3.2.元类的基本使用

#如果要改一个类的产生过程则需要自己先写一个类,让该类继承type
"只有继承了type的类才可以叫元类"
class MyMetaClass(type):
    pass

"如果想要切换产生类的元类,不能直接继承需要用关键字mataclass="
class MyClass(metaclass=MyMetaClass):
    pass

"""
思考:
    类中的__init__用于实例化对象
    元类的__init__用于实例化类
"""
eg: 继承元类时首字母需大写不然报错
    
"只有继承了type的类才可以叫元类"
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():
            raise Exception('首字母必须大写')#如果不是大写直接报错
        super().__init__(what,bases,dict)

"如果想要切换产生类的元类,不能直接继承需要用关键字mataclass="
class aaa(metaclass=MyMetaClass):
    pass

3.3.元类的进阶

元类不仅可以控制类的产生过程,也可以控制对象的
"""
思考:
    1.对象加括号可以执行产生该对象类里面的双下call
    2.类加括号可以执行产生该类的元类里面的双下call
"""
#需求:实例化对象 所有的参数都必须采用关键字参数形式
class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        if args:
            raise Exception('必须用关键字参数传参')
        super().__call__(*args,**kwargs)
class MyClass(metaclass=MyMetaClass):
    def __init__(self,name,age):
        self.name=name
        self.age=age
obj=MyClass('jason',18)#报错
obj = MyClass(name='jason',age=18)#成功运行

总结:
   1.如果想高度定制对象的产生过程
    	可以操作元类里的__call__
   2.如果想要高度定制类的产生过程
    	可以操作元类里面的__init__

3.4元类的双下new方法

"""
类产生对象的步骤
	1.产生一个空对象
	2.自动触发__init__方法实例化对象
	3.返回实例化好的对象
"""

__new__方法专门用于产生空对象		  骨架
__init__方法专门用于给对象添加属性		骨肉

作业

1.自定义字典并且让字典具备
	d.key = value  修改键值对
	d.key = value  添加键值对 
2.整理今日内容及博客
3.预习选课系统
posted @ 2022-08-01 00:01  逢诱  阅读(25)  评论(0)    收藏  举报