版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qd_ltf/article/details/79703820
一、如何派生内置不可变类型并修改实例化行为
# 将列表变成元组,且只保留大于0的整数
class IntTuple(tuple):
def __new__(cls, iterable):
g = (x for x in iterable if isinstance(x, int) and x > 0) # isinstance()判断x是不是int整数类,
return super(IntTuple, cls).__new__(cls, g)
# def __init__(self, iterable): # 默认调用父类的__init__()
# super(IntTuple, self).__init__(iterable)
print IntTuple([1, 2, 6, 'abc', -1, {'a': 5}, 7]) # 结果:(1, 2, 6, 7)
二、如何为创建大量实例节省内存
class player1(object):
def __init__(self, uid, name):
self.uid = uid
self.name = name
class player2(object):
__slots__ = ['uid', 'name'] # 节约内存
def __init__(self, uid, name):
self.uid = uid
self.name = name
p1 = player1('001', 'jim')
p2 = player2('001', 'jim')
p1.x = 100 # p1可以动态添加或删除属性,而p2不能
p1.y = 0
p1.__delattr__('x') # 删除属性
print set(dir(p1)) - set(dir(p2)) # 结果 set(['y', '__dict__', '__weakref__']) '__dict__'占用较大内存
import sys
print sys.getsizeof(p1.__dict__) # 查看占用内存
三、如何让对象支持上下文管理
from telnetlib import telnetlib
from sys import stdin, stdout
from collecttions import deque
class TelnetClient(object):
def __init__(self, addr, port=23)
self.addr = addr
self.port = port
self.tn = None
def start(self):
# user
t = self.tn.read_until('login:')
stdout.write(t)
user = stdin.readline()
self.tn.write(user)
# password
t = self.tn.read_until('Password:')
if t.startswith(user[:-1]): t = t[len(user) + 1:]
stdout.write(t)
self.tn.write(stdin.readline())
t = self.tn.read.until('$ ')
stdout.write(t)
while True:
uinput = stdin.readline()
if not uinput:
break
self.history.append(uinput)
self.tn.write(uinput)
t = self.tn.read_until('$ ')
stdout.write(t[len(uinput) + 1:])
def __enter__(self):
self.tn = Telnet(self.addr, self.port)
self.history = deque()
return self
pass
def __exit__(self, exc_type, exc_val, exc_tb):
self.cn.close()
self.cn = None
with open(self.addr + '_history.txt', 'w') as f:
f.writelines(self.history)
with TelnetClient('127.0.0.1') as client:
client.start()
四、如何创建可管理的对象属性
class Circle(object):
def __init__(self,radius):
self.radius = radius
def getRadius(self):
return round(self.radius,2) # 保留两位小数
def setRadius(self,value):
if isinstance(value,(int,long,float)): # 判断value是否是数字类
self.radius=float(value)
else:
raise ValueError('wrong type')
R = property(fget=getRadius,fset=setRadius,) # property()为类创建可管理属性
c=Circle(3.5)
print c.radius
c.radius='abc' # 显然赋值不符合要求,但程序未能检测出
print c.radius
c.R=53.3473934 # 可以取值,也可以赋值
print c.R # 可以管理,只保留两位小数 # 53.35
# c.R='abc' # 程序就会报错
五、如何让类支持比较操作
# -*- coding: utf-8 -*-
from functools import total_ordering
from abc import ABCMeta, abstractmethod
@total_ordering # 添加这个装饰器后,只需要重载__ltf__,__eq__ 两个比较函数,其它的比较函数装饰器会根据这两个判断生成。
class Shape(object):
@abstractmethod
def area(self): # 定义,需要子类重载
pass
def __lt__(self, other):
print 'in __lt__'
if not isinstance(other, Shape): # 判断比较的类是不是Shape的实例
raise TypeError('other is not Shape')
return self.area() < other.area()
def __eq__(self, other):
print 'in __eq__'
if not isinstance(other, Shape):
raise TypeError('other is not Shape')
return self.area() == other.area()
class Rect(Shape):
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return self.r ** 2 * 3.14 # **表示乘方
r1 = Rect(6, 2)
r2 = Rect(2, 2)
c = Circle(1)
print c <= r2 # 要判断 r1<r2 实际上就是调用r1.__lt__(r2)
六、如何使用描述符对实例属性做类型检查
class Attr(object):
def __init__(self, name, type_):
self.name = name
self.type_ = type_
def __get__(self, instance, cls): # 取值
print 'in __get__', self, instance, cls
return instance.__dict__[self.name]
def __set__(self, instance, value): # 赋值,可以判断属性,以保证赋值不出错
print 'in __set__', self, instance, value
if not isinstance(value, self.type_):
raise TypeError('is not format ')
instance.__dict__[self.name] = value
def __del__(self, instance): # 重载del方法
print 'in __del__'
del instance.__dict__[self.name]
class Person(object):
name = Attr('name', str) # 指定类属性的类型
age = Attr('name', int)
height = Attr('height', float)
p = Person()
p.name = 'litaifa'
print p.name
p.name = 12 # 此处会报错
七、如何在环状数据结构中管理内存
import sys,weakref
class Data(object):
def __init__(self,value,owner):
self.value=value
self.owner=weakref.ref(owner) # 弱引用,不会增加引用计数,
# self.owner=owner
def __str__(self):
return "%s's data,value is %s" % (self.owner(),self.value) # 需要象函数一样调用owner()
def __del__(self):
print 'in Data.__del__ %s ' % (self.value)
class Node(object):
def __init__(self,value):
self.data=Data(value,self) # 引用Data类
def __del__(self):
print 'in Node.__del__ '
node=Node(100)
print node.data
print sys.getrefcount(node)-1 # 返回node的引用计数
del node # 只有当上面的引用计数为零时,才会调用析构函数__del__(),由于弱引用不增加引用计算,所以del后,会调用析构函数
raw_input("wait...")
# 结果:
# <__main__.Node object at 0x0000000003204668>'s data,value is 100
# 2
# in Node.__del__
# in Data.__del__ 100
# wait...
八、如何通过实例方法名字的字符串调用方法
from operator import methodcaller
class Rect(object):
def __init__(self, w, h):
self.w = w
self.h = h
def area(self):
return self.w * self.h
class Circle(object):
def __init__(self, r):
self.r = r
def get_area(self):
return self.r ** 2 * 3.14
def getArea(shape):
for name in ['area', 'get_area']:
f = getattr(shape, name, None)
if f:
# 方法一:
return f()
# 方法二:
return methodcaller(name)(shape) # 相当于shape.name()
shapes = [Rect(2, 3), Circle(1)]
print map(getArea, shapes) # map 对shapes的每个元素应用getArea(),然后返回一个新的列表