day7-面向对象高级与socket编程
今日学习的内容
1.类与对象
2.对象之间的交互
3.类的继承
4.继承原理
5.组合
6.抽象类
7.多态与多态性
8.封装
9.特性
10.反射
11.面向对象的高级用法
12.socket编程
1.类与对象
面象对象编程解决了程序扩展性的问题。
类的第一个功能:实例化;
类的第二个功能: 属性引用(包括变量属性和函数属性)。
例如:定义1个类,实例化2个对象,并引用属性
class Garen:
camp = "Demacia"
def __init__(self,nickname,aggresivity,life_value):
self.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self):
print("is attacking..")
g1 = Garen("盖伦",82,100)
g2 = Garen("盖伦2",82,200)
print(g1.nickname)
print(g1.aggrv)
print(g1.life_value)
print(Garen.attack)
print(g1.attack)
输出:
-----------------------------------------------------------------------------
盖伦
82
100
<function Garen.attack at 0x00000000021EBAE8> # 通过类调用的函数,称为function
<bound method Garen.attack of <__main__.Garen object at 0x00000000021E9C88>> # 通过实例调用的函数,称为bound method
2.对象之间的交互
例如: 创建2个类,实例化2个对象
class Garen:
camp = 'Demacia'
def __init__(self,nickname,aggresivity,life_value):
self.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self,enemy):
enemy.life_value -= self.aggrv
class Riven:
camp = 'Noxus'
def __init__(self,nickname,aggresivity,life_value):
self.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self,enemy):
enemy.life_value -= self.aggrv
g1 = Garen("盖伦",82,100)
r1 = Riven("瑞文",50,200)
print("-----------------------------------------")
# g1 attack r1
print("r1的生命值: %s" % (r1.life_value))
g1.attack(r1)
print("r1被攻击后的生命值: %s" % (r1.life_value))
# r1 attack g1
print("g1的生命值: %s" % (g1.life_value))
r1.attack(g1)
print("g1被攻击后的生命值: %s" % (g1.life_value))
3.类的继承
继承可以重用代码。
如果需要创建的两个对象有相同的属性,也有不同的属性,可以先创建一个基类(包含共性),然后再创建两个类,从基类继承共性,对于不同的属性(方法)可以重写。
代码重用的写法:
class Hero:
def __init__(self,nickname,aggresivity,life_value):
self.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self,enemy):
print("is attacking...",self,enemy)
enemy.life_value -= self.aggrv
class Garen(Hero):
camp = "Demacia"
def run(self):
print("is running.....")
class Riven(Hero):
camp="Noxus"
g1 = Garen("盖伦",82,100)
r1 = Riven("瑞文",50,200)
g1.run()
g1.attack(r1)
输出:
--------------------------------------------------
is running.....
is attacking... <__main__.Garen object at 0x0000000002759DD8> <__main__.Riven object at 0x0000000002759E10>
继承的写法:
class People:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def test(self):
print("from People.test")
# 继承的第一种写法:
class Teacher(People):
def __init__(self,name,age,gender,level):
People.__init__(self,name,age,gender)
self.level = level
# 继承的第二种写法:
class Teacher2(People):
def __init__(self,name,age,gender,level):
super().__init__(name,age,gender)
self.level = level
t = Teacher("tomas",20,"female","senior")
print(t.level)
4.继承原理
关于类的继承:
经典类(python2默认):采用深度优先
新式类(python3默认):采用广度优先
例如:
class A:
def test(self):
print('from A')
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(B):
# def test(self):
# print('from D')
pass
class E(C):
# def test(self):
# print('from E')
pass
class F(D,E):
# def test(self):
# print('from F')
pass
f1 = F()
f1.test()
print(F.mro())
输出:
from A
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
5.组合
例如:
class Teacher:
def __init__(self,name,birth,course):
self.name = name
self.birth = birth
self.course = course
class Course:
def __init__(self,name,price,period):
self.name = name
self.price = price
self.period = period
class Date:
def __init__(self,year,mon,day):
self.year = year
self.mon = mon
self.day = day
t = Teacher("tom",Date(1999,12,20),Course("python",11000,"8mon"))
print(t.birth.year)
输出:
-------------------------
1999
6.抽象类
父类定义功能(函数名),子类必须重写函数功能,抽像类不能实例化,只能用来继承。
import abc
class AllFile(metaclass=abc.ABCMeta):
def test(self):
print("for testing....")
@abc.abstractmethod
def read(self):
pass
@abc.abstractmethod
def write(self):
pass
class Text(AllFile):
def read(self):
print("text read")
def write(self):
print("text write")
t = Text()
t.read()
t.write()
t.test()
输出:
-----------------------
text read
text write
for testing....
7.多态与多态性
多态是指同一种事物的不同形态,如序列化类型包括字符串,列表,元组
s = "helllo world"
l = [1,2,3]
t = (1,2,3)
多态性的用法:
class Animal:
def talk(self):
pass
class People(Animal):
def talk(self):
print("say hello")
class Dog(Animal):
def talk(self):
print("wang wang....")
class Cat(Animal):
def talk(self):
print("miao miao....")
p1 = People()
d1 = Dog()
c1 = Cat()
def func(obj):
obj.talk()
func(p1)
func(d1)
func(c1)
输出:
-----------------------------------------
say hello
wang wang....
miao miao....
8.封装
封装可以隐藏类的属性(包括变量和函数)。
用法:
class Foo:
x = 1
def __init__(self,name,money):
self.name = name
self.__money = money
def getmoney(self):
print(self.__money)
self.__spam() # 在内部函中调用隐藏函数
def __spam(self): # 定义隐藏函数
print("from __spam.......")
f = Foo("tom",100)
# print(f.name)
# 定义类时以下画线开头的变量,会被隐藏:AttributeError: 'Foo' object has no attribute '__money'
# print(f.__money)
# 尽管类在定义时隐藏了__money,但是在内部的函数中是可以正常调用的。
# f.getmoney()
# 以字典形式打印类和对象的属性。
print(Foo.__dict__)
print(f.__dict__)
# 打印隐藏变量的方法
print(f._Foo__money)
# 在类定义之后,赋值时,以下划线开头的变量不会变形,可以直接引用。
f.__x = 10000
print(f.__x)
输出:
------------------------------------------
{'__module__': '__main__', 'x': 1, '__init__': <function Foo.__init__ at 0x00000000021CB8C8>, 'getmoney': <function Foo.getmoney at 0x00000000021CB950>, '_Foo__spam': <function Foo.__spam at 0x00000000021CB9D8>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
{'name': 'tom', '_Foo__money': 100}
100
10000
9.特性
特性的用法一:
import math
class Circle:
def __init__(self,radius):
self.__radius = radius
def area(self):
return math.pi * self.__radius**2
def perimeter(self):
return math.pi * 2 * self.__radius
# 普通函数的调用方式:
c = Circle(10)
print(c.area())
print(c.perimeter())
输出:
----------------------------
314.1592653589793
62.83185307179586
import math
class Circle:
def __init__(self,radius):
self.__radius = radius
@property # area = property(area)
def area(self):
return math.pi * self.__radius**2
@property # perimeter=property(perimeter)
def perimeter(self):
return math.pi * 2 * self.__radius
# property的调用方式:
c = Circle(10)
print(c.area)
print(c.perimeter)
输出:
----------------------------
314.1592653589793
62.83185307179586
特性的用法二:
class A:
def __init__(self,name):
self.__name = name
@property
def name(self):
return self.__name
@name.setter
def name(self,value):
if not isinstance(value,str):
raise TypeError("value must be str")
self.__name = value
@name.deleter
def name(self):
print("deleting.............")
raise AttributeError("error") # 删除时会报这个错
a = A('tom')
print(a.name)
a.name = "Frank"
print(a.name)
输出:
----------------------
tom
Frank
10.反射
反射的用法一:hasattr
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
def compute(self):
print(self.name,self.age)
p1 = foo("xxx",20)
if hasattr(p1,"compute"):
p1.compute()
else:
print("no")
输出:
-------------------
xxx 20
反射的用法二:getattr
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
def compute(self):
print(self.name,self.age)
p1 = foo("xxx",20)
if hasattr(p1,"compute"):
func = getattr(p1,"compute")
print(func)
func()
输出:
----------------------
<bound method foo.compute of <__main__.foo object at 0x00000000021C9CF8>>
xxx 20
反射的用法三:setattr
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
def compute(self):
print(self.name,self.age)
p1 = foo("xxx",20)
print("修改前: %s" % p1.name)
setattr(p1,'name',"yyy")
print("修改后: %s" % p1.name)
输出:
修改前: xxx
修改后: yyy
反射的用法四:delattr
class foo:
def __init__(self,name,age):
self.name = name
self.age = age
def compute(self):
print(self.name,self.age)
p1 = foo("xxx",20)
p1.z = 100
print(p1.__dict__)
delattr(p1,"z")
print(p1.__dict__)
输出:
-----------------------
{'name': 'xxx', 'age': 20, 'z': 100}
{'name': 'xxx', 'age': 20}
11.面向对象的高级用法
"def _call_"的用法:
class Foo:
def __init__(self,name):
self.name = name
def __call__(self, *args, **kwargs):
print("now, it's callable!")
f = Foo("tesila")
f()
输出:
----------------------------
now, it's callable!
"def _getitem_" "def _setitem_" "def _delitem_"的用法:
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item):
print("getitem",self.__dict__)
return self.__dict__[item]
def __setitem__(self, key, value):
print("setitem")
self.__dict__[key] = value
def __delitem__(self, key):
print("del object:")
self.__dict__.pop(key)
f = Foo("tomas")
print(f['name'])
f['age'] = 1000
print(f['age'])
del f['age']
print(f.__dict__)
输出:
-----------------------------------------
setitem
getitem {'name': 'wills', 'age': 1000}
1000
del object:
{'name': 'wills'}
12.socket编程
执行远程命令的服务器与客户端:
服务端:
import socket
import subprocess
import json
import struct
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(("127.0.0.1",8080))
server.listen(5)
while True:
conn,addr = server.accept()
print("client:",addr)
while True:
try:
cmd = conn.recv(1024)
if not cmd: break
print("from client msg: %s" %cmd)
res = subprocess.Popen(cmd.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
err = res.stderr.read()
if err:
back_msg = err
else:
back_msg=res.stdout.read()
print(type(back_msg))
# 第一阶段:制作报头
head_dict = {
'data_size':len(back_msg)
}
head_json = json.dumps(head_dict)
head_bytes = head_json.encode("utf-8")
# 第二阶段:发送报头的长度
conn.send(struct.pack('i',len(head_bytes)))
# 第三阶段:发送报头
conn.send(head_bytes)
# 第四阶段: 发送真实数据
conn.sendall(back_msg)
except Exception:
break
conn.close()
server.close()
客户端:
import socket
import json
import struct
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(("127.0.0.1",8080))
while True:
cmd = input("client> ").strip()
if not cmd: continue
client.send(cmd.encode("utf-8"))
# 收取报头长度
head = client.recv(4)
head_size = struct.unpack('i',head)[0]
# 收取报头
head_bytes = client.recv(head_size)
head_json = head_bytes.decode("utf-8")
head_dict = json.loads(head_json)
data_size = head_dict['data_size']
# 收取真实数据
recv_size = 0
recv_bytes=b''
while recv_size < data_size:
res = client.recv(1024)
recv_bytes += res
recv_size += len(res)
print(recv_bytes.decode('gbk'))
浙公网安备 33010602011771号