Python reflection mechanism and dynamic module import

Python reflection can be understood as using the form of strings to manipulate member properties and methods in objects.

Consider a scenario where different functions are called to perform different operations according to the URL entered by the user:

# commons.py
def login():
    print('登录页面!')
 
def logout():
    print('退出页面!')
 
def index():
    print('主页面!')
 
# index.py
import commons
 
def run():
    inp = input("请输入您想访问页面的URL:").strip()
    if inp == "login":
        commons.login()
    elif inp == "logout":
        commons.logout()
    elif inp == "index":
        commons.index()
    else:
        print("404")
 
if __name__ == '__main__':
    run()

We run index.py, enter: index, the page results are as follows:

$ python3 index.py
请输入您想访问页面的URL:index
主页面!

This realizes a simple WEB routing function, and executes different functions according to different urls to obtain different pages. Now if my website has more content, and there are 100 page operations in commons.py, then correspondingly, I also need to use if else in index.py to manually specify these 100 page functions. Obviously this is impossible! So how to break? At this time, the Python reflection feature can come in handy.

# index.py
import commons
 
def run():
    inp = input('请输入您想访问页面的URL:').strip()
    if hasattr(commons, inp):
        func = getattr(commons, inp)
        func()
    else:
        print('404')
 
if __name__ == "__main__":
    run()

In the actual use environment, page processing functions are often categorized and placed in different modules in different directories. For example, now I have added a new account.py user management file, which also needs to be imported to the home page for invocation.

The __import__ method will dynamically import the module with the same name according to the string parameter.

# account.py
def add_user():
    print('添加用户')
 
def del_user():
    print('删除用户')
 
# commons.py
def login():
    print('登录页面!')
 
def logout():
    print('退出页面!')
 
def index():
    print('主页面')
 
# index.py
def run():
    inp = input('请输入您想访问页面的URL:').strip()
    m, f = inp.split('/')
    obj = __import__(m)
    if hasattr(obj, f):
        func = getattr(obj, f)
        func()
    else:
        print('404')
 
if __name__ == "__main__":
    run()

There is a small flaw here! If my project further refines the division of labor, there is now an additional layer of directory structure, as shown below:

|- index.py
|- commons.py
|- account.py
|- lib
	|- __init__.py
	|- connectdb.py

connectdb.py has the following methods:

def mysql():
    print('连接成功!')

How to solve this problem? There is a fromlist parameter in the __import__ function. The source code explains that if a module is imported in a package, if this parameter is empty, the package object will be returned. If this parameter is not empty, the module object specified under the package will be returned. So make the following changes:

# index.py
def getf(m, f):
    if hasattr(m, f):
        func = getattr(m, f)
        func()
    else:
        print('404')
 
def run():
    if len(inp.split('/')) == 2:
        m, f = inp.split('/')
        obj = __import__(m)
        getf(obj, f)
    elif len(inp.split('/')) == 3:
        p, m, f = inp.split('/')
        obj = __import__(p + '.' + m, fromlist=True)
        getf(obj, f)
    else:
        print('404')
 
if __name__ == "__main__":
    inp = input('请输入您想访问页面的URL:')
    run()

Now run the test:

$ python3 index.py
请输入您想访问页面的URL:commons/index
主页面!

$ python3 index.py
请输入您想访问页面的URL:lib/connectdb/mysql
连接成功!

Further improvements:

# index.py
def getf(m, f):
    if hasattr(m, f):
        func = getattr(m, f)
        func()
    else:
        print('404')
 
def run():
    t = inp.split("/")
    f = t[-1]
    p = '.'.join(t[0:-1])
    obj = __import__(p, fromlist=True)
    getf(obj, f)
    else:
        print('404')
 
if __name__ == "__main__":
    inp = input('请输入您想访问页面的URL:')
    run()

exec and eval also have their stage, and are often used in web frameworks.

Reference: something about operation and maintenance

Guess you like

Origin blog.csdn.net/azenlijing/article/details/129780191