python笔记-9(subprocess模块、面向对象、socket入门)
一、subprocess 模块
1、了解os.system()与os.popen的区别及不足
1.1 os.system()可以执行系统指令,将结果直接输出到屏幕,同时可以将指令是否执行成功的状态赋值给变量保存,0表示执行成功
res=os.system('dir') #保存命令执行是否成功的状态 >>> import os >>> x=os.system('df') ---------------------------------------- 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/vda1 20510332 4724432 14737384 25% / tmpfs 942048 35880 906168 4% /run >>> print(x) 0 #执行成功结果为0
说明:os.system()的返回值为0,表示指令执行成功。
1.2 os.popen的可以将运行指令的输出内容保存到变量中,但是无法显示该指令是否正常运行成功了。
os.popen('dir').read() 保存命令运行结果 >>> os.popen('df') <os._wrap_close object at 0x7f2c8bda7e48> >>> x=os.popen('df') >>> print(x) <os._wrap_close object at 0x7f2c8bda7eb8> >>> print(x.read()) 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/vda1 20510332 4724452 14737364 25% / devtmpfs 932944 0 932944 0% /dev tmpfs 942048 24 942024 1% /dev/shm tmpfs 188412 0 188412 0% /run/user/1000
说明:有时,我们需要把运行结果写入文件或者发送给其他的模块使用,而不是在显示屏上输出,我们需要使用popen
1.3 os指令不能即保留命令的处理成功状态,又保留命令的结果
2、python2.7中commands.getstatusoutput()的使用
输出结果为一个列表[0]为是否执行成功,[1]位输出的内容 该命令在python 3.5 没有了
x=commands.getstatusoutput('df') >>> print(x[1]) 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/vda1 20510332 4724392 14737424 25% / devtmpfs 932944 0 932944 0% /dev >>> print(x[0]) 0
3、subprocess的使用
3.1 subprocess .run用法
run 的用法为python3.5之后出现的方法 python3.5之前没有,无法将输出结果赋值给变量
3.1.1 ''的用法
>>> subprocess.run('df') ---------------------------------------------------------- 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/vda1 20510332 4724516 14737300 25% / devtmpfs 932944 0 932944 0% /dev CompletedProcess(args='df', returncode=0)
说明:subprocess.run(‘’)括号内使用引号,可以解析单独的指令,不能有参数
3.1.2 []的用法(可以用来加参数)
>>> subprocess.run(['df','-h'])
------------------------------------ 文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 20G 4.6G 15G 25% / devtmpfs 912M 0 912M 0% /dev tmpfs 920M 24K 920M 1% /dev/shm CompletedProcess(args=['df', '-h'], returncode=0)
说明:subprocess.run([]) 通过[]输入列表,将指令各个各个部分包括参数传入执行,注意此是不能有管道符的情况(['|'])
3.1.3 shell=True的用法
>>> subprocess.run(['df','-h','|','grep','vda1'])#有错误
-------------------------------------------------------- df: "|": 没有那个文件或目录 df: "grep": 没有那个文件或目录 df: "vda1": 没有那个文件或目录 CompletedProcess(args=['df', '-h', '|', 'grep', 'vda1'], returncode=1) >>> subprocess.run(['df','-h','|','grep','vda1'],shell=True)#shell=True
-------------------------------------------------------- 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/vda1 20510332 4724564 14737252 25% / devtmpfs 932944 0 932944 0% /dev tmpfs 942048 24 942024 1% /dev/shm tmpfs 942048 35880 906168 4% /run tmpfs 942048 0 942048 0% /sys/fs/cgroup tmpfs 188412 0 188412 0% /run/user/0 tmpfs 188412 0 188412 0% /run/user/1000 CompletedProcess(args=['df', '-h', '|', 'grep', 'vda1'], returncode=0)
>>> subprocess.run('df','-h','|','grep','vda1',shell=True)#无花括号
-------------------------------------------------------
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/python3.6.3/lib/python3.6/subprocess.py", line 403, in run with Popen(*popenargs, **kwargs) as process: File "/usr/local/python3.6.3/lib/python3.6/subprocess.py", line 609, in __init__ raise TypeError("bufsize must be an integer") TypeError: bufsize must be an integer
>>> subprocess.run('df -h |grep vda1',shell=True)#引号的写法
-------------------------------------------------------------------
/dev/vda1 20G 4.6G 15G 25% / CompletedProcess(args='df -h |grep vda1', returncode=0)
3.2 call 与check_call对比
>>> subprocess.call('df -h',shell=True) 文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 20G 4.6G 15G 25% / devtmpfs 912M 0 912M 0% /dev tmpfs 920M 24K 920M 1% /dev/shm 0
说明:相当于run(),无法保存结果,只能将运行结果输出到屏幕上,也没有程序是否执行成功的返回值
3.2.2 subprocess.check_call() 将运行结果赋值给变量
>>> x=subprocess.call(['df','-h']) 文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 20G 4.6G 15G 25% / devtmpfs 912M 0 912M 0% /dev >>> print(x) 0
说明:类似于os.system()的返回值,执行成功返回0,只能将运行结果输出屏幕
3.3 subprocess.getstutusoutput() 直接执行 不需要shell=True 返回列表,此方法比run/call常用,一般都用此方法
>>> x=subprocess.getstatusoutput('df -h | grep da') >>> print(x[0]) 0 >>> print(x[1]) /dev/vda1 20G 4.6G 15G 25% / >>> x=subprocess.getoutput('df -h | grep da') >>> print(x) /dev/vda1 20G 4.6G 15G 25% /
说明:放回一个列表,两个元素0、1 x[0]表示命令是否执行成功,x[1]表示命令输出的结果
3.4 subprocess.popen的使用
屏幕不具备存储功能,我们需要将指令运行后输出的信息放在管道里,通过管道来查看指令运行的结果,报错等信息。
>>> x=subprocess.Popen('df -h',shell=True,stdout=subprocess.PIPE) >>> print(x.stdout.read().decode())
-------------------------------------------- 文件系统 容量 已用 可用 已用% 挂载点 /dev/vda1 20G 4.6G 15G 25% / devtmpfs 912M 0 912M 0% /dev tmpfs 920M 24K 920M 1% /dev/shm tmpfs 920M 36M 885M 4% /run # byte --> str 使用decode >>> x=subprocess.Popen('dfadaf -h',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> x.stderr.read().decode()
------------------------------------------ '/bin/sh: dfadaf: 未找到命令\n' >>> x=subprocess.Popen('df -h',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> x.stderr.read().decode()
------------------------------------------ ''
说明:
执行指令时,在后面添加管道stdout=subprocess.PIPE,stderr=subprocess.PIPE
stdout.read.decode()为指令运行的输出结果,stderr.read().decode(),
3.5 poll()与wait()的对比
3.5.1 poll() 运行结束 返回0 没结束返回null
>>> x=subprocess.Popen('sleep 20;echo "hello"',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> x.poll() None >>> print(x.poll()) None >>> print(x.poll()) 0
3.5.2 wait() 进入等待的状态 就是一直等 返回0了 表示运行结束
3.5.3 x.terminate() 杀掉所运行中的指令。
3.6 cwd:用于设置子进程的当前目录(不常用)
>>> x=subprocess.Popen('pwd',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) >>> x.stdout.read() b'/root\n' >>> x=subprocess.Popen('pwd',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,cwd='/tmp') >
>> x.stdout.read() b'/tmp\n'
二、面向对象
1、使用函数的方式虚拟两个角色‘人’和‘狗’
def person_step1(name,age,company): data={ 'name':name, 'age':age, 'company':company } return data def dog_step1(name,type): data={ 'name':name, 'type':type } return data def dog_bark_step1(dog): print('dog %s wang wang wang ...'%dog['name']) def person_walk_step1(person): print('%s is walking'%person['name']) def person_step2(name,age,company): def person_walk_step2(): print('%s is walking' %data['name']) print(locals()) data={ 'name':name, 'age':age, 'company':company, 'walk':person_walk_step2 } return data if __name__=='__main__': p1=person_step1('小明','21','baidu') p2=person_step1('小东','22','tencent') d1=dog_step1('阿呜','金毛') d2=dog_step1('旺财','哈士奇') dog_bark_step1(d1) person_walk_step1(p2) dog_bark_step1(p1) p3 = person_step2('小方', '26', 'ali') p3['walk']() #闭包 x=p3['walk'] del p3 #此时p3已经删除
x()
--------------------------------------------
dog 阿呜 wang wang wang ...
小东 is walking
dog 小明 wang wang wang ...
小方 is walking
{'data': {'name': '小方', 'age': '26', 'company': 'ali', 'walk': <function person_step2.<locals>.person_walk_step2 at 0x0000000001E78BF8>}}
小方 is walking
{'data': {'name': '小方', 'age': '26', 'company': 'ali', 'walk': <function person_step2.<locals>.person_walk_step2 at 0x0000000001E78BF8>}}
2、了解编程范式的概念
几种编程范式的代表:面向对象、面向过程、函数式编程
不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路, 大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。 两种最重要的编程范式分别是面向过程编程和面向对象编程。
2.1 面向过程编程(Procedural Programming)
程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
举个典型的面向过程的例子, 数据库备份, 分三步,连接数据库,备份数据库,测试备份文件可用性。
如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,如果程序开头你设置了一个变量值 为1 , 但如果其它子过程依赖这个值 为1的变量才能正常运行,那如果你改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程 , 那就会发生一连串的影响,随着程序越来越大, 这种编程方式的维护难度会越来越高。
所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
2.2面向对象编程
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
面向对象的几个核心特性如下
Class 类
Object 对象
Encapsulation 封装->私有属性,公有属性,成员属性
Inheritance 继承
Polymorphism 多态
2.3 无论用什么形式来编程,我们都要明确记住以下原则:
写重复代码是非常不好的低级行为
你写的代码需要经常变更
3、熟悉定义类和对象的方法
class dog(object):#一个dog类 print('xxxx,test') def sayhi(self):#类的方法 print('hello,i am a dog') d=dog()#类-->实例化--->实例对象->实例对象简称实例 d.sayhi()#类的方法的使用
-----------------------------
xxxx,test
hello,i am a dog
说明:此处先不考虑object 和self是什么含义,知道此处需要有这个东西即可,在实体化d的时候,print会直接输出
4、类的实例化过程分析,(理解self、构造函数,属性、方法的位置)
想考虑一个问题,我要实例化两个对象,一个叫小明,一个叫小东。那么我应该如何操作
class people(object): def __init__(self,name):#构造函数,构造方法 ,初始化方法 self.NAME=name #成员属性,成员变量 def say_hello(self):#类的方法,或动态属性 print('hello,everybody,my name is',self.NAME) p1=people('小明')#会执行init的过程 people.__init__(p1,'小明') p1.say_hello() #say_hello(p1) print(p1.NAME) #实例化之后的对象叫做实例 类的实例 实例是实例化对象的简称
------------------------------
hello,everybody,my name is 小明
小明
说明:实际类在实例化的过程中会调用构造函数来进行实例化,构造函数(构造方法)接收变量的地址以及需要赋值的属性。self实际就是这个实例的地址。而成员属性实际也被保存在这地址的空间中了,可以通过实例.属性的方式将其print出来
5、封装与类的私有属性
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
我们在定义类的时候 类里面一些属性可以被外界访问,一些属性是不希望被外界访问的,不能被外界访问的属性,被称为私有属性
class role(object): def __init__(self,name,work,tool,life_value=100,money=15000): self.name=name self.work=work self.tool=tool self.life_value=life_value self.money=money self.__areyouok='normal' print(self.name,'角色进入游戏,加入阵营',self.work,'准备战斗') def shot(self,x): print(self.name,'is shoting',x.name) def got_shot(self): print(self.name,'got shot') self.__areyouok='die' def buy_tool(self,tmp_tool): print(self.name,'buy a',tmp_tool) self.tool=tmp_tool def check(self):#对外部提供只读接口 print(self.name,',are you ok man,', self.__areyouok) # 私有属性内部可以调用 if __name__=='__main__': print('对战开始'.center(50,'*')) p1=role('小明','警察','ak47') p2=role('小东','土匪','M4A1') print(p1.name,'目前还有',p1.money,'钱,装备的武器是',p1.tool) p1.buy_tool('手榴弹') print('小明现在手持',p1.tool,'丢向',p2.name) p2.shot(p1) #p1.__areyouok 私有属性外部无法调用 p1.got_shot() p1.check()#通过定义一个方法,只读的方式使用这个私有属性 print(p2._role__areyouok)#强制访问私有属性的方法
---------------------------------------------
***********************对战开始***********************
小明 角色进入游戏,加入阵营 警察 准备战斗
小东 角色进入游戏,加入阵营 土匪 准备战斗
小明 目前还有 15000 钱,装备的武器是 ak47
小明 buy a 手榴弹
小明现在手持 手榴弹 丢向 小东
小东 is shoting 小明
小明 got shot
小明 ,are you ok man, die
normal
说明:注意私有属性self.__areyouok的定义方式、只读查看的方法、强制查看的方法。print(p2._role__areyouok)#强制访问私有属性的方法。强制查看的方法一般不使用。
6、类的公有属性、成员属性对比
6.1 公有属性的定义:属于这个类的对象都可以访问的属性叫做公有属性。一个类,实体了多个对象,
6.2 成员(普通)属性和公有属性的区别:公有属性,每个对象都可以去调用这个公有属性,且这个公有属性的内容是保存在类的内存空间中,即共享同一个内存空间的内容。
6.3 公有属性的定义方式 :类中直接定义
6.4 更改公有属性的方法
对实例的公有属性赋值与更改公有属性的区别(引用,直接划分空间),可以通过obj.xxx=xxx来修改 或者使用classname.xxx=xxx来修改。一种是重新在对象中划分空间来存储这个属性,即普通属性/成员属性。一种是直接修改公有属性的值,其他obj也能继续调用被修改的值。
7、类的析构方法
程序运行结束也会将对象释放同时触发析构
import time class rabbit(object): mother='大花兔' def __init__(self,name): self.name=name self.__color='red' def eat_carrot(self,n): print('一只小兔子 \033[31;1m%s\033[0m 吃了 \033[31;1m%s\033[0m 个胡萝卜'%(self.name,n)) def __del__(self): print('小兔子%s去找妈妈了'%self.name) r1=rabbit('小红') r2=rabbit('小灰') r1.eat_carrot(2) r2.eat_carrot(3) print(r1.mother) print(r2.mother) print('*************************') rabbit.mother='大灰狼' print(r1.mother) print(r2.mother) print('*************************') r1.mother='灰太狼' print(r1.mother) print(r2.mother) print('*************************') def eatmore(x): print(x.name,'吃饱啦,吃不下啦') rabbit.eat_carrot=eatmore r1.eat_carrot() r2.eat_carrot() print('---------------------------') def eatenough(x): print(x.name,'不喜欢吃萝卜') r1.eat_carrot=eatenough r1.eat_carrot(r1) r2.eat_carrot() print('*************************') del r2 print('exit')#程序退出释放r1 运行析构 ------------------------------------------------------------ F:\my_python_file\venv\Scripts\python.exe F:/my_python_file/tmp.py 一只小兔子 小红 吃了 2 个胡萝卜 一只小兔子 小灰 吃了 3 个胡萝卜 大花兔 大花兔 ************************* 大灰狼 大灰狼 ************************* 灰太狼 大灰狼 ************************* 小红 吃饱啦,吃不下啦 小灰 吃饱啦,吃不下啦 --------------------------- 小红 不喜欢吃萝卜 小灰 吃饱啦,吃不下啦 ************************* 小兔子小灰去找妈妈了 exit 小兔子小红去找妈妈了 Process finished with exit code 0
说明:
1、需要区分公有属性和成员属性
2、公有属性及方法都是共用内存相同的空间,针对类进行修改公有属性和方法会影响所有的对象
3、如果针对对象进行单独的赋值修改,会在对象的内存空间中划分一块独立的地方来保存这个新方法,不会影响到其他变量
4、析构方法在程序退出的时候都会被释放
8、类的继承
继承是指一个对象直接使用另一对象的属性和方法。 继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码。
8.1、经典类继承、新式类继承
class Member(object): Member_count=0 def __init__(self,name,age): self.name=name self.age=age self.enroll() def enroll(self): print('[%s] 注册成功!'%self.name) Member.Member_count+=1 def showall(self): print('\t----info [%s]----'%self.name) for i , j in self.__dict__.items(): print('\t',i,'------>',j) print('\t------------------------------------') def __del__(self): Member.Member_count-=1 print('[%s] 被注销,系统当前注册用户数[%s]'%(self.name,Member.Member_count)) class Teacher(Member): def __init__(self,name,age,salary,course): Member.__init__(self,name,age) self.salary=salary self.course=course def teach(self): print('[%s] is teaching'%self.name) class Student(Member): def __init__(self,name,age,major): #Member.__init__(self,name,age) #经典类写法 super(Student, self).__init__(name,age)# 新式类写法 self.major=major self.fee=0 def payit(self,money): print('[%s] has paied [%s]'%(self.name,money)) self.fee+=money if __name__=='__main__': T1=Teacher('Teacher 001',50,40000,'network') S1=Student('Student 001',20,'金融') T1.teach() S1.payit(300) T1.showall() S1.showall() -------------------------------------------------------------- [Teacher 001] 注册成功! [Student 001] 注册成功! [Teacher 001] is teaching [Student 001] has paied [300] ----info [Teacher 001]---- name ------> Teacher 001 age ------> 50 salary ------> 40000 course ------> network ------------------------------------ ----info [Student 001]---- name ------> Student 001 age ------> 20 major ------> 金融 fee ------> 300 ------------------------------------ [Teacher 001] 被注销,系统当前注册用户数[1] [Student 001] 被注销,系统当前注册用户数[0]
说明:1、熟悉新式类和经典类的写法 2、熟悉obj.__dict__.items()的使用
8.2、新式类,经典类与多继承
需要知道深度继承,广度继承的区别,
需要知道 python2.7中经典类class x,新式类class x(object)的两种继承方式。一种有括号object,一种没有,在python2中没有括号的经典类为深度继承,有括号的新式类为广度继承
需要知道python3 不论是使用新式类还是经典类都是广度继承
class A(object):#新式类
class A:#经典类 def __init__(self): self.no="A" def showit(self): print('%s'%self.no) class B(A): pass #def __init__(self): # self.no='B' class C(A): pass #def __init__(self): # self.no='C' class D(B,C): pass #def __init__(self): # self.no='D' tmp_data=D() tmp_data.showit()
说明:经典类d->b->a->c 这样的顺序寻找并继承。新式类:d->b->c->a这样的方式继承
9、多态的实现
在父类中调用子类的方法。python中只能通过变通的方式来实现
class Animal(object): def talk(self): print('nononono') class Dog(Animal): def __init__(self,name): super(Dog, self).__init__() self.name=name def talk(self): print('汪汪汪') d=Dog('tom') def Animal_talk(x): return x.talk() Animal_talk(d)
---------------------------------------
汪汪汪
说明,此时如果有个cat类继承animal,同时cat中也有一个talk方法,那边也可以使用Animal_talk这个函数接口来实现cat的talk,多个对象使用一个接口展现出不同的效果。这就是多态。
10、面向对象的综合概述
10.1、概括面向对象编程
一种编程范式:使用类和对象来实现功能
10.2、什么是类,什么是对象
模块里面有类,类里面有函数
类:类可以被称作属性(字段)+方法(函数)的集合
需要使用类里面函数,则需要实例化一个类的对象,通过实例来调用类的对象
Class name-->定义一个类
Obj=类名()-->实例化方式 类名加括号
10.3 面向对象 面向过程的对比
相比于面向过程,面向对象的内存开销更大
在一些场景下 面向对象能更快的实现某个功能
10.3.1 处理ssh连接 (paramiko)
10.3.2 根据模板创建东西(人,动物)
10.3.3 很多的函数需要同样的参数的时候(self)
10.4 如何理解方法中的self
self就是个参数,表示的是调用当前方法的对象
10.5 方法和属性在内存中的保存方式
Self.name=name
字段(属性)保存在对象中
方法保存在类中
普通字段 普通属性
静态字段 公有属性
私有字段 私有方法
10.6 面向对象三大特点
封装、继承、多态
10.7 封装的理解
类和对象封装内存中的一块地址
类:类中封装了静态字段(公有属性)、方法
对象:普通字段的值和方法
10.8 继承 - 单继承、多继承
一个对象直接使用另一对象的属性和方法
多继承需要考虑到python2的深度继承及广度继承
10.9 多态
首先Python不支持多态,也不用支持多态,使用函数返回值的方式可以完成类似多态。详细实现见上文
11、staicmethod
staticmethod 独立与对象本身
class dog(): def __init__(self,name): self.name=name @staticmethod def eat(self,food): print('[%s] is eating [%s]'%(self.name,food)) d1=dog('dog1') d1.eat(d1,'xxx') #此处需要把对象传入 ---------------------------------------- [dog1] is eating [xxx]
12、静态方法、类方法、属性方法。
静态方法 staticmethod
self不会被传入,实际上跟类没有什么关系了。只是相当于一个单独的函数
类方法 classmethod
类方法只能访问类方法、类变量,不能访问具体对象内的值。传入的参数为cls。
属性方法 propety
把一个方法变成一个静态属性 不需要用()调用
修改变量 setter
删除变量 deleter
class X1(object): xxx='123' def __init__(self,name): self.name=name self.__food=None @staticmethod def print_ok(): print('ok') @classmethod def print_it(cls): cls.print_ok() print(cls.xxx) @property def print_name(self): print(self.name,'--------',self.__food) @print_name.setter def print_name(self,food): self.__food=food @print_name.deleter def print_name(self): del self.__food try: X1.print_it() #classmethod可以将整个class放入参数中传递进去,可以使用类的公有属性及静态方法。 x=X1('小明') x.print_name#此处不需要加() x.print_name='baozi' #此处赋值 x.print_name del x.print_name x.print_name except Exception as R: print (R) ---------------------------------------- ok 123 小明 -------- None 小明 -------- baozi 'X1' object has no attribute '_X1__food'
说明:classmethod中调用了staticmethod方法及类属性。属性方法,将方法变为属性,其中变量需要使用setter来设置,并使用deleter来删除
13、对象的特殊属性方法(是方法,但是不需要使用()括号来调用)
13.1 __doc__ 注释
13.2 __init__ 构造方法
13.3 __moudle__
13.4 __class__
13.5 __del__ 析构方法
13.6 __call__ 对象传参数调用
13.7 __dict__ 查看对象或类中的所有属性和方法
13.8 __str__ 返回值方法
class dog(object): '''这是个定义狗对象的类''' def __init__(self): self.name='汪' def __del__(self): print('狗狗跑走了') def __call__(self, *args, **kwargs): print(args, kwargs) def __str__(self): return self.name class cat(object): '''这是个定义猫对象的类''' def __init__(self): self.name='瞄' def __del__(self): print('小猫上树了') def __call__(self, *args, **kwargs): print(args,kwargs) def __str__(self): return self.name print(dog.__doc__,cat.__doc__) print(dog.__module__,cat.__module__) print(dog.__class__,cat.__class__) d1=dog() c1=cat() d1(1,2,3,4,key1='value',key2='value2') c1(1,2,3,4,key1='value',key2='value2') print(d1,c1) print(d1.__dict__,c1.__dict__) del d1 del c1 ------------------------------------- 这是个定义狗对象的类 这是个定义猫对象的类 __main__ __main__ <class 'type'> <class 'type'> (1, 2, 3, 4) {'key1': 'value', 'key2': 'value2'} (1, 2, 3, 4) {'key1': 'value', 'key2': 'value2'} 汪 瞄 {'name': '汪'} {'name': '瞄'} 狗狗跑走了 小猫上树了
13.9 getitem、setitem、delitem 将对象变成一个字典
class Mydict(object): kk={} def __setitem__(self, key, value): self.kk[key]=value def __getitem__(self, item): return self.kk[item] def __delitem__(self,item): del self.kk[item] x=Mydict() x[1]='你好' x[2]='i am fine' xxx=x[1] print(xxx) print(x[2]) del x[1] #print(x[1]) 出错
--------------------
你好
i am fine
14、类的起源与metaclass
此处不做了解,仅仅占个位
15、反射
四种方法,用来通过字符串来对类的属性、方法进行调用(get),查询(has)、设置(set)、删除(del)
#getattr()
#setattr()
#hasattr()
#delattr()
#四个方法 #getattr() #setattr() #hasattr() #delattr() class Dog(object): def __init__(self,name): self.name=name def talk(self): print('wangwangwang') def run(): print('is runing') d1=Dog('a_wu') print(d1.name) x='name'#假设此处为用户输入 x2='talk' #print(d1.x) print(hasattr(d1,x)) print(getattr(d1,x)) print(getattr(d1,x2)) getattr(d1,x2)()#调用属性及方法 模拟input #f2() setattr(d1,'run2',run)#添加方法 setattr(d1,'age','22') d1.run2() print(d1.age) delattr(d1,'age') # print(d1.age) AttributeError: 'Dog' object has no attribute 'age' -------------------------------------------------- a_wu True a_wu <bound method Dog.talk of <__main__.Dog object at 0x00000000027D7DA0>> wangwangwang is runing 22
16、异常处理,包括捕获异常(单一捕获、多个捕获、总捕获及未知异常处理、以及自定义异常并触发)
15.1 熟悉try/except/else/finally四种方式,用来捕获各种异常,并捕获部分无法被捕获的异常
15.2 了解自定义异常的方法
自定义一个类、init构造对象是传进去的参数就是输出的结果,多个输入,输出结构为元组的形式,可以通过__str__来重新定义输出结果。
a=[0,1,2,3] b={} try: #a[10] #b['name'] #adfafdfa #出错了 name 'adfafdfa' is not defined #except (IndexError,KeyError) as e: #pass pass #可以组合写 一般不推荐,除非对于出现某几种错误 采取同样的处理方式,则使用此方法 except IndexError as e: print(e) #会先打印 Index的Error 异常出现后不会继续往下 except KeyError as e: print(e) #except Exception as e:#出错了 name 'adfafdfa' is not defined #print('出错了',e) 抓住所有的错误,一般不用这个方法 else: print('一切正常') finally: print('有错没错都执行') #抓一个 #抓多个 #抓全部 #未知错误(最后使用Exception来抓未知错误) #else一切正常 #finally 不管错没错都会执行 #缩进错误等让程序无法编译下去的错误 都是无法被except捕捉的 #定义一个自定义异常 class Myexcept(Exception): def __init__(self,message,xxx): self.msg=message self.xxx=xxx self.xxx2='1231231'#默认这个不会被输出 #def __str__(self): # return self.xxx #str的返回值就是自定义异常的报错。 #如果不写str默认返回输入的值 这个很重要 try : raise Myexcept('数据库挂了','2') except Myexcept as e: print(e) ------------------------------------------- 一切正常 有错没错都执行 ('数据库挂了', '2')
三、socket入门
socket,应用层通过socket调用操作系统接口通过网卡与指定的ip及端口进行通信,建立连接发送相应的内容。
1、socket收发一次数据包
使用socket.socket()创建一个连接对象,socket()里面有三个可以设置:
参数1地址簇:
AF.INET、AF.INET6、AF.UNIX 分别代表了ipv4、ipv6以及local
参数2传输类型:
socket.SOCK_STREAM(for tcp)、socket.SOCK_DGRAM(for udp)、socket.SOCK_RAM(for icmp、igmp、也可自建包头此处不研究)、socket.SOCK_RDM(可靠的udp,保证交付数据包,但不保证顺序)、socket.SOCK_SEQPACKET(可靠的连续数据包服务)
参数3类型:
使用什么协议进行数据传输(put、get、post这些动作)默认为0,系统自动选择合适的协议
import socket #socket 协议簇 IPV4 IPV6 IP_UNIX(127.0.0.1) #socket type TCP UDP raw自定义ip头部 可靠的UDP import time client1=socket.socket() #声明socket类型 client1.connect(('localhost',6969)) #time.sleep(10) client1.send(b'are you ok?') data=client1.recv(1024) print('recv',data) client1.close() -------------------------------------------- import socket server1=socket.socket()#创建server1对象 server1.bind(('localhost',6969))#step 1绑定需要监听的ip和端口 server1.listen()#step 2 准备监听 print('正在等待连接') conn1,addr1=server1.accept()#step 3正式开始监听端口 #conn1 1 为客户端在服务器端生成的一个连接实例,addr为连接的ip端口 print(conn1,addr1) print('接收到连接') data=conn1.recv(1024)#step4 开始接收文件 ,定义接收缓存的大小(会受到系统及网卡限制) print('recv',data) conn1.send(data.upper()) server1.close() ------------------------------------------------------- 正在等待连接 <socket.socket fd=304, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6969), raddr=('127.0.0.1', 53508)> ('127.0.0.1', 53508) 接收到连接 recv b'are you ok?'
2、socket多次收发,以及多终端收发
#!/bin/env python3 import socket server1=socket.socket() server1.bind(('0.0.0.0',6666)) server1.listen() while True: print('等待连接中。。。。') conn1,addr=server1.accept() print(addr) while True: x=conn1.recv(1024) if not x:break #为空则退出 print('recv',x.decode()) server1.close() --------------------------------------------------- import socket client1=socket.socket() client1.connect(('115.159.44.122',8888)) while True: x=input('请输入要传输的内容:').strip() if x=='exit': client1.close() break client1.send(x.encode('utf-8')) result1=client1.recv(1024).decode() print(result1) #了解缓冲区与sendall client1.close()
3、socket接口使用shell指令
#!/bin/env python3 import socket import os s1=socket.socket() s1.bind(('0.0.0.0',8888)) s1.listen(5)#同时支持的连接数,此处无用,在异步时有用 print('正在等待客户端连接') connect1,addr1=s1.accept() while True: print('正在等待远程指令') #connect1,addr1=s1.accept() data=connect1.recv(102400).decode() if not data :break print('接收到指令》》》',data) tmp_shell=os.popen(data).read() connect1.send(tmp_shell.encode('utf-8')) print('结果已经返回,请查看客户端') connect1.close()
说明,os.popen的使用,将结果返回给客户端,注意命令的大小以及了解缓冲区
1.4 缓冲区与sendall
每次能收到及发出的数量受到网络、操作系统等各种因素的限制,所以需要多次接收及发送才能完成接收大文件的过程。sendall就是会重复的多次发送
#!/bin/env python3 import socket s1=socket.socket() s1.bind(('0.0.0.0',9999)) s1.listen() print('等待连接') conn,addr=s1.accept() print('已经连接',addr) with open('/tmp/20180330test.exe','wb') as f: print('文件打开') count=1 while True: data=conn.recv(102400) if not data: f.close() break f.write(data) f.flush() print('count=',count) count+=1 #x=input('继续') s1.close() ---------------------------------------------- import socket c1=socket.socket() c1.connect(('115.159.44.122',9999)) with open(r'D:\360setup.exe','rb') as f : data=f.read() print(len(data)) c1.sendall(data) print('传输完成') f.close() c1.close()
---------------------------------------------------
count= 28242
count= 28243
count= 28244
count= 28245
count= 28246
count= 28247
count= 28248
count= 28249
count= 28250
count= 28251
count= 28252
count= 28253
count= 28254
count= 28255
count= 28256
count= 28257
count= 28258
count= 28259
count= 28260
说明:客户端给服务器端使用sendall将所有的数据循环发出(不同的电脑及不同的系统。一次能发出的数据量是有限的),服务器端使用while 循环接收。客户端发完后,断开连接,服务器端data为空,则表示接收完毕。