Python快速入门教程2:Python 面向对象

来源:互联网 发布:mac安装完win7启动失败 编辑:程序博客网 时间:2024/05/19 02:05
第2部分:Python 面向对象

1、类与对象

1.1 定义类

    通常你需要在单独的文件中定义一个类
    [root@hadron python]# vi Employee.py
    #!/usr/bin/python    # -*- coding: UTF-8 -*-    #定义类    class Employee:        '所有员工的基类'  #类文档字符串        #类变量           empCount = 0           #类的构造函数或初始化方法,name和salary为实例变量           def __init__(self, name, salary):              self.name = name              self.salary = salary              Employee.empCount += 1           def displayCount(self):             print "Total Employee %d" % Employee.empCount           def displayEmployee(self):             print "Name : ", self.name,  ", Salary: ", self.salary    "创建 Employee 类的第一个对象"    emp1 = Employee("Zara", 2000)    "创建 Employee 类的第二个对象"    emp2 = Employee("Manni", 5000)    emp1.displayEmployee()    emp2.displayEmployee()    #操作属性    setattr(emp1, 'salary',8000)    print getattr(emp1, 'salary')    print "Total Employee %d" % Employee.empCount
    [root@hadron python]# python Employee.py
    Name :  Zara , Salary:  2000
    Name :  Manni , Salary:  5000
    8000
    Total Employee 2

1.2 Python内置类属性
    __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
    __doc__ :类的文档字符串
    __name__: 类名
    __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
    __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)


对象销毁(垃圾回收)
    Python 使用了引用计数这一简单技术来跟踪和回收垃圾。
    在 Python 内部记录着所有使用中的对象各有多少引用。
    一个内部跟踪变量,称为一个引用计数器。
    当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。
    但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。
    垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。

   析构函数 __del__
    [root@hadron python]# vi Point.py
    #!/usr/bin/python    # -*- coding: UTF-8 -*-    class Point:       def __init__( self, x=0, y=0):          self.x = x          self.y = y       def __del__(self):          class_name = self.__class__.__name__          print class_name, "销毁"    pt1 = Point()    pt2 = pt1    pt3 = pt1    print id(pt1), id(pt2), id(pt3) # 打印对象的id    del pt1    del pt2    del pt3
    [root@hadron python]# python Point.py
    140262137177296 140262137177296 140262137177296
    Point 销毁

2、类的继承
    基类名写在括号里,基本类是在类定义的时候,在元组之中指明的。如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
    1)在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
    2)在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
    3)Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
    [root@hadron python]# vi Parent.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    class Parent:        # 定义父类
       parentAttr = 100
       def __init__(self):
          print "调用父类构造函数"
       def parentMethod(self):
          print '调用父类方法'
       def setAttr(self, attr):
          Parent.parentAttr = attr
       def getAttr(self):
          print "父类属性 :", Parent.parentAttr

    class Child(Parent): # 定义子类
       def __init__(self):
          print "调用子类构造方法"
       def childMethod(self):
          print '调用子类方法 child method'

    c = Child()          # 实例化子类
    c.childMethod()      # 调用子类的方法
    c.parentMethod()     # 调用父类方法
    c.setAttr(200)       # 再次调用父类的方法
    c.getAttr()          # 再次调用父类的方法
    [root@hadron python]# python Parent.py
    调用子类构造方法
    调用子类方法 child method
    调用父类方法
    父类属性 : 200

方法重写
    [root@hadron python]# vi override.py
    
#!/usr/bin/python    # -*- coding: UTF-8 -*-    class Parent:        # 定义父类       def myMethod(self):          print '调用父类方法'    class Child(Parent): # 定义子类       def myMethod(self):          print '调用子类方法'    c = Child()          # 子类实例    c.myMethod()         # 子类调用重写方法

    [root@hadron python]# python override.py
    调用子类方法

基础重载方法
    1) __init__ ( self [,args...] ),构造函数,简单的调用方法: obj = className(args)
    2) __del__( self ),析构方法, 删除一个对象,简单的调用方法 : dell obj
    3) __repr__( self ),转化为供解释器读取的形式,简单的调用方法 : repr(obj)
    4) __str__( self ),用于将值转化为适于人阅读的形式,简单的调用方法 : str(obj)
    5)__cmp__ ( self, x ),对象比较,简单的调用方法 : cmp(obj, x)
    [root@hadron python]# vi Vector.py
    
#!/usr/bin/python    # -*- coding: UTF-8 -*-    class Vector:       def __init__(self, a, b):          self.a = a          self.b = b       def __str__(self):          return 'Vector (%d, %d)' % (self.a, self.b)       def __add__(self,other):          return Vector(self.a + other.a, self.b + other.b)       def __cmp__(self,x):          if self.a>x.a and self.b>x.b:          return 1          elif self.a==x.a and self.b==x.b:          return 0          else:          return -1    v1 = Vector(2,10)    v2 = Vector(5,-2)    print v1 + v2    print cmp(v1,v2)


    [root@hadron python]# python Vector.py
    Vector (7, 8)
    -1


类属性与方法
    1)类的私有属性
    __private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
    2)类的方法
    在类地内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数
    3)类的私有方法
    __private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods

    [root@hadron python]# vi private.py
    
#!/usr/bin/python    # -*- coding: UTF-8 -*-    class JustCounter:        __x = 0  # 私有变量        y = 0    # 公开变量        def __f(self):                print "私有方法",self.__x,self.y        def count(self):                self.__x += 1                self.y += 1                print self.__x                self.__f()    c1 = JustCounter()    c1.count()    c2=JustCounter()    c2.count()    print c2.y

    [root@hadron python]# python private.py
    1
    私有方法 1 1
    1
    私有方法 1 1
    1

    问题是当我们要调用其中的函数的时候,如何让脚本知道是我们到底是想让它直接运行还是只是作为模块引入另外一个脚本呢?
    .py有两种使用方式,一种是作为模块被调用,另外一种是直接运行。那么如何判断呢?
    在main()函数前加入了一个判断语句,以此来让脚本判断自己是被当做模块调用,还是被直接运行的。
    当被import作为模块调用的时候,if以下的代码就不会被执行,也就是说main()函数不会被执行。
    #!/usr/bin/env python
    #A system information gathering script
    import subprocess    
    #command 1
    def uname_func()
        uname = "uname"
        uname_arg = "-a"
        print "gathering system information with $s command:\n" % uname
        subprocess.call([uname,uname_arg])
    #command 2
    def disk_func()
        diskspace = "df"
        diskspace_arg = "-h"
        print "gathering diskspace information %s command:\n"  %  diskspace
        subprocess.call([diskspace,diskspace_arg])
    #main function that call other functions
    def main()
        uname_fun()
        diskspace_fun()
    if __name__== "__main__":
        main()
    总结一下:
    如果我们是直接执行某个.py文件的时候,该文件中那么”__name__ == '__main__'“是True,
    但是我们如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__。

    这个功能还有一个用处:调试代码的时候,在”if __name__ == '__main__'“中加入一些我们的调试代码,我们可以让外部模块调用的时候不执行我们的调试代码,
    但是如果我们想排查问题的时候,直接执行该模块文件,调试代码能够正常运行!

正则表达式
    Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
    re 模块使 Python 语言拥有全部的正则表达式功能。
    compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。
    re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。
    re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
    可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
    group()    返回被 RE 匹配的字符串(If a group matches multiple times, only the last match is accessible: )
    start()    返回匹配开始的位置
    end()    返回匹配结束的位置
    span()    返回一个元组包含匹配 (开始,结束) 的位置    
(1)
    [root@hadron python]# vi re1.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import re
    #re.match()返回的是一个对象,不成功返回的是none.
    #可以通过group(num)或groups()匹配对象函数来获取匹配表达式
    m=re.match("in", "in_contain_china")
    if m:
        print m
        print("match:is match")
        print m.group(),m.span()

    print '---------'
    s=re.search("ain","china_contain")
    if s:
        print s.group(),s.span()
    [root@hadron python]# python re1.py
    <_sre.SRE_Match object at 0x7f5b51d767e8>
    match:is match
    in (0, 2)
    ---------
    ain (10, 13)

    正则表达式修饰符 - 可选标志    
    re.I    使匹配对大小写不敏感
    re.L    做本地化识别(locale-aware)匹配
    re.M    多行匹配,影响 ^ 和 $
    re.S    使 . 匹配包括换行在内的所有字符
    re.U    根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
    re.X    该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

    正则表达式模式
    ^    匹配字符串的开头
    $    匹配字符串的末尾。
    .    匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。    
    [...]    字符集,用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k'
    [^...]    不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
    re*    匹配0个或多个的表达式。
    re+    匹配1个或多个的表达式。
    re?    匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
    re{ n}    
    re{ n,}    精确匹配n个前面表达式。
    re{ n, m}    匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
    a| b    匹配a或b
    (re)    子模式,匹配括号内的表达式,也表示一个组
    (?imx)    正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
    (?-imx)    正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
    (?: re)    类似 (...), 但是不表示一个组
    (?imx: re)    在括号中使用i, m, 或 x 可选标志
    (?-imx: re)    在括号中不使用i, m, 或 x 可选标志
    (?#...)    注释.
    (?= re)    前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
    (?! re)    前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
    (?> re)    匹配的独立模式,省去回溯。
    \w    匹配字母数字及下划线
    \W    匹配非字母数字及下划线
    \s    匹配任意空白字符,等价于 [\t\n\r\f].
    \S    匹配任意非空字符
    \d    匹配任意数字,等价于 [0-9].
    \D    匹配任意非数字
    \A    匹配字符串开始
    \Z    匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。c
    \z    匹配字符串结束
    \G    匹配最后匹配完成的位置。
    \b    匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
    \B    匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
    \n, \t, 等.    匹配一个换行符。匹配一个制表符。等
    \1...\9    匹配第n个分组的子表达式。
    \10    匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式。
    正则表达式实例
    [Pp]ython     匹配 "Python" 或 "python"
    rub[ye]    匹配 "ruby" 或 "rube"
    [aeiou]    匹配中括号内的任意一个字母
    [0-9]    匹配任何数字。类似于 [0123456789]
    [a-z]    匹配任何小写字母
    [A-Z]    匹配任何大写字母
    [a-zA-Z0-9]    匹配任何字母及数字
    [^aeiou]    除了aeiou字母以外的所有字符
    [^0-9]    匹配除了数字外的字符
    .    匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。
    \d    匹配一个数字字符。等价于 [0-9]。
    \D     匹配一个非数字字符。等价于 [^0-9]。
    \s    匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
    \S     匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
    \w    匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
    \W    匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。

    正则表达式使用反斜杠" \ "来代表特殊形式或用作转义字符.为了使正则表达式具有更好的可读性,Python特别设计了原始字符串(raw string).
    raw string就是用'r'作为字符串的前缀,如 r"\n":表示两个字符"\"和"n",而不是换行符了。Python中写正则表达式时推荐使用这种形式。

(2)
    [root@hadron python]# vi re2.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import re
    #可选标志
    s=re.search('abc','I have ABC',re.I)
    if s:
       print s.group()
    #spit()按照能够匹配的子串将string分割后返回列表
    p = re.compile(r'\d+')
    print p.split('one1two2three3four4')
    #检索和替换
    #Python 的 re 模块提供了re.sub用于替换字符串中的匹配项
    phone = "2004-959-559 # 这是一个国外电话号码"
    # 删除字符串中的 Python注释
    num = re.sub(r'#.*$', "", phone)
    print "电话号码是: ", num
    # 删除非数字(-)的字符串
    num = re.sub(r'\D', "", phone)
    print "电话号码是 : ", num
    [root@hadron python]# python re2.py
    ABC
    ['one', 'two', 'three', 'four', '']
    电话号码是:  2004-959-559
    电话号码是 :  2004959559
(3)
    [root@hadron python]# vi re3.py
     #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import re
    email = raw_input("Please input your Email:\n")
    #if re.match(r'[0-9a-zA-Z_]{0,19}@163.com',email):
    if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$',email)
        print('Email is Right!')
    else:
        print('Please reset your right Email address!')
    [root@hadron python]# python re3.py
    Please input your Email:
    hadron.cheng@qq.com
    Please reset your right Email address!
    [root@hadron python]# python re3.py
    Please input your Email:
    6172058@qq.com
    Email is Right!


Python中使用线程有两种方式:函数或者用类来包装线程对象。
    函数式:调用thread模块中的start_new_thread()函数来产生新线程
(1)    [root@hadron python]# vi mythread.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import thread
    import time
    # 为线程定义一个函数
    def print_time(threadName, delay):
       count = 0
       while count < 5:
          time.sleep(delay)
          count += 1
          print "%s: %s" % ( threadName, time.ctime(time.time()) )
    # 创建两个线程
    try:
       thread.start_new_thread( print_time, ("Thread-1", 2, ) )
       thread.start_new_thread( print_time, ("Thread-2", 4, ) )
    except:
       print "Error: unable to start thread"
    #是个死循环,主要是等待线程执行结束
    while 1:
       pass
    [root@hadron python]# python mythread.py
    Thread-1: Tue Jan 24 11:00:18 2017
    Thread-2: Tue Jan 24 11:00:20 2017
    Thread-1: Tue Jan 24 11:00:20 2017
    Thread-1: Tue Jan 24 11:00:22 2017
    Thread-2: Tue Jan 24 11:00:24 2017
    Thread-1: Tue Jan 24 11:00:24 2017
    Thread-1: Tue Jan 24 11:00:26 2017
    Thread-2: Tue Jan 24 11:00:28 2017
    Thread-2: Tue Jan 24 11:00:32 2017
    Thread-2: Tue Jan 24 11:00:36 2017

(2)    
    Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。
    使用Threading模块创建线程,直接从threading.Thread继承,然后重写__init__方法和run方法:

    [root@hadron python]# vi thread2.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import threading
    import time
    exitFlag = 0
    class myThread (threading.Thread):   #继承父类threading.Thread
        def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
        def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
        print "Starting " + self.name
        print_time(self.name, self.counter, 5)
        print "Exiting " + self.name
    def print_time(threadName, delay, counter):
        while counter:
        if exitFlag:
            thread.exit()
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1
    # 创建新线程
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    # 开启线程
    thread1.start()
    thread2.start()
    print "Exiting Main Thread"
    [root@hadron python]# python thread2.py
    Starting Thread-1
    Starting Thread-2
    Exiting Main Thread
    Thread-1: Tue Jan 24 11:05:04 2017
    Thread-2: Tue Jan 24 11:05:05 2017
    Thread-1: Tue Jan 24 11:05:05 2017
    Thread-1: Tue Jan 24 11:05:06 2017
    Thread-2: Tue Jan 24 11:05:07 2017
    Thread-1: Tue Jan 24 11:05:07 2017
    Thread-1: Tue Jan 24 11:05:08 2017
    Exiting Thread-1
    Thread-2: Tue Jan 24 11:05:09 2017
    Thread-2: Tue Jan 24 11:05:11 2017
    Thread-2: Tue Jan 24 11:05:13 2017
    Exiting Thread-2

(3)    线程同步
    使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。
    [root@hadron python]# vi thread3.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-

    import threading
    import time

    class myThread (threading.Thread):
        def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
        def run(self):
        print "Starting " + self.name
           # 获得锁,成功获得锁定后返回True
           # 可选的timeout参数不填时将一直阻塞直到获得锁定
           # 否则超时后将返回False
        threadLock.acquire()
        print_time(self.name, self.counter, 3)
        # 释放锁
        threadLock.release()

    def print_time(threadName, delay, counter):
        while counter:
        time.sleep(delay)
        print "%s: %s" % (threadName, time.ctime(time.time()))
        counter -= 1

    threadLock = threading.Lock()
    threads = []

    # 创建新线程
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)

    # 开启新线程
    thread1.start()
    thread2.start()

    # 添加线程到线程列表
    threads.append(thread1)
    threads.append(thread2)

    # 等待所有线程完成
    for t in threads:
        t.join()
    print "Exiting Main Thread"
    [root@hadron python]# python thread3.py
    Starting Thread-1
    Starting Thread-2
    Thread-1: Tue Jan 24 11:09:08 2017
    Thread-1: Tue Jan 24 11:09:09 2017
    Thread-1: Tue Jan 24 11:09:10 2017
    Thread-2: Tue Jan 24 11:09:12 2017
    Thread-2: Tue Jan 24 11:09:14 2017
    Thread-2: Tue Jan 24 11:09:16 2017
    Exiting Main Thread

(4)    Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue

    Queue.qsize() 返回队列的大小
    Queue.empty() 如果队列为空,返回True,反之False
    Queue.full() 如果队列满了,返回True,反之False
    Queue.full 与 maxsize 大小对应
    Queue.get([block[, timeout]])获取队列,timeout等待时间
    Queue.get_nowait() 相当Queue.get(False)
    Queue.put(item) 写入队列,timeout等待时间
    Queue.put_nowait(item) 相当Queue.put(item, False)
    Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
    Queue.join() 实际上意味着等到队列为空,再执行别的操作

    [root@hadron python]# vi thread4.py
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    import Queue
    import threading
    import time
    exitFlag = 0
    class myThread (threading.Thread):
        def __init__(self, threadID, name, q):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.q = q
        def run(self):
        print "Starting " + self.name
        process_data(self.name, self.q)
        print "Exiting " + self.name
    def process_data(threadName, q):
        while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print "%s processing %s" % (threadName, data)
        else:
            queueLock.release()
        time.sleep(1)
    threadList = ["Thread-1", "Thread-2", "Thread-3"]
    nameList = ["One", "Two", "Three", "Four", "Five"]
    queueLock = threading.Lock()
    workQueue = Queue.Queue(10)
    threads = []
    threadID = 1
    # 创建新线程
    for tName in threadList:
        thread = myThread(threadID, tName, workQueue)
        thread.start()
        threads.append(thread)
        threadID += 1
    # 填充队列
    queueLock.acquire()
    for word in nameList:
        workQueue.put(word)
    queueLock.release()
    # 等待队列清空
    while not workQueue.empty():
        pass
    # 通知线程是时候退出
    exitFlag = 1
    # 等待所有线程完成
    for t in threads:
        t.join()
    print "Exiting Main Thread"    
    [root@hadron python]# python thread4.py
    Starting Thread-1
    Starting Thread-2
    Starting Thread-3
    Thread-3 processing One
    Thread-1 processing Two
    Thread-2 processing Three
    Thread-3 processing Four
    Thread-1 processing Five
    Exiting Thread-2
     Exiting Thread-3
    Exiting Thread-1
    Exiting Main Thread


Python JSON
    [root@hadron 下载]# cp demjson-2.2.4.tar.gz /opt
    [root@hadron 下载]# cd /opt
    [root@hadron opt]# tar -zxvf demjson-2.2.4.tar.gz
    demjson-2.2.4/
    demjson-2.2.4/docs/
    demjson-2.2.4/docs/HOOKS.txt
    demjson-2.2.4/docs/demjson.txt
    demjson-2.2.4/docs/jsonlint.txt
    demjson-2.2.4/docs/NEWS.txt
    demjson-2.2.4/docs/PYTHON3.txt
    demjson-2.2.4/docs/INSTALL.txt
    demjson-2.2.4/docs/CHANGES.txt
    demjson-2.2.4/PKG-INFO
    demjson-2.2.4/README.md
    demjson-2.2.4/LICENSE.txt
    demjson-2.2.4/README.txt
    demjson-2.2.4/setup.py
    demjson-2.2.4/jsonlint
    demjson-2.2.4/demjson.py
    demjson-2.2.4/test/
    demjson-2.2.4/test/test_demjson.py
    [root@hadron opt]# cd demjson-2.2.4/
    [root@hadron demjson-2.2.4]#
    [root@hadron demjson-2.2.4]# python setup.py install
    running install
    running build
    running build_py
    creating build
    creating build/lib
    copying demjson.py -> build/lib
    running build_scripts
    creating build/scripts-2.7
    copying and adjusting jsonlint -> build/scripts-2.7
    changing mode of build/scripts-2.7/jsonlint from 644 to 755
    running install_lib
    copying build/lib/demjson.py -> /usr/lib/python2.7/site-packages
    byte-compiling /usr/lib/python2.7/site-packages/demjson.py to demjson.pyc
    running install_scripts
    copying build/scripts-2.7/jsonlint -> /usr/bin
    changing mode of /usr/bin/jsonlint to 755
    running install_egg_info
    Writing /usr/lib/python2.7/site-packages/demjson-2.2.4-py2.7.egg-info

    [root@hadron python]# vi json1.py
    #!/usr/bin/python
    import demjson
    data = [ { 'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4, 'e' : 5 } ]
    json = demjson.encode(data)
    print json
    [root@hadron python]# python json1.py
    [{"a":1,"b":2,"c":3,"d":4,"e":5}]

    [root@hadron python]# vi json2.py
    #!/usr/bin/python
    import demjson
    json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
    text = demjson.decode(json)
    print  text
    [root@hadron python]# python json2.py
    {u'a': 1, u'c': 3, u'b': 2, u'e': 5, u'd': 4}

Python XML解析
    常见的XML编程接口有DOM和SAX
    
(1)    python使用SAX解析xml
    python 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件    
    在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler
    ContentHandler类方法介绍
        characters(content)方法
            调用时机:
            从行开始,遇到标签之前,存在字符,content的值为这些字符串。
            从一个标签,遇到下一个标签之前, 存在字符,content的值为这些字符串。
            从一个标签,遇到行结束符之前,存在字符,content的值为这些字符串。
            标签可以是开始标签,也可以是结束标签。
        startDocument():文档启动的时候调用。
        endDocument():解析器到达文档结尾时调用。
        startElement(name, attrs):遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。
        endElement(name):遇到XML结束标签时调用。
    [root@hadron python]# vi mySAX.py
    
#!/usr/bin/python    # -*- coding: UTF-8 -*-    import xml.sax    class MovieHandler( xml.sax.ContentHandler ):       def __init__(self):          self.CurrentData = ""          self.type = ""          self.format = ""          self.year = ""          self.rating = ""          self.stars = ""          self.description = ""       # 元素开始事件处理       def startElement(self, tag, attributes):          self.CurrentData = tag          if tag == "movie":         print "*****Movie*****"         title = attributes["title"]         print "Title:", title       # 元素结束事件处理       def endElement(self, tag):          if self.CurrentData == "type":         print "Type:", self.type          elif self.CurrentData == "format":         print "Format:", self.format          elif self.CurrentData == "year":         print "Year:", self.year          elif self.CurrentData == "rating":         print "Rating:", self.rating          elif self.CurrentData == "stars":         print "Stars:", self.stars          elif self.CurrentData == "description":         print "Description:", self.description          self.CurrentData = ""       # 内容事件处理       def characters(self, content):          if self.CurrentData == "type":         self.type = content          elif self.CurrentData == "format":         self.format = content          elif self.CurrentData == "year":         self.year = content          elif self.CurrentData == "rating":         self.rating = content          elif self.CurrentData == "stars":         self.stars = content          elif self.CurrentData == "description":         self.description = content    if ( __name__ == "__main__"):       # 创建一个 XMLReader       parser = xml.sax.make_parser()       # turn off namepsaces       parser.setFeature(xml.sax.handler.feature_namespaces, 0)       # 重写 ContextHandler       Handler = MovieHandler()       parser.setContentHandler( Handler )       parser.parse("movies.xml")

    [root@hadron python]# python mySAX.py
    *****Movie*****
    Title: Enemy Behind
    Type: War, Thriller
    Format: DVD
    Year: 2003
    Rating: PG
    Stars: 10
    Description: Talk about a US-Japan war
    *****Movie*****
    Title: Transformers
    Type: Anime, Science Fiction
    Format: DVD
    Year: 1989
    Rating: R
    Stars: 8
    Description: A schientific fiction
    *****Movie*****
    Title: Trigun
    Type: Anime, Action
    Format: DVD
    Rating: PG
    Stars: 10
    Description: Vash the Stampede!
    *****Movie*****
    Title: Ishtar
    Type: Comedy
    Format: VHS
    Rating: PG
    Stars: 2
    Description: Viewable boredom
(2)    使用xml.dom解析xml
    一个 DOM 的解析器在解析一个 XML 文档时,一次性读取整个文档,把文档中所有元素保存在内存中的一个树结构里,
    之后你可以利用DOM 提供的不同的函数来读取或修改文档的内容和结构,也可以把修改过的内容写入xml文件。
    python中用xml.dom.minidom来解析xml文件
    [root@hadron python]# vi dom.py
    
#!/usr/bin/python    # -*- coding: UTF-8 -*-    from xml.dom.minidom import parse    import xml.dom.minidom    # 使用minidom解析器打开 XML 文档    DOMTree = xml.dom.minidom.parse("movies.xml")    collection = DOMTree.documentElement    if collection.hasAttribute("shelf"):       print "Root element : %s" % collection.getAttribute("shelf")    # 在集合中获取所有电影    movies = collection.getElementsByTagName("movie")    # 打印每部电影的详细信息    for movie in movies:       print "*****Movie*****"       if movie.hasAttribute("title"):          print "Title: %s" % movie.getAttribute("title")       type = movie.getElementsByTagName('type')[0]       print "Type: %s" % type.childNodes[0].data       format = movie.getElementsByTagName('format')[0]       print "Format: %s" % format.childNodes[0].data       rating = movie.getElementsByTagName('rating')[0]       print "Rating: %s" % rating.childNodes[0].data       description = movie.getElementsByTagName('description')[0]       print "Description: %s" % description.childNodes[0].data


    [root@hadron python]# python dom.py
    Root element : New Arrivals
    *****Movie*****
    Title: Enemy Behind
    Type: War, Thriller
    Format: DVD
    Rating: PG
    Description: Talk about a US-Japan war
    *****Movie*****
    Title: Transformers
    Type: Anime, Science Fiction
    Format: DVD
    Rating: R
    Description: A schientific fiction
    *****Movie*****
    Title: Trigun
    Type: Anime, Action
    Format: DVD
    Rating: PG
    Description: Vash the Stampede!
    *****Movie*****
    Title: Ishtar
    Type: Comedy
    Format: VHS
    Rating: PG
    Description: Viewable boredom

python操作mysql数据库
    MySQLdb 是用于Python链接Mysql数据库的接口,它实现了 Python 数据库 API 规范 V2.0
(1)    [root@hadron python]# vi mysql.py
   #!/usr/bin/python    # -*- coding: UTF-8 -*-    import MySQLdb
    [root@hadron python]# python mysql.py
    Traceback (most recent call last):
      File "mysql.py", line 4, in <module>
        import MySQLdb
    ImportError: No module named MySQLdb
    意味着你没有安装 MySQLdb 模块

(2)    [root@hadron 下载]# tar -zxvf MySQL-python-1.2.4b4.tar.gz -C /opt
    [root@hadron MySQL-python-1.2.4b4]# python setup.py build
    Downloading http://pypi.python.org/packages/source/d/distribute/distribute-0.6.28.tar.gz
    Extracting in /tmp/tmpz4y_0u
    Now working in /tmp/tmpz4y_0u/distribute-0.6.28
    Building a Distribute egg in /opt/MySQL-python-1.2.4b4
    /opt/MySQL-python-1.2.4b4/distribute-0.6.28-py2.7.egg
    sh: mysql_config: 未找到命令
    Traceback (most recent call last):
      File "setup.py", line 18, in <module>
        metadata, options = get_config()
      File "/opt/MySQL-python-1.2.4b4/setup_posix.py", line 43, in get_config
        libs = mysql_config("libs_r")
      File "/opt/MySQL-python-1.2.4b4/setup_posix.py", line 25, in mysql_config
        raise EnvironmentError("%s not found" % (mysql_config.path,))
    EnvironmentError: mysql_config not found
    [root@hadron MySQL-python-1.2.4b4]# yum install python-devel
    [root@hadron MySQL-python-1.2.4b4]# yum install mariadb-devel

    [root@hadron MySQL-python-1.2.4b4]# python setup.py build
    running build
    running build_py
    creating build
    creating build/lib.linux-x86_64-2.7
    copying _mysql_exceptions.py -> build/lib.linux-x86_64-2.7
    creating build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/__init__.py -> build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/converters.py -> build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/connections.py -> build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/cursors.py -> build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/release.py -> build/lib.linux-x86_64-2.7/MySQLdb
    copying MySQLdb/times.py -> build/lib.linux-x86_64-2.7/MySQLdb
    creating build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/__init__.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/REFRESH.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
    running build_ext
    building '_mysql' extension
    creating build/temp.linux-x86_64-2.7
    gcc -pthread -fno-strict-aliasing -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -Dversion_info=(1,2,4,'beta',4) -D__version__=1.2.4b4 -I/usr/include/mysql -I/usr/include/python2.7 -c _mysql.c -o build/temp.linux-x86_64-2.7/_mysql.o
    gcc -pthread -shared -Wl,-z,relro build/temp.linux-x86_64-2.7/_mysql.o -L/usr/lib64/mysql -L/usr/lib64 -lmysqlclient -lpthread -lz -lm -lssl -lcrypto -ldl -lpython2.7 -o build/lib.linux-x86_64-2.7/_mysql.so

    [root@hadron MySQL-python-1.2.4b4]# python setup.py install
    running install
    running bdist_egg
    running egg_info
    writing MySQL_python.egg-info/PKG-INFO
    writing top-level names to MySQL_python.egg-info/top_level.txt
    writing dependency_links to MySQL_python.egg-info/dependency_links.txt
    writing MySQL_python.egg-info/PKG-INFO
    writing top-level names to MySQL_python.egg-info/top_level.txt
    writing dependency_links to MySQL_python.egg-info/dependency_links.txt
    reading manifest file 'MySQL_python.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    writing manifest file 'MySQL_python.egg-info/SOURCES.txt'
    installing library code to build/bdist.linux-x86_64/egg
    running install_lib
    running build_py
    copying MySQLdb/release.py -> build/lib.linux-x86_64-2.7/MySQLdb
    running build_ext
    creating build/bdist.linux-x86_64
    creating build/bdist.linux-x86_64/egg
    creating build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/MySQLdb/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/MySQLdb/converters.py -> build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/MySQLdb/release.py -> build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/MySQLdb/times.py -> build/bdist.linux-x86_64/egg/MySQLdb
    creating build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/__init__.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/ER.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/FLAG.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/REFRESH.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/CR.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/FIELD_TYPE.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/constants/CLIENT.py -> build/bdist.linux-x86_64/egg/MySQLdb/constants
    copying build/lib.linux-x86_64-2.7/MySQLdb/connections.py -> build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/MySQLdb/cursors.py -> build/bdist.linux-x86_64/egg/MySQLdb
    copying build/lib.linux-x86_64-2.7/_mysql_exceptions.py -> build/bdist.linux-x86_64/egg
    copying build/lib.linux-x86_64-2.7/_mysql.so -> build/bdist.linux-x86_64/egg
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/__init__.py to __init__.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/converters.py to converters.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/release.py to release.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/times.py to times.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/__init__.py to __init__.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/ER.py to ER.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FLAG.py to FLAG.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/REFRESH.py to REFRESH.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CR.py to CR.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/FIELD_TYPE.py to FIELD_TYPE.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/constants/CLIENT.py to CLIENT.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/connections.py to connections.pyc
    byte-compiling build/bdist.linux-x86_64/egg/MySQLdb/cursors.py to cursors.pyc
    byte-compiling build/bdist.linux-x86_64/egg/_mysql_exceptions.py to _mysql_exceptions.pyc
    creating stub loader for _mysql.so
    byte-compiling build/bdist.linux-x86_64/egg/_mysql.py to _mysql.pyc
    creating build/bdist.linux-x86_64/egg/EGG-INFO
    copying MySQL_python.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO
    copying MySQL_python.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
    copying MySQL_python.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
    copying MySQL_python.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO
    writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt
    zip_safe flag not set; analyzing archive contents...
    creating dist
    creating 'dist/MySQL_python-1.2.4b4-py2.7-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it
    removing 'build/bdist.linux-x86_64/egg' (and everything under it)
    Processing distribute-0.6.28-py2.7.egg
    creating /usr/lib64/python2.7/site-packages/distribute-0.6.28-py2.7.egg
    Extracting distribute-0.6.28-py2.7.egg to /usr/lib64/python2.7/site-packages
    Adding distribute 0.6.28 to easy-install.pth file
    Installing easy_install script to /usr/bin
    Installing easy_install-2.7 script to /usr/bin

    Installed /usr/lib64/python2.7/site-packages/distribute-0.6.28-py2.7.egg
    Processing dependencies for distribute==0.6.28
    Finished processing dependencies for distribute==0.6.28
    Processing MySQL_python-1.2.4b4-py2.7-linux-x86_64.egg
    creating /usr/lib64/python2.7/site-packages/MySQL_python-1.2.4b4-py2.7-linux-x86_64.egg
    Extracting MySQL_python-1.2.4b4-py2.7-linux-x86_64.egg to /usr/lib64/python2.7/site-packages
    Adding MySQL-python 1.2.4b4 to easy-install.pth file

    Installed /usr/lib64/python2.7/site-packages/MySQL_python-1.2.4b4-py2.7-linux-x86_64.egg
    Processing dependencies for MySQL-python==1.2.4b4
    Finished processing dependencies for MySQL-python==1.2.4b4
    
(3)    [root@hadron python]# vi mysql.py
#!/usr/bin/python    # -*- coding: UTF-8 -*-    import MySQLdb    # 打开数据库连接    db = MySQLdb.connect("localhost","root","123456","test")    # 使用cursor()方法获取操作游标         cursor = db.cursor()    # 使用execute方法执行SQL语句        cursor.execute("SELECT VERSION()")    # 使用 fetchone() 方法获取一条数据库        data = cursor.fetchone()    print "Database version : %s " % data    db.close()
    [root@hadron python]# python mysql.py
    Database version : 5.5.52-MariaDB


(4)    [root@hadron python]# vi mysql2.py
#!/usr/bin/python    # -*- coding: UTF-8 -*-    import MySQLdb    # 打开数据库连接    db = MySQLdb.connect("localhost","root","123456","test")      # 使用cursor()方法获取操作游标    cursor = db.cursor()    # 如果数据表已经存在使用 execute() 方法删除表。    cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")    # 创建数据表SQL语句    sql = """CREATE TABLE EMPLOYEE (         FIRST_NAME  CHAR(20) NOT NULL,         LAST_NAME  CHAR(20),         AGE INT,           SEX CHAR(1),         INCOME FLOAT )"""    cursor.execute(sql)    print "创建表成功!"    # SQL 插入语句    sql = "INSERT INTO EMPLOYEE(FIRST_NAME, \           LAST_NAME, AGE, SEX, INCOME) \           VALUES ('%s', '%s', '%d', '%c', '%d' )" % \           ('Mac', 'Mohan', 20, 'M', 2000)    try:       # 执行sql语句       cursor.execute(sql)       # 提交到数据库执行       db.commit()       print "插入1条记录"    except:       # Rollback in case there is any error       db.rollback()    # SQL 查询语句    sql = "SELECT * FROM EMPLOYEE \           WHERE INCOME > '%d'" % (1000)    try:       # 执行SQL语句       cursor.execute(sql)       # 获取所有记录列表       results = cursor.fetchall()       for row in results:          fname = row[0]          lname = row[1]          age = row[2]          sex = row[3]          income = row[4]          # 打印结果          print "fname=%s,lname=%s,age=%d,sex=%s,income=%d" % \             (fname, lname, age, sex, income )    except:       print "Error: unable to fecth data"    # 关闭数据库连接    db.close()
    [root@hadron python]# python mysql2.py
    mysql2.py:10: Warning: Unknown table 'EMPLOYEE'
      cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
    创建表成功!
    插入1条记录
    fname=Mac,lname=Mohan,age=20,sex=M,income=2000

    MariaDB [test]> show tables;
    +----------------+
    | Tables_in_test |
    +----------------+
    | EMPLOYEE       |
    +----------------+
    1 row in set (0.00 sec)

    MariaDB [test]> select * from EMPLOYEE;
    +------------+-----------+------+------+--------+
    | FIRST_NAME | LAST_NAME | AGE  | SEX  | INCOME |
    +------------+-----------+------+------+--------+
    | Mac        | Mohan     |   20 | M    |   2000 |
    +------------+-----------+------+------+--------+
    1 row in set (0.00 sec)

Python调用Linux命令
    Python目前已经废弃了os.system,os.spawn*,os.popen*,popen2.*,commands.*来执行其他语言的命令,subprocesss是被推荐的方法;
    subprocess允许你能创建很多子进程,创建的时候能指定子进程和子进程的输入、输出、错误输出管道,执行后能获取输出结果和执行状态。
    subprocess模块在python2.4中初次亮相,其中集中了关于进程的诸多操作,其中的call()完全替代了system(),而popen()被更为丰富的Popen类替代;
(1)    [root@hadron python]# vi cmd.py
    #!/usr/bin/env python    # -*- coding: UTF-8 -*-    #python wapper for the ls command    import subprocess    subprocess.call(["ls","-l"])    subprocess.call(["cat","/root/python/cmd.py"])    #系统信息    uname = "uname"    uname_arg = "-a"    print "Gathering system information with %s command:\n" % uname    subprocess.call([uname,uname_arg])
    [root@hadron python]# python cmd.py
    总用量 196
    -rw-r--r-- 1 root root  320 1月  24 15:30 cmd.py
    -rwxr-xr-x 1 root root  245 1月  22 13:39 dict.py
        .....................
    -rw-r--r-- 1 root root  261 1月  23 14:00 try2.py
    -rw-r--r-- 1 root root  272 1月  23 13:46 try.py
    -rwxr-xr-x 1 root root  234 1月  23 09:04 var.py
    -rw-r--r-- 1 root root  510 1月  23 15:22 Vector.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    #python wapper for the ls command
    import subprocess
    subprocess.call(["ls","-l"])
    subprocess.call(["cat","/root/python/cmd.py"])
    #系统信息
    uname = "uname"
    uname_arg = "-a"
    print "Gathering system information with %s command:\n" % uname
    subprocess.call([uname,uname_arg])
    Gathering system information with uname command:

    Linux hadron 3.10.0-514.2.2.el7.x86_64 #1 SMP Tue Dec 6 23:06:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux


(2)    [root@hadron python]# vi LocalUtil.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import shlex
    import datetime
    import subprocess
    import time

    def execute_command(cmdstring, cwd=None, timeout=None, shell=False):
      """执行一个SHELL命令
          封装了subprocess的Popen方法, 支持超时判断,支持读取stdout和stderr
          参数:
        cwd: 运行命令时更改路径,如果被设定,子进程会直接先更改当前路径到cwd
        timeout: 超时时间,秒,支持小数,精度0.1秒
        shell: 是否通过shell运行
      Returns: return_code
      Raises: Exception: 执行超时
      """
      if shell:
        cmdstring_list = cmdstring
      else:
        cmdstring_list = shlex.split(cmdstring)
      if timeout:
        end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)

      #没有指定标准输出和错误输出的管道,因此会打印到屏幕上;
      sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096)

      #subprocess.poll()方法:检查子进程是否结束了,如果结束了,设定并返回码,放在subprocess.returncode变量中
      while sub.poll() is None:
        time.sleep(0.1)
        if timeout:
          if end_time <= datetime.datetime.now():
        raise Exception("Timeout:%s"%cmdstring)

      return str(sub.returncode)

    if __name__=="__main__":
      print execute_command("ls")

    [root@hadron python]# python LocalUtil.py
    cmd.py     elif.py      file2.py          fun.py    import.py  lambda.py     mySAX.py     mythread.py  Parent.py   re1.py      str.py      
    dict.py  Employee.py  file3.py          fun.pyc    in_is.py   LocalUtil.py  myServer.py  mytime.py    Point.py    re2.py      
    dir.py     Emp.py       for.py          hello.py    json1.py   movies.xml     mysql2.py    mytuple.py   print.py    re3.py      t
    dom.py     file1.py     from_import.py  if.py    json2.py   mylist.py     mysql.py     override.py  private.py  server.py  
    0

    [root@hadron python]# vi cmd2.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import LocalUtil
    LocalUtil.execute_command('uname -a')
    [root@hadron python]# python cmd2.py
    Linux hadron 3.10.0-514.2.2.el7.x86_64 #1 SMP Tue Dec 6 23:06:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux


Python Paramiko模块安装和使用
    大家会发现,常见的解决方法都会需要对远程服务器必要的配置,如果远程服务器只有一两台还好说,如果有N台,还需要逐台进行配置,或者需要使用代码进行以上操作时,上面的办法就不太方便了。使用paramiko可以很好的解决以上问题,比起前面的方法,它仅需要在本地上安装相应的软件(python以及PyCrypto),对远程服务器没有配置要求,对于连接多台服务器,进行复杂的连接操作特别有帮助。
    安装paramiko有两个先决条件,python和另外一个名为PyCrypto的模块。

    [root@hadron 下载]# wget http://ftp.dlitz.net/pub/dlitz/crypto/pycrypto/pycrypto-2.6.tar.gz
    [root@hadron 下载]# tar -zxvf pycrypto-2.6.tar.gz -C /opt
    [root@hadron 下载]# cd /opt/pycrypto-2.6/
    [root@hadron pycrypto-2.6]# python setup.py build && python setup.py install
    [root@hadron pycrypto-2.6]# python
    Python 2.7.5 (default, Nov  6 2016, 00:28:07)
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import Crypto
    >>>

    下载:https://pypi.python.org/pypi/paramiko/2.1.1
    [root@hadron 下载]# tar -zxvf paramiko-2.1.1.tar.gz -C /opt
    [root@hadron 下载]# cd /opt/paramiko-2.1.1/
    [root@hadron paramiko-2.1.1]# python setup.py build && python setup.py install
    [root@hadron paramiko-2.1.1]# python
    Python 2.7.5 (default, Nov  6 2016, 00:28:07)
    [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import paramiko
    >>>

使用用户名密码连接远程主机    
    [root@hadron python]# vi paramikoDemo.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import paramiko
    import sys,os
    hostname='192.168.1.169'
    username='root'
    password='123456'
    #通过sys下的argv来获取命令行的输入
    cmd=sys.argv[1]
    if __name__=='__main__':
         paramiko.util.log_to_file('paramiko.log')
         s=paramiko.SSHClient()
          #加载本地的known_hosts文件
         s.load_system_host_keys()
          #用于允许连接不在known_hosts名单中的主机
         s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
          #连接远程主机
         s.connect(hostname=hostname,username=username,password=password)
          #执行命令
         stdin,stdout,stderr=s.exec_command(cmd)
          #读取命令结果
         print stdout.read()
         print stderr.read()
         s.close()
    [root@hadron python]# python paramikoDemo.py free
              total        used        free      shared  buff/cache   available
    Mem:        7995716      583520     5689056       16816     1723140     7145116
    Swap:       4194300           0     4194300
    [root@hadron python]# python paramikoDemo.py 'df -h'
    Filesystem               Size  Used Avail Use% Mounted on
    /dev/mapper/centos-root   36G  2.3G   34G   7% /
    devtmpfs                 3.9G     0  3.9G   0% /dev
    tmpfs                    3.9G     0  3.9G   0% /dev/shm
    tmpfs                    3.9G   17M  3.8G   1% /run
    tmpfs                    3.9G     0  3.9G   0% /sys/fs/cgroup
    /dev/sda1                497M  125M  373M  26% /boot
    tmpfs                    781M     0  781M   0% /run/user/0


    [root@hadron python]# vi remote.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import paramiko
    def python_ssh(hostname,username,password,**shell):
        try:
        s = paramiko.SSHClient()
        s.set_missing_host_key_policy(paramiko.AutoAddPolicy())   # 用于允许连接不在known_hosts名单中的主机
        s.connect(hostname = hostname,username = username,password = password)
        result = {}
        for key in shell:
            stdin,stdout,stderr = s.exec_command(shell[key])
            result[key] = stdout.read(),stderr.read()
        s.close()
        return result
        except:
        result = u"无"
        return result
    [root@hadron python]# vi sshDemo.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    from remote import python_ssh
    result=python_ssh('192.168.1.169','root','123456',SHELL1='free')
    print result
    [root@hadron python]# python sshDemo.py
    {'SHELL1': ('              total        used        free      shared  buff/cache   available\n
                Mem:        7995716      583492     5689252       16820     1722972     7145300\n
                Swap:       4194300           0     4194300\n', '')}

使用key连接远程主机
    将本地公钥发送给远程主机认证方
    [root@hadron .ssh]# cat id_rsa.pub
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC....eGTXv5dt4ZcyLnA4BIS/x root@node1
    [root@node3 .ssh]# vi authorized_keys
    
    [root@hadron python]# vi privatekey.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import paramiko
    import sys,os
    host = sys.argv[1]
    user = 'root'
    #指定用来解密的私钥的路径
    pkey_file = '/root/.ssh/id_rsa'
    #使用私钥解密
    key = paramiko.RSAKey.from_private_key_file(pkey_file)
    cmd = sys.argv[2]
    s = paramiko.SSHClient()
    s.load_system_host_keys()
    s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    s.connect(host,22,user,pkey=key,timeout=5)
    stdin,stdout,stderr=s.exec_command(cmd)
    cmd_result = stdout.read(),stderr.read()
    for line in cmd_result:
        print line,
    s.close()
    [root@hadron python]# python privatekey.py 192.168.1.120 df
    Filesystem      1K-blocks      Used  Available Use% Mounted on
    /dev/sda1       153525000 141787340   11737660  93% /
    devtmpfs         65946880         0   65946880   0% /dev
    tmpfs            65961464       280   65961184   1% /dev/shm
    tmpfs            65961464     59300   65902164   1% /run
    tmpfs            65961464         0   65961464   0% /sys/fs/cgroup
    /dev/sda3       283712156     32928  283679228   1% /data
    tmpfs            13192296        16   13192280   1% /run/user/988
    tmpfs            13192296        32   13192264   1% /run/user/0
    /dev/sdb1      1952559608  34260612 1918298996   2% /sdb

Paramiko SFTP传送文件
    [root@hadron python]# vi sftp.py
    #!/usr/bin/env python
    # -*- coding: UTF-8 -*-
    import paramiko
    import sys,os
    host = sys.argv[1]
    user = 'root'
    password='123456'
    t = paramiko.Transport((host,22))
    #连接方式也可以用key,这里只需要将password=password改为pkey=key,其余的key代码与前面的一样
    t.connect(username=user,password=password)
    sftp = paramiko.SFTPClient.from_transport(t)  #使用t的设置方式连接远程主机
    sftp.get('/tmp/hello.txt','hello.txt')        #下载文件
    sftp.put('hello.py','/tmp/hello.py')            #上传文件
    t.close();    
    [root@hadron python]# python sftp.py 192.168.1.169
    [root@hadron python]# cat hello.txt
    Hello,World!
    [root@webServer tmp]# ls
    hello.py  hello.txt  hsperfdata_root

0 0