subprocess模块python
ret = os.system("command")linux |
输出命令的结果,可是只返回命令的执行状态,所以ret的值在正常返回为0,不正常为非0shell |
|
ret = os.popen("command").read()编程 |
此命令返回命令执行的结果,ret是命令的输出,可是没有执行状态vim |
|
import commandswindows ret = commands.getstatusoutput("command")安全 |
在python 2.7中存在,3.5中已经不存在的模块,而且在windows下执行会有问题。 |
|
import subprocess |
以列表方式传入命令的每个参数,例如linux下的命令df -h就写成subprocess.run(["df","-h"])编码 可是这种写法不支持有管线"|"的命令,若是有管线的命令就须要写为: subprocess.run("df -h |grep sda1",shell=True),其中shell=True表明前面的字符串将由linux解析 |
|
subprocess.call() |
就是os.system(),只返回程序的执行状态,不返回结果。一样若是有管线则应该使用shell=True参数,其实此参数也能够在无管线的命令中使用 |
|
subprocess.check_call() |
若是命令执行状态正常就返回0,不然抛异常 |
|
subprocess.getstatusoutput("command") |
以元祖形式返回(命令的执行状态,命令的结果)和2.7的commands.getstatusoutput()同样 |
ret=subprocess.getstatusoutput("ipconfig") |
subprocess.getoutput() |
仅获取命令输出 |
ret = subporcess.getoutput("ipconfig")和上面的ret[1]同样 |
subprocess.check_output() |
若是命令正常执行,则返回结果,不然报错 |
|
subprocess.Popen("command",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) |
stdout就是一个标准屏幕输出,stderror是命令执行错误时屏幕上显示的报错内容,stdin是一个屏幕输入
subprocess.PIPE参数表明开辟一个管道(内存空间),用来将Popen的命令输出保存起来
所以当咱们须要打印结果时,则须要到stdout中读取,见例子,同时由于他能够将stdout和stderror分别保存在独立的PIPE中,所以咱们也就能够分别获取正确的输出和错误的报错。
Popen方法是一个底层封装,上面使用的集中subprocess的方法内部都是封装的Popen()方法,使用这个方法能够本身结合处不少新的方法
Popen方法的参数:
shell:让操做系统自行解析命令,当shell=True时无需像上面同样输入,只须要subprocess.Popen("df -h",shell=True,stdout=subprocess.PIPE)便可
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量,若是env = None,子进程的环境变量将从父进程集成
universla_newlines:自动兼容操做系统的换行符,这个设置默认是打开的
|
ret = subprocess.Popen("ipconfig",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print(ret.stdout.read())打印命令的输出 print(ret.stderr.read())打印报错 |
ret = subprocess.Popen("command",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE)
ret.stdout.read() |
ret.stout.read(),从标准输出中读取结果 |
|
ret.poll() |
用来检查命令的执行状态,由于当咱们使用Popen命令时若是命令须要执行很长时间实际咱们从输出上是看不到的,命令至关于后台运行咱们在命令行里看不到执行进程,而poll()方法实际就是一种能够由手动发起的检测,用来检测当前命令的执行状态,
若是程序没有执行完,则返回None 若是执行完毕,则返回程序执行状态 0为正常,异常为非0 |
|
ret.wait() |
wait()方法则是将程序调用到前台执行,也就是此时什么也作不了只能等待程序运行结束,运行正常返回0不然返回非0 |
|
ret.terminate() |
终止程序的运行 |
|
ret.communicate() |
在调用Popen后,能够向stdin(标准屏幕输入)中输入内容,以后经过communicate()方法获得输入的内容 |
obj = subprocess.Popen("python",shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
obj.stdin.write(b"print(1) \n") obj.stdin.write(b"print(2) \n") obj.stdin.write(b"print(3) \n") obj.stdin.write(b"print(4) \n")
out = obj.communicate() print(out)
输出:(b'1\r\n2\r\n3\r\n4\r\n', b'') |
Python sudo输入密码
在linux中经过一条命令直接sudo 连同输入密码带执行命令的写法是:
echo "password" | sudo -S yum install vim
其中sudo -S就是屏幕标准输入stdin,以前的echo "password" 就是向stdin输入数据
所以当咱们经过python须要执行sudo 命令时就能够写为
subprocess.Popen("echo 'password' | sudo -S yum install vim",shell=True)便可,此处password中须要用单引号以免命令参数的双引号重复
面向对象
class类
是对一类拥有相同属性的对象的抽象、蓝图、圆形。在类中定义了这些对象都具有的属性(varialbes(data))、共同方法
object对象
一个对象是类的实例化后的实例,一个雷必须通过实例化后方可在程序中调用,一个类能够实例化多个对象,每一个对象亦能够有不一样的属性,就像人类指全部人,每一个人是指具体的对象,人与人之间的共性,亦有不一样
开发规范:
一、类名首字母大写
二、函数全小写
三、不管是类仍是函数,在定义完名称后第二行开始应该写注释
面向对象的特性
Encapsulation 封装
在类中对数据的赋值、内部调用,对外部用户是透明的,这使得类变成一个胶囊或者容器,里面包含着类的属性,数据和方法。
封装的做用有2:一、防止数据被随意修改 二、使外部程序不须要关注对象的内部构造,只须要经过对象对外提供的接口进行直接访问便可。
Inheritance 继承
一个类能够派生出子类,在这个父类里定义的属性、方法自动被子类继承
定义时共性能够在父类中定义,而子类中是对象的个性,这样具象化子类便可建立有一个独立的对象
经过 父类-->子类的方式,以最小代码量的方式实现不一样角色的共同点和不一样点
Polymorphism 多态
一种接口,有不一样表现形式
类的定义
定义一个简单的类
class Dog(object): |
# print("hello,i am a dog.") 类和函数同样直接打印那么建立对象就会执行,这样是不对的,所以须要执行应该放到函数中 |
def sayhi(self): |
|
print("hello,i am a dog") |
|
调用类(实例化)
d = Dog() |
# 机遇dog建立一个名叫d的实例 |
d.sayhi() |
# 对象.函数 便可调用 |
可是上面的类有一个问题,没法区分建立的对象,由于他们都是打印hello i am dog,我并不知道那个对象作的,
所以我须要传递一个参数
class Dog(object): |
|
def __init__(self,name): |
|
self.Name = name |
|
def sayhi(self): |
# print("hello,i am a dog,my name is",name) 这样会报错,由于name这个变量时在__init__函数中的局部变量,是不能使用到sayhi函数中的 |
print("hello,i am a dog,my name is",self.Name) |
# 这样是能够的, |
d = Dog("zhangsan") |
# 此处所传递的参数实际是传递给__init__(self,name)中的name,而类中的self实际就是对象,也就是Dog(d,"zhangsan"),而对应的在函数内就变成了d.Name="zhangsan",至关于给d这个对象的Name变量赋值为"zhangsan",因此在后面sayhi方法中咱们须要传递的是self.Name,而不是name |
d2 = Dog("lisi") |
|
类中的self |
类是不少函数的组合,可是函数之间不能互相访问局部变量,所以就须要self来打通各个函数。self就是指代的就是类实例化后的实例。 |
def __init__() |
类中定义的这种函数,就是构造函数或构造方法,也称为初始化方法,若是不向类传递参数能够不定义 |
def sayhi() |
类中的其余方法,就是类的方法,此处指代出了构造函数外的其余全部类中的方法 |
因此在类中定义的函数应该始终将self做为第一个参数。
class test(): |
|
def __init__(self,*args,**kwargs): |
# 若是不传递参数能够不定义这个方法 |
def test(self): |
|
self应该使用存在,而这个类的实际形式参数应该写到其构造函数中 def __init__(self,...):
由于在构造函数中建立了变量(self.Name),并且咱们也能够在其余的方法中直接使用self.Name来引用,所以咱们也可使用一样的方式来更改变量的值
class test(object):
def __init__(self,name)
self.Name = name
def test(self):
self.Name = new_name
类 --> 实例化 --> 实例对象
def __init__(self): 构造函数
self.name = name # 类的属性,成员变量
def sayhi(self): # 方法,动态属性
私有属性:
self.__heart = "Normal" ,使用__定义的属性是私有属性,私有属性没法被外部访问
class test(object):
def __init__(self):
self.__name = "test"
此时外部访问
a = test()
print(a.__name) 这是没法访问的
可是能够被类中定义的其余方法访问
self.__heart = "Normal" ,使用__定义的属性是私有属性,私有属性没法被外部访问
class test(object):
def __init__(self):
self.__name = "test"
def test(self):
print(self.__name) # 这是在方法中定义的打印,不是外部要求的打印
a = test()
a.test() # 这样运行到test()方法时定义的print能够self.__name打印出来
所以若是要在外部获取私有属性,则须要在类内部定义一个新的方法将私有属性返回,
这是一个比较安全的方法,这样获得的值是只读的
class test(object): |
|
def __init__(self): |
|
self.__name = "test" |
|
def get_name(self): |
|
return self.__name |
|
a = test()
print(a.get_name()) # 这样就能够得到__name的值
若是我不考虑安全性,而直接要求访问类的私有属性,则按照以下的方法获取:
对象._类名__私有属性
例如
a._test__name
公有属性:
直接定义在类中的属性是公有属性,这个属性能够被外部直接调用。公有属性和成员属性是有差别的(私有属性也是成员属性),成员属性是定义在构造函数中的,而公有属性是在类下直接定义的。
class test(object): |
|
nationality = "CN" |
# 公有属性 |
def __init__(self,name,age): |
|
self.name = name |
# 成员属性 |
self.__age = age |
# 私有属性 |
类的公有属性的更改有以下的方法:
一、直接调用类名更高:test.nationality = "US"
二、经过对象调整:
a1 = test("zhangsan",30)
a2 = test("lisi",44)
a1.nationality = "US"
可是若是经过类名调用,则全部实例对象都会被调整。而若是是经过实例对象调整,则只有本对象被调整
这是由于实例对象中的变量实际是类中的参数的引用,所以经过类.变量的调整就会调整全部对象中的公有属性。
可是一旦经过对象.变量的方式调整了,则会在对象的内存中建立一个开辟一个新的内存地址,建立了一个新的变量,所以这样就只改变对象的变量。
系统在对变量进行寻址时,首先选择对象中是否存在这个变量,若是没有则向类中寻找。
从位置看,类的公有属性和类的方法是同级的,所以实际上每一个对象在调用类的方法时也并非将类的方法复制到对象内存中,而是调用的类的方法的引用。所以这也是self存在的缘由。由于是引用因此须要区分不一样的对象,而self实际就是指代的建立的对象,因此类中的每一个方法都必须有self参数
所以类中的方法实际也是公有的,那么若是我但愿方法也是私有的,就须要在外部定义一个方法来替换
class test(object): |
|
nationality = "CN" |
# 公有属性 |
def __init__(self,name,age): |
|
self.name = name |
# 成员属性 |
self.__age = age |
# 私有属性 |
def test(self): |
|
print("123") |
|
|
|
a1 = test() |
|
a2 = test() |
|
a1.test() |
# 输出123 |
a1.test() |
# 输出123 |
def test():
print("234")
a1.test = test # 此处不要加括号,由于加了()就是执行函数,不加括号是为了将函数体赋值
a1.test() # 输出234
a2.test() # 输出123
a1.test()变成了私有的
类的析构方法
在类中定义以下方法:
class test(object):
def __del__(self):
print("...")
这个方法就是析构方法,此方法是在对象被删除时自动执行。
r1 = test()
del r1 # 这行的命令是在内存中将r1和所建立的r1的内存空间的关系移除,此时r1的内容并无被内存回收,在此时会执行析构方法。当内存空间没有被引用(del r1就是这种状况),以后这块内存就会被python的内存回收机制收回。
析构方法的做用是作一些程序的收尾工做,好比当咱们的程序链接了不少客户端,当咱们del这个对象的时候,能够在__del__这个方法内定义与客户端断开链接等操做
单继承
继承有两种继承方法:
一、实现继承 是指使用父类的属性和方法二无需额外编码的能力
二、接口继承 是指使用父类的属性和方法的名称,可是子类必须提供实现的能力(子类重构父类的方法)
在考虑使用继承时,应注意 父类和子类之间应该是属于的关系,例如manager能够继承person,可是leg不能继承person。由于manager是一我的拥有人的完整特征,manager彻底是属于person。可是leg只是人的一部分他没有人的特征(好比人有鼻子眼睛,可是leg没有)
继承的写法
class Person(object): |
|
def talk(self): |
|
print("。。。") |
|
class BlackPerson(Person): |
# 此时就是继承了Person,括号中的就是父类 |
def walk(self): |
|
print("walking") |
|
|
|
b = BlackPerson() |
|
b.talk() |
# 继承父类的方法 |
b.walk() |
# 调用子类本身的方法 |
当须要传递新的参数时,须要对构造函数先继承,后重构
class Person(object): |
|
def __init__(self,name,age): |
# 父类传递2个参数,name和age |
self.name = name |
|
self.age = age |
|
self.say_hi(self) |
# 能够在父类的构造函数中调用父类的方法,这样后续的子类继承父类构造函数时自动执行这个方法,也能够在每一个子类中单独调用 |
def say_hi(self): |
|
pass |
|
class BlackPerson(Person): |
|
def __init__(self,sname,sage,a): |
# 此时须要在子类中新增一个a参数传入,那么久须要先继承父类的构造函数,在重构子类的构造函数,此时定义子类的构造函数的形式参数 |
Person.__init__(self,sname,sage) |
# 继承父类的构造函数,注意看此处参数的写法,实际是将子类的参数传递给父类的构造函数,因此这里是调用应该写实际参数名 |
self.a = a |
# 重构构造函数,定义新的属性 |
print(self.name,self.age,self.a) |
# 打印属性,注意看此时全部的参数均可以打印了,可是self.name 和 self.age实际是继承的父类里构造函数的调用,因此获得的结果继承的部分仍是父类的,而子类的仍是子类的参数 |
self.say_hi() |
# 由于这是继承了Person的类,因此我在子类的构造函数中就能够调用父类的方法 |
a = BlackPerson("zhangsan",30,"xx") |
|
由上面的设置能够看到,不管是如何继承,由于有了self,而self就是等于对象,因此才能够直接使用self.变量来调用,可是若是我在父类中定义一个变量,要计算有多少个“对象”(注意不是子类)调用了这个父类。
例如 一个学院成员的父类,一个老师和一个学生的子类分别继承了学院成员的父类,此时我在学院成员中定义了一个注册变量,没增长一个老师或学生这个变量要加1
那么在学院成员这个变量的定义就不能使用self,而应该是学院成员这个类名,由于若是使用self,只表明对象本身调用的此时,不能表明类被调用的次数
class SchoolMember(object): |
|
member = 0 |
# 定义公有属性,以便后续累加 |
def __init__(self,name,age,sex): |
|
self.name = name |
|
self.age = age |
|
self.sex = sex |
|
self.enroll() |
# 在父类中调用一个父类的方法,这样每一个子类都会执行 |
def enroll(self): |
# 注册流程 |
SchoolMember.member += 1 |
# 此处本意是每次建立对象就要+1,可是若是使用self,则不会加由于self指代的是对象本身,对象自己不会重复调用。是类在重复调用,所以只能使用类.menmber才会累加,而这种调用方法实际就要求member必须是公有属性 |
print("number[%s] just enroll a new school membe [%s]".%(SchoolMember.member, self.name)) |
# 此处能够self.member,也能够SchoolMember.member,但决不可直接member |
|
|
class Teacher(SchoolMember): |
|
def __init__(self,name,age,sex,salary): |
|
SchoolMember.__init__(self,name,age,sex) |
|
self.salary = salary |
|
|
|
class Student(SchoolMember): |
|
def __init__(self,name,age,sex,fee): |
|
SchoolMember.__init__(self,name,age,sex) |
|
self.fee = fee |
|
|
|
t1 = Teacher("zhangsan",30,"F",3000) |
|
s1 = Student("lisi",26,"F",2000) |
|
self.__dict__ |
# 将对象的属性做为列表打印出来,相似: |
下面的例子是一个使用self.__dict__的例子
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def tell(self):
print(self.__dict__) # 在父类中定义打印对象属性,打印的格式是{'name': 'zhangsan', 'a': 'xx', 'age': 30}
for i,v in self.__dict__.items():
print(i,v) # 使用self.__dict__.items()的方式将key和value变为元组,而且赋值两个变量输出,结果为name zhangsan\n age 30...
class BlackPerson(Person):
def __init__(self,sname,sage,a):
Person.__init__(self,sname,sage)
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx")
a.tell()
多继承
多继承时原则来讲继承的多个类智能有一个有构造函数,不该该出现多个类多个构造函数对应不一样的属性的状况
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def tell(self):
print(self.__dict__)
for i,v in self.__dict__.items():
print(i,v)
class School(object):
def school_addr(self, address):
print("school address is ", address)
class BlackPerson(Person,School): # BlackPerson继承了2个父类
def __init__(self,sname,sage,a):
# Person.__init__(self,sname,sage)
super(BlackPerson,self).__init__(sname,sage)
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx")
a.tell()
a.school_addr("sh") # 第二个父类的方法自动得到
同时多继承我也能够对两个父类分别继承属性
class Person(object):
def __init__(self,name,age): # Person的构造函数
self.name = name
self.age = age
def tell(self):
print(self.__dict__)
for i,v in self.__dict__.items():
print(i,v)
class School(object):
def __init__(self,addr): # School的构造函数,并制定了一个新的属性
self.addr = addr
def school_addr(self):
print("school address is ", self.addr)
class BlackPerson(Person,School):
def __init__(self,sname,sage,a,addr): # 子类的构造函数
super(BlackPerson,self).__init__(sname,sage) # Person函数继承构造函数,使用新式类继承方法
School.__init__(self,addr) # School函数构造函数继承,使用的是经典类
self.a = a
print(self.name,self.age,self.a)
a = BlackPerson("liubo",30,"xx","sh")
a.tell()
a.school_addr() # 调用父类 School的方法
新式类 vs 经典类
子类继承父类函数并重构构造函数的时候又两种继承父类构造函数的方法
class Person: |
# 经典类建立 |
class Person(object): |
# 新式类建立 |
Person.__init__(self,sname,sage) |
# 经典类继承构造函数 |
super(BlackPerson,self).__init__(sname,sage) |
# 新式类继承构造函数 |
多继承时 继承顺序有区别
概念:
广度查询:函数在继承时从左至右继承,若是父类中都没有再想父类的父类里继承
例如:
祖父: A
父类:B继承A、C继承A
子类:D继承 B和C
此时在调用D时的查询顺序是 B -- C -- A
深度查询:函数在继承时首先在从左侧开始从父类一直查询到父类的父类,若是没有再到第二继承顺序从父类到父类的父类
例如
祖父:A
父类: B继承A、C继承A
子类:D继承 B和C
此时调用D 查询顺序是 B -- A -- C
在Python 3.0之后,不管是新式类仍是经典类,继承顺序都是广度查询
在Python2.7之后,经典类是深度查询,而新式类则是广度查询
多态
继承和封装的目的是减小代码的重复性
而多态的目的是接口重用
python不直接支持多态,可是能够间接实现
实现的方式是在全局下定义一个函数,将对象传入,由这个函数来调用对应的接口
class Dog(object): |
# 定义类 |
def __init__(self,name): |
|
self.name = name |
|
|
|
def talk(self): |
|
return "wang!" |
|
|
|
class Cat(object): |
# 定义类 |
def __init__(self,name): |
|
self.name = name |
|
|
|
def talk(self): |
|
return "miao!" |
|
|
|
d = Dog("dahuang") |
|
c = Cat("xiaomi") |
|
|
|
def com_talk(obj): |
# 定义一个通用的方法,而后将建立好的对象传入,而后再调用对象的talk方法 |
print(obj.talk()) |
|
|
|
com_talk(c) |
# 这样以后调用talk方法时只须要调用函数再将对象传入便可,一个方法 根据传入对象的不一样而有不通的结果 |
com_talk(d) |
|
一、什么是面向对象编程
二、什么是类什么是对象,有什么关系
三、何时适用面向对象
# 建立链接
obj = SSH(....) # 实例化
obj.conn() # 链接服务器
obj.upload() # 上传
obj.close() # 关闭
上面的方法最后实现起来全部的步骤是能够直接使用随意组合,不像函数式要为每种场景定义方法,而且每次都有重复的操做
四、self 公有属性 普通属性
self就是调用当前方法的对象
如上图,内存中会为类开辟内存空间,在建立对象后对象的内存空间会有一个类对象指针指向他所实例化的类
同时将本身(对象)传递给类的self参数。类的方法保存在类的内存中,而类的属性则会保存在对象的内存中
当有一种情景,我建立了一个省份的类
class province(object):
def __init__(self,name,count):
self.Name = name
self.Count = count
self.country = "中国"
在这种状况下,我明知每一个省都属于中国,可是我仍然将country定义为普通属性,就会形成这个属性在每一个对象中保存,无疑会浪费大量的内存空间。
此时我应该将其定义为类的公有属性,一旦定义为公有属性,则不管建立多少个对象这个属性都只建立一次,同时该属性也再也不保存在对象中,而是保存在类的内存中
class province(object):
country = "中国" # 公有属性
def __init__(self,name,count):
self.Name = name
self.Count = count
若是每个对象都会有共同的值,则这些值应该定义为公有属性
五、封装、继承
class F1(object):
def __init__(self,name):
self.Name = name
class F2(object):
def __init__(self,obj):
self.a = obj
class F3(object):
def __init__(self,obj):
self.b = obj
o1 = F1("ZS")
o2 = F2(o1)
o3 = F3(o2)
print(o3.b.a.Name)
上面的例子,最终输出的是是ZS,对象是能够相互调用的,os.b就是o2,那么o2.a就是o1,而o1.Name就是ZS,所以我经过o3来调用时就会变成o3.b.a.Name
class F2(object):
def a1(self):
self.a2() # 下面调用的obj是F3()所以当执行F3.a1()时F3没有会找F2,而这里至关因而obj.a2(),而obj是F3建立的,所以调用F3的a2输出F3A2
print("F2A1") # 以后再打印
def a2(self):
print("F2A2")
class F3(F2):
def a2(self):
print("F3A2")
obj = F3()
obj.a1()
六、
属性
普通属性(保存在对象中)
公有属性(保存在类中)
方法
普通方法(保存在类中,调用者是对象,至少有一个self参数)
静态方法(能够有任意个参数)
静态方法的建立
class F1(object):
def a1(self):
print("123")
当建立上面的对象时,由于没有定义构造函数因此会被提示有问题
此时咱们能够经过@staticmethod来装饰这个函数,使这个函数变为静态方法。
class F1(object):
@staticmethod # 变为静态方法
def a1(): # 静态方法self就不须要了
print("123")
调用静态方法无需建立对象,直接经过类调用便可
F1.a1
静态方法能够直接调用无需建立的对象,这点很像原来不创建类而直接定义函数的方法
做业:
选课系统
角色:学校、学员、课程、讲师
要求:
一、北京、上海两所学校
二、建立 linux、python go3个课程,linux\py在北京开,go在上海开
三、课程包含,周期、价格,经过学校建立课程
四、经过学校建立班级,班级关联课程、讲师
五、建立学院时,选择学校,关联班级
建立讲师角色时要关联学校
六、提供两个角色接口
学员视图,能够注册,交学费,选择班级
讲师视图,讲师能够管理本身的班级,上课时选择班级,查看班级学员列表,修改所管理学员的成绩
管理视图,建立讲师,建立班级,建立课程
七、上面的操做产生的数据都经过pickle序列化保存到文件里