python类和对象实例_Python类与对象实例详解
1.如何派⽣内置不可变类型并修其改实例化⾏为
问题1: 我们想定义⼀种新类型的元组,对于传⼊的可迭代对象,我们只保留其中int类型且值⼤于0的元素,例如:IntTuple([1,-1,'abc',6, ['x','y'],3])==>(1,6,3),要求IntTuple是内置tuple的⼦类,如何实现?
解决⽅案:定义类IntTuple继承tuple,并实现new,修改实例化⾏为
new⽅法接受的参数虽然也是和init⼀样,但init是在类实例创建之后调⽤,⽽ new⽅法正是创建这个类实例的⽅法。new⽅法会返回所构造的对象,init则不会,在使⽤new返回对象的时候会隐式调⽤init函数。new函数必须以cls作为第⼀个参数,⽽init则以self作为其第⼀个参数
class IntTuple(tuple):
def __new__(cls, iterable):
g = (x for x in iterable if isinstance(x,int) and x > 0)
return super(IntTuple, cls).__new__(cls,g)
def __init__(self, iterable):
return super(IntTuple,self).__init__(iterable)
t = IntTuple([1,-1,'abc',6,['x','y'],3])
print t
输出:
(1, 6, 3)
2.如何为创建⼤量实例节省内存
问题2: 某⽹络游戏中,定义了玩家类Player(id,name,status,...),每有⼀个在线玩家,服务器内部则有⼀个Player的实例,当在线⼈数很多时,将产⽣⼤量实例,如何降低这些⼤量实例的内存开销
解决⽅案:定义类的slots属性,它是⽤来声明实例属性名字的列表
class Player(object):
def __init__(self,uid,name,status=0,level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
class Player2(object):
__slots__ = ['uid', 'name', 'status', 'level']
def __init__(self,uid,name,status=0,level=1):
self.uid = uid
self.name = name
self.status = status
self.level = level
p1 = Player('0001',"Jim")
p2 = Player2('0001',"jim")
print dir(p1)
print '\n'
print dir(p2)
print '\n'
print set(dir(p1)) -set(dir(p2))
输出:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'level', 'name',
'status', 'uid']
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'level', 'name', 'status', 'uid']
set(['__dict__', '__weakref__'])
# 可以看到使⽤__slots__属性的类,⽐正常的少了__dict__,即不可以动态绑定属性,但是也减少了内存消耗,因为__dict__使⽤会占⽤内存
3.如何让对象⽀持上下⽂管理
问题3: 实现了⼀个telnet客户端的类TelnetClient,调⽤实例的start()⽅法启动客户端与服务器交互,交互完毕后需要调⽤cleanup⽅法关闭已连接的socket,以及将操作历史记录写⼊⽂件并关闭,能否让TelnetClient的实例⽀持上下⽂管理协议,从⽽替代⼿⼯调⽤cleanup()⽅法
from telnetlib import Telnet
from sys import stdin, stdout
from collections import deque
class TelnetClient(object):
def __init__(self, addr, port=23):
self.addr = addr
self.port = port
< = None
def start(self):
< = Telnet(self.addr, self.port)
self.history = deque()
# user
t = ad_until('login: ')
stdout.write(t)
user = adline()
# password
t = ad_until('Password: ')
if t.startswith(user[::-1]):
t = t[len(user) + 1:]
stdout.write(t)
t = ad_until('$ ')
stdout.write(t)
while True:
uinput = adline()
if not uinput:
break
self.history.append(uinput)
t = ad_until('$ ')
stdout.write(t[len(user) + 1:])
def cleanup(self):
< = None
with open(self.addr + '_', 'w') as f:
f.writelines(self.history)
client = TelnetClient('127.0.0.1')
print '\nstart'
client.start()
print '\ncleanup'
client.cleanup()
执⾏Python⽂件,输⼊⽤户名,密码登录telnet服务器,然后输⼊命令进⾏测试,然后ctrl + D退出,发现此时会⽣成127.0.0.⽂件,⾥⾯记录了操作的历史命令
解决⽅案:
实现上下⽂管理协议,需定义实例的enter,exit⽅法,它们分别在with开始和结束时被调⽤
from telnetlib import Telnet
from sys import stdin, stdout
from collections import deque
class TelnetClient(object):
def __init__(self, addr, port=23):
self.addr = addr
self.port = port
< = None
def start(self):
# user
t = ad_until('login: ')
stdout.write(t)
user = adline()
# password
t = ad_until('Password: ')
if t.startswith(user[::-1]):
t = t[len(user) + 1:]
stdout.write(t)
t = ad_until('$ ')
stdout.write(t)
while True:
uinput = adline()
if not uinput:
break
self.history.append(uinput)
t = ad_until('$ ')
stdout.write(t[len(user) + 1:])
def __enter__(self):
< = Telnet(self.addr, self.port)
self.history = deque()
return self
def __exit__(self, exc_type, exc_val, exc_tb): lose()
< = None
with open(self.addr + '_', 'w') as f: f.writelines(self.history)
# with TelnetClient('127.0.0.1') as client的对象是 __enter__⽅法return返回的对象,当start()⽅法抛出异常时,仍然会执⾏__exit__⾥⾯的⽅法
with TelnetClient('127.0.0.1') as client:
client.start()
4.如何创建可管理的对象属性
问题4:在⾯向对象编程中,我们把⽅法看做对象的接⼝,直接访问对象的属性可能是不安全的,或设计上不够灵活,但是使⽤调⽤⽅法在形式上不如访问属性简洁,能否在形式上是属性访问,但实际上调⽤⽅法?
解决⽅案: 使⽤内置的property函数,Python内置的@property装饰器就是负责把⼀个⽅法变成属性调⽤
from math import pi
class Circle(object):
def __init__(self, radius):
self.radius = radius
def getRadius(self):
return self.radius
def setRadius(self, value):
if not isinstance(value, (int, long, float)):
raise ValueError('wrong type')
self.radius = float(value)
def getArea(self):
return self.radius ** 2 * pi
R = property(getRadius, setRadius)
c = Circle(3.2)
# 得到getRadius⽅法⾥的值
print c.R
writelines()方法将什么写入文件# 使⽤setRadius设置值
c.R = 5.9
print c.R
输出:
3.2
5.9
5.如何让类⽀持⽐较操作
问题5:有时我们希望⾃定义的类,实例间可以使⽤<,<=,>,>=,!=符号进⾏⽐较,我们⾃定义⽐较的⾏为,例如有个矩形的类,我们希望⽐较两个矩形的实例时,⽐较的是它们的⾯积
解决⽅案:⽐较符号运算符重载,需要实现以下⽅法lt和le和gt和eq和ne
使⽤标准库下的functools下的类装饰器total_ording 可以简化此过程
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论