一.消除if…else
因为代码中涉及到太多的if…else. 本来想使用策略模式 + 工厂模式 (消除if…else). 但是由于项目起始没有考虑代码设计模式, 导致现在改动会花费增加很大的工作量. 所以只能想其他的办法.
-
之前对
jumpserver
进行二次开发时, 研究过核心代码. 发现代码中使用了大量的getattr
, 里面getattr主要是用在函数调用上. 比如下面我截取部分代码def run_command(self, func_name, args): """ Attempts to run the given command. If the command does not execute, or there are any problems validating the given GET vars, an error message is set. func: the name of the function to run (e.g. __open) command_variables: a list of 'name':True/False tuples specifying which GET variables must be present or empty for this command. """ if not self.check_command_args(args): self.response['error'] = 'Invalid arguments' print("++++++++++++++++++++++++++++++++ not valid") return func = getattr(self, '_' + self.__class__.__name__ + func_name, None) if not callable(func): self.response['error'] = 'Command failed' return try: func() except Exception as e: self.response['error'] = '%s' % e logger.error("Error occur ------------------------------") logger.exception(e) logger.error("Error end ------------------------------")
getattr
是python里的一个内建函数,在python的官方文档中:getattr()的解释:getattr(object, name[, default])
Return the value of the named attribute of object. name must be a string. If the string is the name of one of the object’s attributes, the result is the value of that attribute. For example, getattr(x, ‘foobar’) is equivalent to x.foobar. If the named attribute does not exist, default is returned if provided, otherwise AttributeError is raised.
getattr()
这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。这也是python中的所说的自省
这样,- 你就可以把一个类可能要调用的方法放在配置文件里,在需要的时候动态加载。
-
python里面跟
getattr
相关的有hasattr,setattr,delattr
,那么我们通过下面的例子,来详细的说说他们的用法。
二. 反射机制
-
hasattr(object,name)
- bool 判断object中是否具有name属性,例如:
foo = test()
hasattr(foo,’setName’) #判断setName是否存在,存在则返回True。
2.getattr(object,name,default)
-
如果存在name属性(方法)则返回name的值(方法地址)否则返回default值。
# foo.py
def name():
return "hello"
# main.py
import foo
getattr(foo,'name',"default value") # 存在name属性,所以返回其value
# "hello"
getattr(foo,'test',None)
# None
-
这里函数的调用方式.
3.setattr(object,name,default)
-
为类设置一个新的属性
class Foo(object):
def __init__(self,sex):
self.sex = sex
foo = Foo('man') # 实例化类
setattr(Foo,'age',18) # 设置一个新的属性
foo.age
# 18
-
改变原有的类属性的值
class Foo(object):
def __init__(self,sex):
self.sex = sex
foo = Foo('man') # 实例化类
setattr(Foo,'sex','woman') # 设置一个新的属性
foo.sex
# woman
4.delattr(object,'name')
-
删除类属性
delattr(foo,'sex') #删除属性sex,原值为`woman`
getattr(foo,'sex','not find')
#'not find''
三.getattr 详解
本篇重点是讲述getattr
的用法
1. 函数
- demo.py
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
import time
def hello(a, b):
print('hello')
return a, b
def test_sleep(a, b):
print('test_sleep')
time.sleep(3)
return a, b
- main.py
#!/usr/bin/env python # ~*~ coding: utf-8 ~*~ import multiprocessing import demo def run(func, *args): print(getattr(demo, func)(*args)) if __name__ == "__main__": run('hello', "a", "b") pool = multiprocessing.Pool(processes=4) for i in range(10): pool.apply_async(run, ('hello', 'a', 'b')) pool.apply_async(run, ('test_sleep', 'a', 'b')) pool.close() pool.join() print("END ")
定义一个字符串,然后用
getattr
去执行,这样调用效果有些类似python的celery那种用globals的用法。 传递一个函数的名字,当然是字符串,用multiprocessing多进程调用这个方法。