Python高效编程(五)

174 阅读2分钟

实际编程和面试都会遇到的典型问题。

图片来源于网络

如何派生内置不可变类型并修改其实例化行为

#我们想自定义一种新类型元组,对于传入的可迭代对象,我们只想保留其中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)))