实际编程和面试都会遇到的典型问题。
如何派生内置不可变类型并修改其实例化行为
#我们想自定义一种新类型元组,对于传入的可迭代对象,我们只想保留其中int类型>0的元素 新类型是内置tuple的子类
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):
super(IntTuple,self).__init__()
it = IntTuple([1,-2,3,'x'])
it
如何为创建大量实例节省内存
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('001','uu')
p2 = Player2('001','uu')
set(dir(p1)) - set(dir(p2))
# p1比p2多了{'__dict__', '__weakref__'}
# '__dict__'可以动态绑定
p1.x = 123
del p1.__dict__['x']
import sys
# 占用了320内存
sys.getsizeof(p1.__dict__)
# p2事先定义__slots__ 声明了实例属性名字的列表
# p2就无法动态绑定 从而节省了内存
# p2.x = 123
如何创建可管理的对象属性
from math import pi
class Cricle(object):
def __init__(self,radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self,value):
if not isinstance(value,(int,float)):
raise ValueError('wrong type')
self._radius = value
def getArea(self):
return self._radius ** 2 * pi
c = Cricle(5)
c.radius
如何让类支持比较操作
from math import pi
from functools import total_ordering
@total_ordering
class Cricle(object):
def __init__(self,radius):
self._radius = radius
def area(self):
return self._radius ** 2 * pi
def __lt__(self,obj):
return self.area() < obj.area()
def __eq__(self,obj):
return self.area() == obj.area()
c1 = Cricle(3)
c2 = Cricle(5.0)
c1 > c2
如何使用描述符对实例属性做类型检查
# 描述符 __get__ __set__ __del__
class Attr(object):
def __init__(self,name,type_):
self.name = name
self.type_ = type_
def __get__(self,instance,cls):
return instance.__dict__[self.name]
def __set__(self,instance,value):
if not isinstance(value,self.type_):
raise TypeError('expected an %s'%self.type_)
instance.__dict__[self.name] = value
def __delete__(self,instance):
del instance.__dict__[self.name]
class Person(object):
name = Attr('name',str)
age = Attr('age',int)
height = Attr('height',float)
p = Person()
p.name = '123'
p.age = 123
p.height = 1.0
如何通过实例方法名字的字符串调用方法
class Circle(object):
def __init__(self,r):
self.r = r
def area(self):
return self.r ** 2 * 3.14
class Rectangle(object):
def __init__(self,w,h):
self.w = w
self.h = h
def get_area(self):
return self.w * self.h
class Triangle(object):
def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def getArea(self):
#海伦公式:√[p(p-a)(p-b)(p-c) ]其中p=1/2(a+b+c)
p = (self.a + self.b + self.c) / 2
return (p * (p - self.a) * (p - self.b) * (p - self.c)) ** 0.5
def getArea(shape):
for name in ('area','get_area','getArea'):
f = getattr(shape,name,None)
if f:
return f()
shape1 = Circle(3)
shape2 = Rectangle(5,6)
shape3 = Triangle(3,4,5)
shapes = [shape1,shape2,shape3]
print(list(map(getArea,shapes)))