[Python实战] - No.15 Python中的反射

Python反射

这篇文章没有系统地解释什么是反射以及完整的Python反射机制,仅仅作为我之前使用反射解决问题的一个记录。

假设我们有以下文件:

E:.

├─package1
│ main.py
│ people.py
│ __init__.py

└─package2
animal.py
__init__.py

package1.people中的代码如下所示:

class People:
    def __init__(self,name):
        print("My name is {}".format(name))

    def say_hello(self,words):
        print(words)


def write(words):
    print("Writing:{}".format(words))

该文件中定义了一个People类,该类有一个含参构造函数和成员函数say_hellopeople模块中有一个函数write

package2.animal中的代码如下所示:

class Cat:
    def __init__(self,name):
        print("This is a cat named {}".format(name))

    def roar(self):
        print("meow meow meow")

该模块中仅有Cat类,其内部有一个含参构造函数和一个成员函数roar

我们在package1.main中编写reflection相关的代码。假设我们有以下需求:

A. 我们需要动态引入package1.people中的People类和write函数

import inspect
import types
from inspect import isfunction


"""The same package"""
# get class in module
module = __import__("people")
people_clazz = getattr(module,"People")
write_func = getattr(module,"write")

# create instance by reflection
print("Create an instance of people")
args = {"name":"xiaoming"}
p = people_clazz(**args)

# invoke function by reflection
write_func("An apple a day keep the doctor away!")

已知people和当前模块main在同一个包路径下,因此我们直接使用__import__("people") 来引入people模块。同时,使用我们使用getattr来获取module中的People类和write函数。

由于People类和write函数都是callable的,因此我们可以直接调用people_clazzwrite_func

Console Output:

Create an instance of people
My name is xiaoming
Writing:An apple a day keep the doctor away!

B. 获取一个module中所有函数(除去module自身的builtin的函数)

# get function of module
module_funcs = [func[0] for func in inspect.getmembers(module) if isinstance(func[1],types.FunctionType)]
# module_funcs = [func[0] for func in inspect.getmembers(module) if isfunction(func[1])] # the same as code above
print("Get functions from module",module_funcs)

inspect是Python中一个专门用于查询module,class,functionlive objects信息的模块。

我们获取people模块所有的成员函数/变量,并判断其是不是Function类型。

注意,注释部分的代码和其上方的代码功能是一样的。isfunction内部的实现也正是如此。

inspect.getmembers(module)返回的是一个list,其中的每个元素为tuple类型。tuple的第一个元素为变量名,第二个为变量类型。

Console Output:

Get functions from module [‘write’]

C. 获取一个类中所有的函数(类的魔法函数除外)

# get function of class
people_clazz_func = [func[0] for func in inspect.getmembers(people_clazz) if not func[0].startswith("_")]
print("Get member function of class people",people_clazz_func)

同上面的代码。

注意,这里我判断过滤掉了那些以_开头的函数,以此来过滤掉类的魔法函数。但是这样也会过滤掉自身定义的以_开头的函数。

Console Output:

Get member function of class people [‘say_hello’]

D. 获取一个函数的参数:

# get arguments of function
people_init_args = inspect.getargs(people_clazz.__init__.__code__)
print("Get arguments from class member function",people_init_args.args)
write_args = inspect.getargs(write_func.__code__)
print("Get arguments from module function",write_args.args)

这里我展示了两种类型的函数。一个是类的成员函数,一个是普通的函数。用法都是一样的,使用inspect.getargs 和 函数的__code__属性来获取参数变量。

注意,如果想获取列表类型的参数,需要使用args属性。

Console Output:

Get arguments from class member function [‘self’, ‘name’]
Get arguments from module function [‘words’]

E. 被引入模块和当前文件不在同一个包内

"""Different package"""
module_package, cat_class = "package2.animal", "Cat"
module = __import__(module_package, globals(), locals(), [cat_class])
cat_clazz = getattr(module, cat_class)
args = {"name":"puppy"}
c = cat_clazz(**args)
c.roar()

稍微复杂了一些,但是原理是一样的,只是__import__多传入了包名以及globals(), locals()等参数。

Console Output:

This is a cat named puppy
meow meow meow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值