1.sys模块之stdout,stderr
查阅以下python文档可知:任何object及其派生类只要重写了write()方法,均可以替换sys.stdout,sys.stderr.所以
sys.stdin
sys.stdout
sys.stderr
File objects corresponding to the interpreter’s standard input, output and error streams. stdin is used for all interpreter
input except for scripts but including calls to input() and raw_input(). stdout is used for the output of print and expression
statements and for the prompts of input() and raw_input(). The interpreter’s own prompts and (almost all of) its error messages
go to stderr. stdout and stderr needn’t be built-in file objects: any object is acceptable as long as it has a write() method
that takes a string argument.
基于此,sqlmap作者有以下代码(sqlmap.py中第3部分中):
sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
那么此处的StdDbOut又是什么呢?
在lib\utils\api.py中可以看到Class StdDbOut的定义:代码主要就是上面说的那些,重写了write,并赋值替换sys.stdout,sys,stderr。
题外话:
a. write方法中
def write(self, value, status=CONTENT_STATUS.IN_PROGRESS, content_type=None)
看看CONTENT_STATUS的定义才发现作者把class当作enum来使了,不太清楚python中的enum
b. write方法中
if kb.partRun is not None:
content_type = PART_RUN_CONTENT_TYPES.get(kb.partRun)
看到kb,挺眼熟的,一翻才发现就是下面的dict的包装类
kb = AttribDict()
....
class AttribDict(dict):
....
2.dict
之前有在博文中提到sqlmap中用了封装的dict,就是作者自定义一个类型继承自dict.
阅读作者源代码中不可避免的遇到了原生dict的相关特性,故此,需要参考pydoc
首先了解下dict,可知其键值必须为hashable,value可以为任意。所谓hashable,参见(https://docs.python.org/2/glossary.html#term-hashable),简单来说呢,就是在生存
期内,值不能发生变化,与mutable相对。所以,dict的key不能为list,dict,set.具体请参见pydoc.
至于源码中的self.__dict__()
object.__dict__
A dictionary or other mapping object used to store an object’s (writable) attributes.
self.__class__
instance.__class__
The class to which a class instance belongs.
此处有个小知识点:
if "_AttribDict__initialised" not in self.__dict__:
这里的_AttribDict__initialised实际是
self.__initialised = True
的变形。具体参见(
http://blog.csdn.net/my2010sam/article/details/10949717)
另,此处的self.__getitem__应该是db['xxx']的实现,但是没有找到这个方法的说明,猜的,作者是怎么知道的?
最后再来看看那个深拷贝函数:
def __deepcopy__(self, memo):
retVal = self.__class__()
memo[id(self)] = retVal
for attr in dir(self):
if not attr.startswith('_'):
value = getattr(self, attr)
if not isinstance(value, (types.BuiltinFunctionType, types.BuiltinFunctionType, types.FunctionType, types.MethodType)):
setattr(retVal, attr, copy.deepcopy(value, memo))
for key, value in self.items():
retVal.__setitem__(key, copy.deepcopy(value, memo))
return retVal
说白了,是把凡是不能直接拷贝的如对象的id,对象的私有变量,对象中的内建函数和方法属性都特殊处理,其他的都用直接拷贝。
首先是字典整体的属性的处理,后面是字典中每个对象(键值对)的拷贝。
多说一句,那个id就是内存地址。
关于深拷贝参考(http://www.01happy.com/python-shallow-copy-and-deep-copy/)