Python学习之旅 —— 基础篇(七)反射、冒泡排序算法

时间:2021-05-29 11:11:12
本篇要点:
冒泡算法
反射
 
一、冒泡排序
  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码示例:
li = [5, 67, 2, 8, 5, 19, 6, 33, 98, ]

times = len(li)
for i in range(times):
    for j in range(times-1):
        if li[j] > li[j+1]:
            li[j], li[j+1] = li[j+1], li[j]
print(li)
结果:
[2, 5, 5, 6, 8, 19, 33, 67, 98]
 
### 插入排序、选择排序
 
二、反射
有时候我们想要导入某个模块的某个方法,或者需要对对象的某个参数赋值,需要通过参数传递字符串的形式输入。在这样的情况你会选择什么样的办法来解决吗?例如:
# 模块 commons.py
def home():
    print("主页面")
 
def login():
    print("登录页面")
 
def logout():
    print("退出页面")
 
# index.py 导入模块
import commons
 
def run():
    inp = input("请输入要访问的URL: ")
    if inp == "home":
        commons.home()
    elif inp == "login":
        commons.login()
    elif inp == "logout":
        commons.logout()
    else:
        print("404")
 
if __name__ == '__main__':
    run()
 

 

在上面的代码中使用if语句的话,就是你每写一个方法就得有一个elif语句来判断,假如有1000个方法,这样就得有1000个elif语句。这么看实在是弱爆了。有没有更简单的方法实现字符串参数转换成函数名?那就要使用到反射了。修改后的代码如下:
# 模块 commons.py
def home():
    print("主页面")
 
def login():
    print("登录页面")
 
def logout():
    print("退出页面")
 
# index.py 导入模块
import commons
 
def run():
    inp = input("请输入要访问的URL: “)  # 字符串类型
    # 利用字符串的形式去对象(模块)中操作(检查、查找、修改、删除)成员
    # delattr()、setattr()  在内存中进行操作
    # 通过hasattr()判断函数是否存在
    if hasattr(commons, inp):
        # 通过反射执行commons模块中的函数
        func = getattr(commons, inp)
        func()
    else:
        print("404")
 
if __name__ == '__main__':
    run()
 
现在只有一个模块,如果有1000个模块,难道要导入1000次?当然不用,我们引入__import__()函数,来实现字符串转换成模块引入。代码如下:
# 模块account.py
def login():
    print("登录页面")
 
def logout():
    print("退出页面")
 
# 模块commons.py
def home():
    print("主页面")
 
# 模块manager.py
def order():
    print("订单页面")
 
# 主函数 index.py 导入模块
def run():
    # account/login格式
    inp = input("请输入要访问的URL: ")
    m, f = inp.split("/“)  # 将account/login格式分割成两部分 m="account",f="login”  m,f 都是字符串
    obj = __import__(m)  # 导入名字为account的模块
    
    # 通过反射实现模块中函数的调用
    if hasattr(obj, f):
        func = getattr(obj, f)
        func()
    else:
        print("404")
 
if __name__ == '__main__':
    run()
 
上面的例子其实是伪造了web框架的路由系统。
补充:
__import__("libs.aaa.bbb", fromlist=True)   # 支持目录的拼接,否则只能导入libs
 
如果完整的软件包想要实现更高的可移植性,需要把文件的主目录放到sys.path中,方便模块的导入,方法如下:
def add_path():
    # 添加程序的执行路径
    import os
    import sys
    # ps.path.abspath(__file__) 获取当前执行文件的绝对路径
    # os.path.dirname() 获取当前路径的上一层路径
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # 一直找到主目录为止,然后将主目录添加到sys.path
 
# __name__ 只有再执行当前文件时,__name__ =__main__,导入不执行
if __name__ == '__main__':
    add_path()