序列的修改、散列和切片

Vector第1版(不可切片版):

 

from array import array
import reprlib
import math


class Vector:

    type_code = 'd'

    def __init__(self,components):

        self._components = array(self.type_code,components)

    def __iter__(self):
        return iter(self._components)


    def __repr__(self):
        components = reprlib.repr(self._components)
        components = components[components.find('['):-1]
        return 'Vector({})'.format(components)

    def __str__(self):

        return str(tuple(self))

    def __bytes__(self):

        return bytes([ord(self.type_code)]) + bytes(self._components)

    def __eq__(self, other):

        return tuple(self) == tuple(other)

    def __abs__(self):

        return math.sqrt(x*x for x in self._components)

    def __bool__(self):

        return bool(abs(self))

    @classmethod
    def frombytes(cls,octets):

        t_code = chr(octets[0])
        comps = array(t_code)
        comps.frombytes(octets[1:])
        return cls(comps)


longlist = [i for i in range(100)]
longVector = Vector(longlist)
print('repr(longVector):',repr(longVector))

v = Vector([3.1,4.2])
print('str(v):',v)
print('repr(v):',repr(v))
b = bytes(v)
w = Vector.frombytes(b)
print('repr(w):',repr(w))
print(v == w)

输出:
repr(longVector): Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])
str(v): (3.1, 4.2)
repr(v): Vector([3.1, 4.2])
repr(w): Vector([3.1, 4.2])
True

 

Vector第2版(不完美切片版):

from array import array
import reprlib
import math


class Vector:

    type_code = 'd'

    def __init__(self,components):

        self._components = array(self.type_code,components)

    def __iter__(self):
        return iter(self._components)


    def __repr__(self):
        components = reprlib.repr(self._components)
        components = components[components.find('['):-1]
        return 'Vector({})'.format(components)

    def __str__(self):

        return str(tuple(self))

    def __bytes__(self):

        return bytes([ord(self.type_code)]) + bytes(self._components)

    def __eq__(self, other):

        return tuple(self) == tuple(other)

    def __abs__(self):

        return math.sqrt(x*x for x in self._components)

    def __bool__(self):

        return bool(abs(self))

    @classmethod
    def frombytes(cls,octets):

        t_code = chr(octets[0])
        comps = array(t_code)
        comps.frombytes(octets[1:])
        return cls(comps)

    # 定义下面两个方法以后,Vector类就支持简单切片
    def __len__(self):
        return len(self._components)

    def __getitem__(self, idx):
        return self._components[idx]


l = [i for i in range(100)]
v = Vector(l)
print('repr(longVector):',repr(v))

# []操作符调用__getitem__
print(v[0],v[-1])

# _components是一个array,所以切片返回array
print(v[1:4])

输出:
repr(longVector): Vector([0.0, 1.0, 2.0, 3.0, 4.0, ...])
0.0 99.0
array('d', [1.0, 2.0, 3.0])

 

切片原理

  - 切片背后与slice对象和indices对象有关

  - 实际调用的是slice(start, stop, stride).indices(len)

    - 给定长度为len的序列,计算起始和结尾的索引,以及步幅。超出边界的索引会被截掉。

 

class MySeq:

    def __getitem__(self, item):
        return item

s = MySeq()
l = [1,2,3,4,5]

# 切片时传递给__getitem__的参数是slice对象
# 这里是slice(1, 4, None)
print(s[1:4])

# slice(1, 4, 2)
print(s[1:4:2])

# 在内置可迭代对象的__getitem__中,还要调用indices方法对start、stop、stride进行处理
# 步幅为正数,start=None自动替换成0
# stop超过len,自动替换成len
# (0, 5, 2)
print(slice(None, 10, 2).indices(5))
# 相应切片返回[1, 3, 5]
print(l[:10:2])


# 步幅=None,自动替换成1
# 步幅为正数,start=-3自动替换成len-3
# stop=None自动替换成len
# (2, 5, 1)
print(slice(-3, None, None).indices(5))
# 相应切片返回[3, 4, 5]
print(l[-3::])


# 步幅为负数,start=-3自动替换成len-3
# stop=None自动替换成-1
# (2, -1, -1)
print(slice(-3, None, -1).indices(5))
# 相应切片返回[3, 2, 1]
print(l[-3::-1])


# 从2开始,倒退到3,切片为空
# (2, 3, -1)
print(slice(-3, 3, -1).indices(5))
# 相应切片返回[]
print(l[-3:3:-1])

 

Vector第3版(完美切片版):

 

from array import array
import reprlib
import math
import numbers

class Vector:

    type_code = 'd'

    def __init__(self,components):

        self._components = array(self.type_code,components)

    def __iter__(self):
        return iter(self._components)


    def __repr__(self):
        components = reprlib.repr(self._components)
        components = components[components.find('['):-1]
        return 'Vector({})'.format(components)

    def __str__(self):

        return str(tuple(self))

    def __bytes__(self):

        return bytes([ord(self.type_code)]) + bytes(self._components)

    def __eq__(self, other):

        return tuple(self) == tuple(other)

    def __abs__(self):

        return math.sqrt(x*x for x in self._components)

    def __bool__(self):

        return bool(abs(self))

    @classmethod
    def frombytes(cls,octets):

        t_code = chr(octets[0])
        comps = array(t_code)
        comps.frombytes(octets[1:])
        return cls(comps)

    # 定义下面两个方法以后,Vector类就支持简单切片
    def __len__(self):
        return len(self._components)

    def __getitem__(self, idx):

        cls = type(self)

        if isinstance(idx,slice):
            # 把slice对象传递给_components的__getitem__函数
            return cls(self._components[idx])
        elif isinstance(idx,numbers.Integral):
            # 直接返回相应元素
            return self._components[idx]
        else:
            msg = '{0} indices must be integers'
            raise TypeError(msg.format(cls.__name__))


l = [i for i in range(100)]
v = Vector(l)
print('repr(longVector):',repr(v))

# 传入整数,__getitem__返回相应元素
print(v[0],v[-1])

# 经过改造后,切片返回Vector对象
print(repr(v[1:4]))

 

Vector第4版(带hash版):

from array import array
import reprlib
import math
import numbers
import functools
import operator

class Vector:

    type_code = 'd'

    def __init__(self,components):

        self._components = array(self.type_code,components)

    def __iter__(self):
        return iter(self._components)


    def __repr__(self):
        components = reprlib.repr(self._components)
        components = components[components.find('['):-1]
        return 'Vector({})'.format(components)

    def __str__(self):

        return str(tuple(self))

    def __bytes__(self):

        return bytes([ord(self.type_code)]) + bytes(self._components)

    def __eq__(self, other):

        # zip生成一个由元组构成的生成器,在Vector由大数据量的可迭代对象构成时,效率比较高
        # all函数在每一个元素都为True时返回True
        return len(self)==len(other) and all(a==b for a,b in zip(self,other))

    def __hash__(self):

        # reduce接受三个参数,第一个参数是一个可接受两个参数的函数
        # 第二个参数是一个可迭代对象,第三个参数是初始值,如果可迭代对象为空,返回这个初始值
        hashes = (hash(i) for i in self)
        return functools.reduce(operator.xor, hashes, 0)

    def __abs__(self):

        return math.sqrt(x*x for x in self._components)

    def __bool__(self):

        return bool(abs(self))

    @classmethod
    def frombytes(cls,octets):

        t_code = chr(octets[0])
        comps = array(t_code)
        comps.frombytes(octets[1:])
        return cls(comps)

    # 定义下面两个方法以后,Vector类就支持简单切片
    def __len__(self):
        return len(self._components)

    def __getitem__(self, idx):

        cls = type(self)

        if isinstance(idx,slice):
            # 把slice对象传递给_components的__getitem__函数
            return cls(self._components[idx])
        elif isinstance(idx,numbers.Integral):
            # 直接返回相应元素
            return self._components[idx]
        else:
            msg = '{0} indices must be integers'
            raise TypeError(msg.format(cls.__name__))

    shortcut = 'xyzt'

    # 动态存取属性
    def __getattr__(self, item):
        cls = type(self)
        if len(item) == 1:
            pos = cls.shortcut.find(item)
            if 0 <= pos < len(self._components):
                return self._components[pos]
            else:
                raise AttributeError('{0} has no attribute {1}'.format(cls,item))


l = [3.1, 4.2]
v = Vector(l)
print('repr(v):',repr(v))

print('v.x:',v.x)

print('hash(v):',hash(v))

输出:

repr(v): Vector([3.1, 4.2])
v.x: 3.1
hash(v): 384307168202284039

 

posted @ 2019-03-24 15:52  StackNeverOverFlow  阅读(219)  评论(0编辑  收藏  举报