OOP 反射&元类

面向对象

反射:reflect,可以理解为自省的意思

  反射是指一个对象应该具有自我检测、修改、增加自身属性的能力

  反射就是通过字符串操作属性

涉及到的函数:hasattr & getattr & setattr & delattr

hasattr(对象,‘属性名‘):判断某个对象是否存在某个属性

getattr(对象,‘属性名‘,None):从对象中取出属性     第三个值位默认值,当属性不存在是返回默认值

setattr(对象,‘属性名‘,‘属性对应的值‘):为对象设置添加新的属性

delattr(对象,‘属性名‘):从对象中删除属性

class Person:
    def __init__(self, name):
        self.name = name

p = Person(‘rose‘)
if hasattr(p, ‘name‘):  # 判断是否具有某个属性
    print(getattr(p, ‘name‘))  # 获取属性  rose

setattr(p, ‘age‘, 18)  # 设置添加属性
print(getattr(p, ‘age‘))  # 18

delattr(p, ‘name‘)  # 删除属性
print(p.__dict__)  # {‘age‘: 18}  可以看到name属性被成功删除

 使用场景:

  反射其实就是对属性的增删改查,但是如果直接使用内置的__dict__来操作,语法繁琐,不好理解

  另外一个最主要的问题是:如果对象不是我们自己写的而是另一方提供的,我们就必须判断这个对象是否满足要求,也就是是否具有我们需要的属性和方法

# 以框架设计方式为例:
# 需求:要实现一个用于处理用户的终端指令的小框架

import kkkkk

def run(a):
    while True:
        cmd = input(‘请输入指令>>>  ‘)
        if cmd == ‘exit‘:
            break

        if hasattr(a, cmd):
            res = getattr(a, cmd)
            res()
        else:
            print(‘不支持该指令!!!‘)

    print(‘拜拜了您嘞!‘)

# 生成模块的实例化对象
wincmd = kkkkk.Windows()
linuxcmd = kkkkk.Linux()
# 调用框架来使用
run(wincmd)  # 括号里传入模块的实例化对象,这样就可以使用到模块实例化对象中的方法
# kkkkk模块内容

class Windows:
    def cd(self):
        print(‘Windows 切换目录...‘)

    def dir(self):
        print(‘Windows 列出所有目录‘)

    def delete(self):
        print(‘Windows 删除文件‘)

class Linux:
    def cd(self):
        print(‘Linux 切换目录‘)

    def rm(self):
        print(‘Linux 删除文件‘)

    def ls(self):
        print(‘Linux 列出所有目录‘)

  上述框架代码中,写死了必须使用某个类,这是不合理的;因为无法提前知道对方的类在什么地方以及类叫什么

  所以我们应该为框架的使用者提供一个配置文件,要求对方将类的信息写入配置文件;如将模块路径和类名写到settings中

  然后框架自己去加载需要的模块(从settings中导入模块路径及类名,拿到类后实例化对象,最后调用框架)

import kkkkk

def run(a):
    while True:
        cmd = input(‘请输入指令>>>  ‘)
        if cmd == ‘exit‘:
            break

        if hasattr(a, cmd):
            res = getattr(a, cmd)
            res()
        else:
            print(‘不支持该指令!!!‘)

    print(‘拜拜了您嘞!‘)

# 在settings拿到你需要的类
path = settings.CLASS_PATH
# 从settings单独拿出模块路径和类名
module_path, class_name = path.rsplit(‘.‘, 1)
# 拿到模块
get_class = importlib.import_module(module_path)
# 拿到类
cls = getattr(get_class, class_name)
# 实例化对象
obj = cls()
# 调用框架
run(obj)
# kkkkk

class Windows:
    def cd(self):
        print(‘Windows 切换目录...‘)

    def dir(self):
        print(‘Windows 列出所有目录‘)

    def delete(self):
        print(‘Windows 删除文件‘)

class Linux:
    def cd(self):
        print(‘Linux 切换目录‘)

    def rm(self):
        print(‘Linux 删除文件‘)

    def ls(self):

print(‘Linux 列出所有目录‘)
# settings

# 作为框架使用者 在配置文件中指定你配合框架的类是哪个  这里面要求格式书写————  模块名与类

CLASS_PATH = ‘kkkkk.Windows‘  # ---模块名与类----字符串形式

元类metaclass 创建类的类

  作用:用于创建类

  解释:对象是通过类实例化产生的,万物皆对象,类也是对象,所以也有产生类对象的类,这个类就叫元类

  PS:通常默认所有的类的元类都是type

  扩展:如果只是为了创建类就不需要使用元类,直接定义就可以了。所以我们使用元类,一般是为了在类创建的过程时候进行一些限制

如何创建??

  1.定义一个类,使其继承type这样这个类就变成了一个元类,并且这个元类就有了type所有的属性方法

  2.对定义的元类进行初始化,覆盖type中的init方法

# 定义一个元类,使其限制新创建的类的类名必须使用大驼峰体

class MyType(type):
    def __init__(self, name, base, dict):
        super().__init__(name, base, dict)
        if name.istitle():
            pass
        else:
            raise Exception(‘每个单词首字母要大写!‘)

class person(metaclass=MyType):  # 报错,因为没有使用大驼峰体
    pass

(补充)元类中  __new__  的使用:

  当你要创建类对象时,会首先执行元类中的__new__方法,拿到一个空对象,然后会自动调用__init__来对这个类进行初始化操作

  如果你覆盖了该方法则必须保证,new方法必须有返回值且必须是对应的类对象

  例:

class Meta(type):

    def __new__(cls, *args, **kwargs):
        ‘‘‘
        这中间可以增加你想要的定义操作。增加以后会先执行__new__方法,有了一个返回值以后才会执行__init__方法
        不增加的话可以不写,默认返回对应的类对象
        ‘‘‘
        # return super().__new__(cls,*args,**kwargs)  # 这里面的super就像相当于type
        # 可以写成下面的形式,两者等价
        obj = type.__new__(cls,*args,**kwargs)
        return obj

    def __init__(self,a,b,c):
        super().__init__(a,b,c)

  所以__new__和__init__都可以控制类对象的创建,但是__init__更为简单

元类中  __call__  的使用:

  我们知道,类实例化的过程就是调用__call__的过程,所以如果我们想要控制对象创建过程(实例化过程),据需要覆盖call方法;但是,覆盖元类中的call之后,这个类就无法产生对象,必须调用super().__call__来完成对象的创建,并返回其返回值。如下例:

# 将对象的所有属性名称转为大写

class M(type):
    def __call__(self, *args, **kwargs):
        new_args = []
        for i in args:
            new_args.append(i.upper())
        return super().__call__(*new_args,**kwargs)  # 注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

class K(metaclass=M):
    def __init__(self,name):
        self.name = name

k = K(‘www‘)
print(k.name)  # WWW 成功实现

例子:

# 要求创建对象时必须以关键字参数形式来传参# 覆盖元类的__call__# 判断你有没有传非关键字参数 == 不能有位置参数# 有就炸

# 第一步,创建一个元类:
class K(type):
    # 第二步,定义实例化时候的格式
    def __call__(self, *args, **kwargs):
        if args:
            raise Exception(‘不能使用位置传参...‘)  # 如果是位置参数,则报错

        return super().__call__(*args, **kwargs)  # 注意:一旦覆盖了call必须调用父类的call方法来产生对象并返回这个对象

# 第三步,创建一个类,并制定其元类
class O(metaclass=K):
    def __init__(self, name):
        self.name = name

# 第四步,实例化,创建对象的过程
# o = O(‘位置参数‘)  # Exception: 不能使用位置传参...  表明位置传参不行
o = O(name = ‘关键字传参‘)
print(o.name)  # 关键字传参   表明关键字传参可行

原文地址:https://www.cnblogs.com/pupy/p/11271671.html

时间: 2024-10-07 17:48:01

OOP 反射&元类的相关文章

Python第二十一课(反射/元类)

Python第二十一课(反射/元类)    >>>思维导图>>>中二青年 反射reflect 什么是反射, 其实是反省,自省的意思 反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力 反射就是通过字符串操作属性 涉及的四个函数,这四个函数就是普通的内置函数 没有双下划綫,与print等等没有区别 hasattr getattr setattr delattr p = Person("jack",18,"man") #

7.28 多态 反射 元类

多态 1.什么是多态 多态指的是一类事物有多种形态 例如: 动物有多种形态: 人,狗,猪 在程序中多态指的是,不同对象可以响应相同方法,并可以有自己不同的实现方式 2.为什么需要多态 案例分析: import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass class People(Animal): #动物的形态之一:人 def talk(self): prin

反射 元类

1.反射 reflect 反射指的是一个对象应该具备,可以检测,修改,增加自身属性的能力 反射就是通过字符串操作属性 涉及四个普通的内置函数,没有双下划线, hasattr    getattr     setattr      delattr class Person: def __init__(self,name,age,male): self.name = name self.age = age self.male = male p = Person('jack',18,'man') if

Python -- OOP高级 -- 元类

type()函数既可以返回一个对象的类型,又可以创建出新的类型 def fn(self, name="world"): print("Hello, %s!" % name) Hello = type("Hello", (object,), dict(hello=fn)) h = Hello() >>> h.hello() Hello, world! >>> type(h) Out[165]: __main__.

QObject提供了QMetaObject元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化

元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化其中元类又提供了:classInfo,className,构造函数,多重祖先元类,method, property, Enumerator, Signal, Slot等等 http://doc.qt.io/qt-5/qobject.html http://doc.qt.io/qt-5/qmetaobject.html 我感觉Qt的出现,除了提供GUI以外,主要就是提

Python基础- 类和对象(使用、继承、派生、组合、接口、多态、封装、property、staticmethod、classmethod、反射、slots、上下文管理协议、元类)

标签: python对象 2017-07-01 16:28 79人阅读 评论(0) 收藏 举报  分类: python(11)  版权声明:本文为广大朋友交流学习,如有纰漏望不吝赐教,若存在版权侵犯请及时与我联系 目录(?)[+] 一.初识类和对象 在python3中类型就是类 先定义类在产生相对应的对象,也就是现有了概念再有了实体 class Garen: camp = 'Demacia' def attack(self): print('attack') 1.如何使用类 在python3:

反射与元类

1.isinstance与issubclass 在介绍反射之前,先来介绍两个关于类的内置方法,第一个是用来判断对象是否是某一类的对象(以前常说的判断是否是某一类型,类与类型其实是一个概念),第二个则是用来判断某一类是否是继承了另一个类 l=list([1,2,3]) print(isinstance(l,list)) #True class People: def __init__(self): pass class Chinese(People): def __init__(self): pa

python3全栈开发-内置函数补充,反射,元类,__str__,__del__,exec,type,__call__方法

一.内置函数补充 1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() print(isinstance(obj, Foo)) #结果为True 2.issubclass(sub, super)检查sub类是否是 super 类的派生类 class Foo(object): pass class Bar(Foo): pass print(issubclass(Bar, Foo)) #结果为True

python面向对象高级:反射、魔法方法、元类

自省/反射什么是反射?自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的.并且在python里,反射可以使得程序运行时对象拥有增删改查它本身属性或行为的一种能力如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作.还有那些特殊属性,像__dict__,__name__及__doc__反射的使用场景? 即插即用,即可以事先定义好接口,接口只有在被完成后才会真正执行 比如:如果和别人共同合作开发项目,但是需要用到对方的类的方法,对方还没完成 f1=FtpC