python-面向对象-反射

isinstance 和 issubclass

isinstance(obj,cls)检查是否obj是否是类的cls的对象

class Test:
    def __init__(self, var):
        self.var = var

    def show(self):
        print("哈哈!")


t = Test('test')
a = 'test'

print(isinstance(t, Test))  # True
print(isinstance(a, Test))  # False

isinstance和type区别

class Test(object): pass


class Test_son(Test): pass


t1 = Test()
t2 = Test_son()
print(isinstance(t2, Test))  # True  # 承认继承关系
print(type(t2) is Test)  # False   # 不承认继承关系

a = 10

print(type(a) is int)  # True
print(isinstance(a, int))  # True


# isinstance(obj,类)
    # 承认继承关系的
# 类 = type(obj)
    # 只承认实例化这个对象的那个类(不承认所有的继承关系)

issubclass(sub,super)检查sub类是否是super类的派生类

class Test:
    def __init__(self, var):
        self.var = var

    def show(self):
        print("哈哈!")


class Test1(Test):
    pass


print(issubclass(Test1, Test))  # True

反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。python面向对象中的反射:通过字符串的形式操作对象相关的属性

  • hasattr 检测是否含有某个属性
  • gatattr 获取属性
  • setattr 设置属性
  • delattr 删除属性
class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        print("哈哈哈!")


obj = Foo("Tom", 14)

#检测某个属性

print(hasattr(obj, 'age'))  # True
print(hasattr(obj, 'sex'))  # False
print(hasattr(obj, 'show'))  # True


# 获取属性

print(getattr(obj,'age'))  # 14
print(getattr(obj,'show'))  # <bound method Foo.show of <__main__.Foo object at 0x0000025D610AF940>>
# print(getattr(obj, 'sex'))  # error AttributeError: 'Foo' object has no attribute 'sex'


# 修改属性

print(obj.__dict__)  # {'name': 'Tom', 'age': 14}
print(setattr(obj, 'sex', "male"))
print(obj.__dict__)  #{'name': 'Tom', 'age': 14, 'sex': 'male'}

print(setattr(obj, 'name', "Yang"))
print(obj.__dict__)  # {'name': 'Yang', 'age': 14, 'sex': 'male'}


# 删除属性
print(obj.__dict__)  # {'name': 'Yang', 'age': 14, 'sex': 'male'}
print(delattr(obj, "name"))
print(obj.__dict__)  # {'age': 14, 'sex': 'male'}

print(delattr(obj,'func'))  # Error AttributeError: func

反射的详细说明:

看下面的代码,是没有使用反射的

class Manager:  # 管理员用户
    def __init__(self, name):
        self.name = name

    def create_course(self):  # 创建课程
        print('in Manager create_course')

    def create_student(self):  # 给学生创建账号
        print('in Manager create_student')

    def show_courses(self):  # 查看所有课程
        print('in Manager show_courses')

    def show_students(self):  # 查看所有学生
        print('in Manager show_students')


# 不用反射
tim = Manager('Tim')
operate_lst = ['创建课程', '创建学生账号', '查看所有课程', '查看所有学生']
for index, opt in enumerate(operate_lst, 1):
    print(index, opt)
num = input('请输入您要做的操作 :')
if num.isdigit():
    num = int(num)
if num == 1:
    tim.create_course()
elif num == 2:
    tim.create_student()
elif num == 3:
    tim.show_courses()
elif num == 4:
    tim.show_students()


使用反射之后:

tim = Manager('Tim')

operate_lst = [('创建课程', 'create_course'), ('创建学生账号', 'create_student'),
               ('查看所有课程', 'show_courses'), ('查看所有学生', 'show_students')]
for index, opt in enumerate(operate_lst, 1):
    print(index, opt[0])
num = input('请输入您要做的操作 :')
if num.isdigit():
    num = int(num)
    if hasattr(tim, operate_lst[num - 1][1]):
        getattr(tim, operate_lst[num - 1][1])()

如果使用反射呢?

# 对象名.属性名 / 对象名.方法名() 可以直接使用对象的方法和属性
# 当我们只有字符串数据类型的内容的时候
    # getattr(对象名,'方法名')()
    # getattr(对象名,'属性名')

类反射

class A(object):
    Country = "China"

    @classmethod
    def show(cls):
        print("国家:", cls.Country)


getattr(A, "show")()  # 等价于A.show()
print(getattr(A, "Country"))  # 等价于print(A.Country)

反射在模块中

import re

res = re.findall("\d+", "1abcdef123a123")
print(res)  # ['1', '123', '123']

# 使用反射
res1 = getattr(re, 'findall')("\d+", "1abcdef123a123")
print(res1)  # ['1', '123', '123']

# getattr(re,'findall') 等价于re.findall

import time

now = time.time()
print(now)  # 1554102738.7555645
res = getattr(time, "time")()
print(res)  # 1554102738.7555645

# getattr(time, "time") 等价于time.time
# 只要是a.b这种结构,都可以使用反射
# 用对象\类\模块反射,都只有以下场景
# 这种结构有两种场景
    # a.b   b是属性或者变量值
        # getattr(a,'b')   == a.b
    # a.b()  b是函数或者方法
        # a.b()
            # getattr(a,'b')()
        # a.b(arg1,arg2)
            # getattr(a,'b')(arg1,arg2)
        # a.b(*args,**kwargs)
            # getattr(a,'b')(*args,**kwargs)

反射在当前文件中的使用

怎么样查看本文件下的a变量,func函数。而不是使用打印的方式。

def func():
    print("func")

a = 999

解决这个问题,需要导入内置的模块,sys,在sys中的modules方法,就所以的模块列举出来。

from sys import modules
print(modules)

20190401152836.png

上图片中标注出来的就当前的文件,则就可通过字典进行访问,而key就是"__main__",在访问当前的文件,也可以直接使用__name__。

print(__name__)  # __main__  打印__name___ 直接是__main__

from sys import modules
a = 999

def func():
    print("func")


print(modules['__main__'].a)  # 999
modules["__main__"].func()  # func

print(modules[__name__].a)  # 999
modules[__name__].func()  # func

from sys import modules

a = 999


def func():
    print("func")


class Test(object):
    Country = "China"

    @classmethod
    def show(cls):
        print("国家:", cls.Country)


# print(modules['__main__'].a)  # 999
# modules["__main__"].func()  # func
#
# print(modules[__name__].a)  # 999
# modules[__name__].func()  # func
if hasattr(modules[__name__], 'a'):
    print(getattr(modules[__name__], 'a'))  # 999
if hasattr(modules[__name__], 'func'):
    getattr(modules[__name__], 'func')()

if hasattr(modules[__name__], 'Test'):
    print(Test)  # <class '__main__.Test'>
    print(getattr(modules[__name__], 'Test'))  # <class '__main__.Test'>
    print(getattr(modules[__name__], 'Test').Country)  # China
    getattr(modules[__name__], 'Test').show()  # 国家: China

setattr

能够通过字符串数据类型的变量名 给一个对象创建一个新的属性

class A(object):
    def func(self):
        print("func")


a = A()
print(a.__dict__)  # {}
a.name = "Tom"
setattr(a, "name1", "Jack")  # 相当于a.name1 = "Jack"
print(a.__dict__) # {'name': 'Tom', 'name1': 'Jack'}

deltattr

print(a.__dict__)  # {'name': 'Tom', 'name1': 'Jack'}
delattr(a, 'name1')
print(a.__dict__)  # {'name': 'Tom'}
del a.name
print(a.__dict__)  # {}

总结:

# hasattr和getattr
    # 只要是a.b这种结构,都可以使用反射
    # 用对象\类\模块反射,都只有以下场景
    # 这种结构有两种场景
    #     a.b   b是属性或者变量值
    #         getattr(a,'b')   == a.b
    #     a.b()  b是函数或者方法
    #         a.b()
    #             getattr(a,'b')()
    #         a.b(arg1,arg2)
    #             getattr(a,'b')(arg1,arg2)
    #         a.b(*args,**kwargs)
    #             getattr(a,'b')(*args,**kwargs)
    # 如果是本文件中的内容,不符合a.b这种结构
        # 直接调用func()
            # getattr(sys.modules[__name__],'func')()
        # 直接使用类名 Person()
            # getattr(sys.modules[__name__],'Person')()
        # 直接使用变量名 print(a)
            # getattr(sys.modules[__name__],'a')
    # 所有的getattr都应该和hasattr一起使用
        # if hasattr():
             getattr()
# setattr 只用来修改或者添加属性\变量,不能用来处理函数或者是其他方法
    # a.b = value
    # setattr(a,'b',value)
    
# delattr 只用来删除 属性\变量
    # del a.b 删除属性  相当于删除了a对象当中的b属性
    # delattr(a,'b')
posted @ 2019-08-04 22:23  yangchangjie  阅读(120)  评论(0编辑  收藏  举报