61581229 发表于 2018-8-15 10:58:17

Python面向对象学习笔记

  视频课程《三-Python高级自动化开发工程师微职位:面向对象》
  subprocess模块:

[*]  用途:如在Linux上调用windows的命令,需要获取命令的输出结果,而不是python代码的结果
[*]  与os.system的区别
  输出命令结果到屏幕,返回值是Python代码运行的结果
  subprocess把命令运行的结果和Python代码运行的结果都以元组形式返回,依次读取相应的值即可获得所需数据
[*]  Python2中类似的command
os.system("dir")# 返回状态  

  
os.popen("dir").read()# 获取结果,但不明确"dir"的运行状态
  

  
# Linux上支持的比较好
  
import commands
  
comands.getstatusoutput("dir") # 以元组形式返回状态值和命令运行的结果
  

  
# Python3.5后出现的方法
  
import subprocess
  
subprocess.run(["df","-h"]) # 形式1
  
subprocess.run("df -h | grep sda1", shell=True) # 形式2
  

  
# Python3.5前的方法
  
subprocess.call(["ls", "-a"]) # 类似与os.system("ls")
  
# 不需要获得命令运行结果,只需指导代码运行状态时
  
subprocess.check_call(["ls", "-l"]) # 返回0或者异常
  
subprocess.getstatusoutput("ls bin/ls") # 返回(0, "/bin/ls")
  
subprocess.output("ls bin/ls") # 返回/bin/ls"
  
subprocess.check_output(["ls", "-a"]) # 返回res,如:b'/bin/ls',并非打印
  底层封装subprocess.popen()方法,返回到res对象中同时还能细分stderror
#res中只包含stdout的输出,从subprocess.PIPE读取而得  
res = subprocess.Popen("ifconfig | grep 192", shell=True, stdout=subprocess.PIPE)
  
res.stdout.read() # 获得stdout的数据
  
res = subprocess.Popen("ifconfig haha | grep 192, shell=True, stdout=subprocess.PIPE,
  
stderr=subprocess.PIPE)
  
res.stdout.read() # 获取运行结果
  
res.stderr.read() # 获取错误信息
  注意,每次调用相当于启动一个新的shell
res = subprocess.Popen("sleep 10; echo 'hi'", shell=True, stdout=subprocess.PIPE)  
res.poll() # 在命令执行完成后返回0,否则一直返回None,这是一个有趣的方法,注意理解
  
#或者可以使用阻塞的方法
  
res.wait() # 等待命令执行完,返回0
  
res.terminate()# 中止执行命令
  

  
res = subprocess.Popen("python3", shell=True, stdout=process.PIPE, stdin=subprocess.PIPE)
  
res.stdin.write("print(1)") # 启动过程中写入数据
  
res.communicate(timeout=10) # 等待结果
  例子:
# python中执行“sudo -S apt-get install vim”注意这个过程需要输入密码  
subprocess.Popen("sudo -S apt-get install vim", shell=True, stdout=subprocess.PIPE) # 出错
  
# 明确命令“echo '1234' | sudo -S apt-get install vim”
  面向对象
  OOP利用类和对象对世界进行描述,使得程序维护和扩展变得简单,提高开发效率,代码容易理解。
  Class类
  抽象出属性的描述和方法。抽象的意义在于化繁为简,更有效率的描述信息。
  Object对象
  类的实例,对象真正存储着属性的值(通常意义上,类属性等除外)
  Encapsulation封装
  在类中对数据赋值、内部调用,外部调用不必也不能对类内进行修改访问。(对外部隐藏对象的工作细节)
  Inheritance继承
  代码复用,以普通类为基础建立专门的类
  Polymorphism多态
  对不同类的对象使用相同的操作,它们会有不同的结果。
  “重复代码是可耻的行为”
  “代码需要经常改动”
  定义
  原则:可读性好,易扩展
class Role(object):  
    def __init__(self, name, role, value, money):
  
      self.name = name
  
      self.role = role
  
      self.life_value = value
  
      self.money = money
  

  
    def shot(self):
  
      print("shooting...")
  

  
    def got_shot(self):
  
      print("ah..., I got shot...")
  

  
    def buy_gun(self, gun):
  
      print("just bought %s", gun)
  

  
    # Python自动调用__del__方法,当对象内存被回收时,将会调用这个方法
  
    def __del__(self):
  
            print("del ...run")
  Python类定义的写法,其实就是执行代码块。
  特性

[*]  普通属性(成员变量或字段)
  在__init__()中确定,可以被直接访问和修改,也可以通过方法访问和修改。属于对象的,不同对象不能直接访问。
[*]  私有属性
  形如self.__heart,obj.__heart无法外部访问,但实际上可以通过如下方法进行访问
def get_heart(self): # 通过方法访问  
    return self.__heart
  
obj._Role__heart # 通过对象引用直接访问和修改

[*]  公有属性
  类的所有实例都可以访问的属性,可以理解为类的属性。如果通过对象的引用修改了同名的公有属性,相当于对象添加了一个自己的普通属性。所以类的属性只能通过类名.nationality来修改。
[*]  方法
  方法也是公有的,要注意理解。之所以要用对象的引用调用,因为定义时要通过self传递参数。
def shot2(self):  
    print("run my own shot method, self.name
  
r1.shot = shot2
  
r1.shot(r1)
  
r2.shot()
  
# 注意,r1对象shot方法对应的方法已经被外部定义的shot2方法替换,并且需要手动传递参数
  
# r2则使用的时原来的参数

[*]  析构方法
  __del__(self),对象的引用被清理时会被自动调用,相当于“回调方法”在自定义对象被清理时,手动清理需要清理的变量。
  关于继承机制
  继承机制能够让子类或派生类在使用父类(基类)的功能,并且在无需编写原来功能代码的情况下对这些功能进行扩展。继承机制的实现有以下三种方式:

[*]  单继承
  先继承再重写
class Person(object):  
    person_count = 0
  
    def __init__(self, name, age, sex):
  
      self.name = name
  
      self.age = age
  
      self.sex = sex
  

  
    def talk(self):
  
      print("Person is talking.")
  

  
    def inroll(self):
  
      # 类的计数器要使用类名调用
  
      Person.person_count += 1
  

  
    def tell(self):
  
      print("%s info" % self.name)
  
      for k,v in self.__dict__.items():
  
            print(k, v)
  

  
class BlackPerson(Person):
  
    def __init__(self, name, age, sex, strength):
  
      # 这里先继承了父类,然后重写了方法,并调用了父类的方法
  
      #Person.__init__(self, name, age, sex)# 经典类写法
  

  
      # 新式类写法,注意self参数的位置,以及理解调用机制
  
      super(Person, self).__init__(name, age, sex)
  
      self.strength = strength
  
      print(self.name, self,age, self, sex)
  

  
    def talk(self):
  
      # 同名方法,子类会覆盖父类的方法
  
      print("Black person is talking")
  

  
    def walk(self):
  
      # 子类对父类的拓展
  
      print("Black is walking.")

[*]  多继承
  再Python2和Python3里类的寻找路径是有区别的,Python2是深度优先(是否区分经典和新式?),Python3是广度优先。
# 此代码在windows下Python3环境运行  
# 无论O是新式或经典写法,查询路径都是广度优先,很可能Python3内部实现已经全部归于新式类
  
class O(object):
  
    def __init__(self):
  
      print("init O")
  
      self.n = "O"
  

  
class A(O):
  
    pass
  
    # def __init__(self):
  
    #   print("init A")
  
    #   self.n = "A"
  

  
class B(O):
  
    # pass
  
    def __init__(self):
  
      print("init B")
  
      self.n = "B"
  

  
class C(A, B):
  
    pass
  

  
cc = C()
  
print(cc.n)
  但是利用在线解释器,使用Python2.7环境下会有区别,如图:


  可以看出区别,Python2.7环境下,新式类广度优先,经典类深度优先(注意O的写法)
  广度优先和深度优先的临界点

  只有查找到A0时才会判断使用深度优先还是广度优先,如果再A0时查找O则是深度优先,如果去查找B1则是广度优先!

[*]  组合
  关于多态
  接口重用,通俗讲,就是通过父类调用子类的方法,体现出不同的形态。
class Animal(object):  
    def talk(self):
  
      raise NotImplementedError("未实现该方法,报错")
  

  
    def real_talk(self):
  
      print(self.talk())
  

  
class Cat(Animal):
  
    def talk(self):
  
      return "Meow!"
  

  
class Dog(Animal):
  
    def talk(self):
  
      return "Woof,Woof!"
  

  
c = Cat()
  
d = Dog()
  
c.real_talk()
  
d.real_talk()
  补充
  类,对象的关系
  ssh应用案例:
# 整个过程还是抽象,抽象,抽象  
class SSH:
  
    def __init__(self, host, port, pwd, username):
  
      self.host = host
  
      self.port = port
  
      self.qwd = pwd
  
      self.username = username
  

  
    def connection(self):
  
      # 创建链接
  
      #self.conn = 链接对象()
  
      pass
  

  
    def close(self):
  
      # 关闭链接
  
      pass
  

  
    def upload(self):
  
      pass
  

  
    def com(self):
  
      pass
  

  
obj = SSH()
  函数保存在类里,字段保存在对象里。
  静态属性(共有属性)
  封装的理解:
  类封装了字段名和方法,“抽象”是封装的方法论;
  对象封装了字段的值,也就是类的实体;
  类方法寻找的顺序,要注意F2的a1方法里调用self.a2(),self.a2()寻找的起点仍然是F3
class F1:  
    def __init__(self):
  
      print("F1")
  

  
    def a1(self):
  
      print("F1a1")
  

  
    def a2(self):
  
      print("F1a2")
  

  
class F2(F1):
  
    def __init__(self):
  
      print("F2")
  

  
    def a1(self):
  
      self.a2()
  
      print("F2a1")
  

  
    def a2(self):
  
      print("F2a2")
  

  
class F3(F2):
  
    def __init__(self):
  
      print("F3")
  

  
    def a2(self):
  
      print("F3a2")
  

  
obj = F3()
  
obj.a1() # F3a2 F2a1
  静态方法 @staticmethod
  保存在类里
class F1:  
    def __init__(self):
  
      print("F1")
  

  
    @staticmethod
  
    def a1(): # 可以没有self参数,也可以设定任意参数
  
      print("F1a1")
  

  
F1.a1() # 通过类来访问
  Python是否有“静态变量”?
  Python是动态语言,它的类严格讲没有静态变量,不过从特性上来讲,类变量可以称为“静态变量”

[*]  子类调用父类构造方法
# 两种方法可以实现  
class A:
  
    def __init__(self):
  
      self.hungry = True
  

  
class B:
  
    def __init__(self):
  
      A.__init__(self) # 方法一,调用父类的未绑定构造方法
  
      # super(A, self).__init__()# 方法二,super函数返回的引用相当于父类对象的引用,可以直接调用。
  
      self.sound = "Squawk!"
  两种方法均可以调用,通过super函数调用的写法是新式类的写法,而利用父类的未绑定构造方法并传入self引用的调用方法是“传统阵营”的写法。所以使用super更被推荐。
  
页: [1]
查看完整版本: Python面向对象学习笔记