第三个模块
面向对象
1、什么是面向对象?
i.面向对象和面向过程的区别
面向过程:核心是过程二字,过程指的是解决问题的步骤,设计一条流水线,机械式的思维方式;优点:复杂的问题流程化,进而简单化;缺点:可扩展性差
面向对象:核心就是对象二字,对象就是特征与技能的结合体;优点:可扩展性强;缺点:编程复杂度高。
ii简述类、对象、实例化是什么?
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型、模板。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法;
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同;
实例化:把一个类转变为一个对象的过程就叫实例化
2、类与对象
i.实例和实例化
实例(对象):一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同;
实例化:把一个类转变为一个对象的过程就叫实例化。
ii.解释一下构造函数中__init__(self)中的self是什么意思?
self,就是实例本身!你实例化时python解释器会自动把这个实例本身通过self参数传进去。
iii.类变量和实例变量的区别和作用?
类变量是所有实例共有,实例变量是对象独有的数据;
静态变量在类中,不属于实例对象,属于类所有,只要程序加载了字节码,不用创建实例对象静态变量就会被分配空间,已经可以使用。
实例变量是某个对象的属性,只有实例化对象后,才会被分配空间,才能使用。类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;
而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象;
3、继承和派生
class Parent(object): def __init__(self,name,age): self.name = name self.age = age class Child(Parent): def __init__(self,name,age,sex): Parent.__init__(self,name,age) #super.__init__(name,age) d = Child('ago',18,'M') print(d.name)
i. 以下python3代码最终结果是什么?也就是顺序是什么?继承广度优先和深度优先(继承的顺序)
class A(object): def test(self): print('A') class B(A): def test(self): print('B') class C(A): def test(self): print('C') class D(B): def test(self): print('D') class E(B): def test(self): print('E') class F(D,E,C): def test(self): print('F') f1 = F() f1.test() print(F.__mro__) #打印: F (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
顺序是F--D--E--B--C--A--object
py3中继承的是广度优先
ii. 继承和装饰器
在定义类时,可以从已有的类继承, 被继承的类称为基类(父类),新定义的类称为派生类(子类)。
装饰器(deco):装饰函数的参数是被装饰的函数对象,返回原函数对象 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象 概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
类装饰器:@property 装饰过的函数返回的不再是一个函数,而是一个property对象装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。
@staticmethod (静态方法)把没有参数的函数装饰过后变成可被实例调用的函数, 函数定义时是没有参数的,可以不接收参数
@classmethod (类方法)把装饰过的方法变成一个classmethod类对象,既能被类调用又能被实例调用。 注意参数是cls代表这个类本身。 一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。 而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。 这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。
iii. 继承和组合(把一个实例当成参数传给类)
通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合。
4、属性和绑定方法
i. 共有属性和私有属性
_m:代表私有属性,仅能在实例的内部各方法(函数)中调用;隐藏一些功能的的实现细节,只给外部暴露调用。
共有属性是所有对象都可以用的
5、多态和多态性
多态指的是一类事物有多种形态。动物有多种形态:人,狗,猪等
多态性指在不考虑实例类型的情况下使用实例;多态性分为静态多态性和动态多态性。
静态多态性:如任何类型都可以用运算符+进行运算;字符串、列表、数字都能用上加上,站在+号的角度。
6、封装
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。
7、构造方法__init__和析构方法__del__
__init__()类的初始化,类被实例化的时候执行该函数,放置需要初始化的属性;
__del__()回收资源的,外部主动调用执行,对象在作用域中调用完毕,跳出作用域就会被执行、释放内存空间。
8、以下代码执行后分别得到结果是什么?说明缘由
class A: def __test(self): #_A__test print('A.test') def func(self): print('A.func') self.__test()#b._A__test() class B(A): def __test(self): #_B__test print('B.test') b = B() b.func() #打印: A.func A.test
实例化对象b先从自己这找func,没有再去自己的类里边找,也没有再去父类A里边找,得到A.func
self.__test()相当于是b._A__test();在A类中,__test(self)将其封装了,实际上是_A__test;在B类中,__test(self)相当于_B__test,所以是A.test
class A: def test(self): print('A.test') def func(self): print('A.func') self.test()#b.test() class B(A): def test(self): print('B.test') b = B() b.func() #打印: A.func B.test
实例化对象b先从自己这找func,没有再去自己的类里边找,也没有再去父类A里边找,得到A.func;self.test()相当于b.test()自己这没有,在自己的类B中找,得到B.test
9、特性property有什么作用?name.setter和name,deleter;什么是property,如何定义,如何使用,给谁用,什么情况下应该将一个属性定义成property,有什么好处?
property是把一个方法转换成实例的属性。func = property(func) 或者@property来装饰方法(函数)
此时的name是一个property对象。该对象下面有getter、setter、deleter等方法。
只有@property表示只读;同时有@property和@x.setter表示可读可写;同时有@property和@x.setter和@x.deleter表示可读可写可删除。
(参考:http://www.cnblogs.com/yangzhenwei123/p/6759311.html)
10、静态方法和类方法staticmethod和classmethod区别是什么?
class A: __role ='CHINA' #_A__role = 'CHINA' @classmethod #绑定到类的方法,由类来调用,把类当做第一个参数传进去 def show_role(cls): print(cls.__role) #A._A__role @staticmethod #非绑定方法,对象和类都可以调用,没有自动传值了 def get_role(): return A.__role # A._A__role @property #让使用者使用的时候感知不到他是个调用一个功能,他以为自己是用的数据属性。必须要有个返回值作为它的结果 def role(self): return self.__role #a._A__role a = A() print(a.role) print(a.get_role()) a.show_role() #打印: CHINA CHINA CHINA
__role在类中属于类的数据属性,被隐藏起来了,实际上是_A__role
三个装饰器的作用见上边代码。
11、反射
使用反射的知识点查看类的静态属性role;使用反射的知识点调用类的func方法;请为b对象设置一个name属性,值为你的名字。
class B: role = 'CHINA' def func(self): print('in func') b = B() print(getattr(B,'role')) getattr(b,'func')() setattr(b,'name','kris') print(b.name) #打印: CHINA in func kris
12、__getitem__ __delitem__ __setitem__ 的作用?
可以让对象变成一个dict一样操作;
13、利用type语法生成下面这个类
class Test(object): def __init__(self,name,age): self.name = name self.age = age def sayhi(self,name): print('self',name,self.name) class_name = 'Test' class_bases = (object,) class_body =""" def __init__(self,name,age): self.name = name self.age = age def sayhi(self,name): print('self',name,self.name) """ class_dic = {} exec(class_body,globals(),class_dic) Test = type(class_name,class_bases,class_dic) print(Test) #打印: <class '__main__.Test'>
14、__new__()作用是什么,它和__init__ 有什么关系?
__new__用来创建类对象,实例化一个cls的类对象,表示这个类已经被加载了,解析了,现在可以拿着这个类创建普通实例对象了。如果类对象创建失败,则不会调用init方法;其用处是:自定义方式创建类对象,比如改变这个类的属性等。
__new__ 用来创建实例,在返回的实例上执行__init__,如果不返回实例那么__init__将不会执行;实例化一个类时,最先被调用的方法 其实是 __new__ 方法
__init__是在类实例创建之后调用,而 __new__方法正是创建这个类实例的方法。
参考:http://www.jb51.net/article/48044.htm
15、自定义元类利用metaclass __new__ __init__ __call__创建一个类(定制类)
class MyType(type): def __init__(self, *args, **kwargs): print("元类init") super(MyType, self).__init__(*args, **kwargs) def __new__(cls, *args, **kwargs): print("new") return super().__new__(cls, *args, **kwargs) def __call__(self, *args, **kwargs): print("call") obj = self.__new__(self, *args, **kwargs) # object.__init__(....) obj.__init__(*args, **kwargs) # self.__init__(obj,*args, **kwargs) return obj ##没有这一步,结果也是一样的 class Foo(object, metaclass=MyType): def __init__(self): print('本类init') x = Foo() # new # 元类init # call # 本类init
16、自定义类
i. 一个圆形类,属性是半径,提供两个方法,计算圆周长和面积
from math import pi class Circle: def __init__(self,r): self.r = r def area(self): return self.r**2*pi def perimeter(self): return 2*pi*self.r c1 = Circle(5) print(c1.area()) print(c1.perimeter()) #打印: 78.53981633974483 31.41592653589793
ii. 实现如图的继承关系,然后验证经典类与新式类在查找一个属性时的搜索顺序
经典类是深度优先;新式类是广度优先的查找顺序
iii. 基于多态的概念来实现linux中一切皆问题的概念:文本文件,进程,磁盘都是文件,然后验证多态性
import abc class All_file(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): print('All file') pass @abc.abstractmethod def write(self): print('All file') pass class Text(All_file): def read(self): super().read() print('Text read') def write(self): super().write() print('Text write') class Sata(All_file): def read(self): super().read() print("Sata read") def write(self): super().write() print("Sata write") def read(obj): obj.read() def write(obj): obj.write() t = Test() s = Sata() t.read() s.write() read(s)
#打印:
All file
Text read
All file
Sata write
All file
Sata read
iv. 定义老师类,把老师的属性:薪资,隐藏起来,然后针对该属性开放访问接口
class Teacher(): def __init__(self,name,sex,salary): self.name = name self.sex = sex self.__salary = salary def tell_salary(self): print('你的工资是%s'%self.__salary) t1 = Teacher('alex','male',10000) t1.tell_salary()
v. 定义如下类,并最大程度地重用代码(继承,派生:子类重用父类方法,组合)老师类 学生类 分数类 课程类 日期类
class People(): school = 'luffycity' def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex class Teacher(People): def __init__(self,name,age,sex,salary): super().__init__(name,age,sex) self.salary = salary def teach(self): print('%s is teaching'%self.name) class Student(People): def __init__(self,name,age,sex,class_time): super().__init__(name,age,sex) self.class_time = class_time def learn(self): print('%s is learning'%self.name) class Course: def __init__(self,course_name,course_price): self.course_name = course_name self.course_price = course_price def tell_info(self): print("课程名%s,课程价钱%s"%(self.course_name,self.course_price)) class Data: def __init__(self,year,month): self.year = year self.month = month def tell_info(self): print('%s年%s月'%(self.year,self.month)) tea1 = Teacher('alex',33,'male',10000) stu1 = Student('kris',22,'male',7) python = Course('python','8999') data1 = Data(2018,4) tea1.course = python print(python)
vi. 基于授权定制自己的列表类型,要求定制的自己的__init__方法
vii. 定制自己的append:只能向列表加入字符串类型的值
viii. 定制显示列表中间那个值的属性(提示:property)
ix. 其余方法都使用list默认的(提示:__getattr__加反射)
class List: def __init__(self,value): self.x=list(value) def append(self,value): if not isinstance(value,str): raise TypeError('append到列表的内的元素必须是str类型') self.x.append(value) def insert(self,index,value): self.x.insert(index,value) def __getattr__(self, item): return getattr(self.x,item) @property def type(self): print(self.x) t=int(len(self.x)/2) print(self.x[t],type(self.x[t])) l=List([1,2,3]) l.append("egon") l.append('hello') l.append('alex') l.insert(7,5) l.pop() l.type #打印 [1, 2, 3, 'egon', 'hello', 'alex'] egon <class 'str'>
x. 定义用户类,定义属性db,执行obj.db可以拿到用户数据结构
#user.db文件 { "egon":{"password":"123",'status':False,'timeout':0}, "alex":{"password":"456",'status':False,'timeout':0}, }
class User: db_path='user.db' def __init__(self,username): self.username=username @property def db(self): data=open(self.db_path,'r').read() return eval(data) u=User('egon') print(u.db['egon']) print(u.db['egon']['password'])
#打印:
{'password': '123', 'status': False, 'timeout': 0}
123
xii. 根据下述原理,编写退出登录方法(退出前判断是否是登录状态),自定义property,供用户查看自己账号的锁定时间
参考:http://www.cnblogs.com/DragonFire/p/6748082.html
import time class User: db_path='user.db' def __init__(self,name): self.name=name @property def db(self): with open(self.db_path,'r') as read_file: info=read_file.read() return eval(info) @db.setter def db(self,value): with open(self.db_path,'w') as write_file: write_file.write(str(value)) write_file.flush() def login(self): data=self.db if data[self.name]['status']: print('已登录') return True if data[self.name]['timeout'] < time.time(): count=0 while count < 3: passwd=input('password>>: ') if not passwd:continue if passwd == data[self.name]['password']: data[self.name]['status']=True data[self.name]['timeout']=0 self.db=data break count+=1 else: data[self.name]['timeout']=time.time()+10 self.db=data else: print('账号已锁定10秒') u1=User('egon') u1.login() u2=User('alex') u2.login()
网络编程
1、三次握手/四次挥手
基于tcp协议,客户端给服务端发一次消息,服务端要回应下并且给发给客户端,然后客户端再发给服务端,中间两步回应下+给客户端发消息可以合成一步,链接建立完成也就是三次握手;客户端说要断开链接PIN=1,服务端确认下ack=1,客户端接收到了,这条管道就断开了,服务端要断开发PIN=1,客户端回一个ack=1,管道就断开了。
客户端说把数据传完了,服务端不一定传完数据了,中间那两步不能合成一步,所以断开链接需要四次挥手。
2、osi七层模型
物理层功能:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0。
数据链路层的功能:定义了电信号的分组方式按照以太网协议;一组电信号构成一个数据包,叫做一组数据‘帧’;每一数据帧分成:报头head和数据data两部分。head前六个字节和后六个字节是mac地址,基于mac地址来标示对方;在局域网内以广播的方式工作。
网络层功能:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址。
传输层功能:建立端口到端口的通信,端口即应用程序与网卡关联的编号。tcp和udp
应用层功能:有自己的协议如http、ftp协议,跑应用软件。
3、ip
每台机器配个ip地址,有一个IP头和data数据。IP地址和mac地址就可以找到世界上一台独一无二的机器。IP找到子网,mac找到子网它在哪个位置。
IP协议:
- 规定网络地址的协议叫ip协议,它定义的地址称之为ip地址,广泛采用的v4版本即ipv4,它规定网络地址由32位2进制表示
- 范围0.0.0.0-255.255.255.255
- 一个ip地址通常写成四段十进制数,例:172.16.10.1
4、socket 写一个简单的socket的服务端和客户端
##服务端 import socket ph = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ph.bind(('127.0.0.1',8081)) ph.listen(5) print('starting') conn,client_addr = ph.accept() print(client_addr) while True: data = conn.recv(1024) conn.send(data.upper()) conn.close() ph.close() ###客户端 import socket ph = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ph.connect(('127.0.0.1',8081)) while True: msg = input('>>>:') ph.send(msg.encode('utf-8')) data = ph.recv(1024) print(data) ph.close()
5、黏包,解释下黏包现象,如何解决。
客户端只recv(1024), 可结果比1024长只好在服务器端的IO缓冲区里把客户端还没收走的暂时存下来,等客户端下次再来收,所以当客户端第2次调用recv(1024)就会首先把上次没收完的数据先收下来,再收df命令的结果。 这个现象叫做粘包,就是指两次结果粘到一起了。它的发生主要是因为socket缓冲区导致的。问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。
服务端:1收命令;2执行命令,拿到结果;3把命令的结果返回给客户端:3.1制作固定长度的报头;3.2先发送报头的长度;3.3再发报头;3.4再发真实数据
客户端:1发命令;2拿到命令的结果并打印下;2.1先收报头的长度;2.2再收报头;2.3从报头中解析出对真实数据的描述信息;2.4接收真实数据。
报头:字典的形式里有文件名,状态码,文件大小等等
报头长度 struct
6、异常,自定义一个异常
try: print('--before---') l = [1,2,3] l[100] print('--->>>') except Exception as e: print('异常发生了:',e) print('after---')
#自定义个异常类型 class Myexception(BaseException): def __init__(self,msg): super(Myexception,self).__init__() self.msg = msg def __str__(self): return '<%s>'%self.msg raise Myexception('我自己的异常类型')
7、socket和socketserver的区别是什么?
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一 般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。
8、写一个客户端调用服务端的系统命令的程序
import socket import subprocess phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bind(('127.0.0.1',8081)) phone.listen(5) print('starting') while True: conn,client_addr = phone.accept() print(client_addr) while True: try: #1收命令 cmd = conn.recv(1024) #2执行命令拿到结果 obj = subprocess.Popen(cmd.decode('utf-8'),shell= True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) stdout = obj.stdout.read() stderr = obj.stderr.read() #3把命令结果返回给客户端 print(len(stdout)+len(stderr)) conn.send(stdout+stderr) except ConnectionResetError: break conn.close() phone.close()
##服务端 import socket import subprocess phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8081)) while True: #1发命令 cmd = input('>>>:').strip() if not cmd:continue phone.send(cmd.encode('utf-8')) #2拿命令结果并打印 data = phone.recv(1024) print(data.decode('gbk')) phone.close()
编程题
1.定义两个类(人)实例化出:老王和小明
i.共同属性及技能:出生地,吃饭
不同属性及技能:a.属性:名字,年龄;
b.老王技能1:讲课;
c.老王技能2:布置作业
d.小明技能1:罚站
e老王技能3:打小明(假设小明有100点血,被打之后就掉了50点血了)
使用到了继承:共同技能和属性
定义了老王的攻击力:50
定义了小明的血量:100
class People1(): birthday = 'China' def __init__(self, name, age, life_value, aggresivity): self.name = name self.age = age self.life_value = life_value self.aggresivity = aggresivity def eat(self): print("%s is eating"%self.name) def talk_lesson(self): print("%s is talking lesson"%self.name) def have_homework(self): print("%s could hane_homework"%self.name) def attack(self,xm_obj): print('%s 打了%s'%(self.name,xm_obj.name)) xm_obj.life_value -= self.aggresivity class People2: def __init__(self,name,age): self.name = name self.age = age self.life_value = 100 def stand(self): print('%s is standing'%self.name) lw = People1('老王','32',80,50) xm = People2('kris',22) print(xm.life_value) lw.attack(xm) print(xm.life_value)
ii.模拟cs游戏
人物角色分为警察和匪徒两种,定义成两个类;所有的警察角色都是police;每个警察都有自己独有名字,生命值,武器,性别;每个人都可以开枪攻击敌人,且攻击目标不能是police;
所有的匪徒的角色都是terrorist;每个匪徒都有自己独有名字,生命值,武器,性别;每个人都可以开枪攻击别人,且攻击目标不是是terrorist;
a,实例化一个警察,一个匪徒,警察攻击匪徒,匪徒掉血
class Police(): def __init__(self,name,sex,life_value,weapon,aggresivity): self.name = name self.sex = sex self.life_value = life_value self.weapon = weapon self.aggresivity = aggresivity def attack(self,terro_obj): print('%s attack %s'%(self.name,terro_obj.name)) terro_obj.life_value -= self.aggresivity class Terrorist(Police): def __init__(self, name, sex, life_value, weapon, aggresivity): super().__init__( name, sex, life_value, weapon, aggresivity) def attack(self,poli_obj): print('%s attack %s'%(self.name,poli_obj.name)) poli_obj.life_value -= self.aggresivity p1 = Police('kris','male',100,'kk47',50) t1 = Terrorist('galen','female',100,'倚天剑',20) print(t1.life_value) p1.attack(t1) print(t1.life_value)
综合题
1.远程执行命令(subprocess执行命令)saltstack
2.远程配置管理(传输文件) saltstack
3.根据配置进行执行命令
4.远程传输文件
https://blog.csdn.net/chengyuqiang/article/details/78119322 saltstack入门简介