<jupyter_start><jupyter_text>兼容vector2d<jupyter_code>import math
from array import array
import reprlib
import numbers

class myVector_v1:

    typecode = 'd'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        return self._componets[index]

    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    def __eq__(self, other):
        return tuple(self) == tuple(other)

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)
# 接受可迭代的对象
v1 = myVector_v1((1,2,3,4,5,6))
# 有限长度显示
v1
# 实现打印
print(v1)
# 实现abs
abs(v1)
# 实现==
v2 = myVector_v1((1,2,3,4,5,6,7))
v1 == v2
v3 = v1
v1 == v3
# 实现bool

bool(v1)
# 实现bytes
bytes(v1)<jupyter_output><empty_output><jupyter_text>错误案例```python@classmethoddef frombytes(cls, octets):    typecode = octets[0]    octets = octets[1:]    mev = memoryview(octets).cast(str(typecode))    return cls(mev)``` 实现frombytes类方法```pythonoctets = bytes(v1)v4 = myVector_v1.frombytes(octets)v4``` 返回```---------------------------------------------------------------------------ValueError                                Traceback (most recent call last) in       1  实现frombytes类方法      2 octets = bytes(v1)----> 3 v4 = myVector_v1.frombytes(octets)      4 v4 in frombytes(cls, octets)     41         typecode = octets[0]     42         octets = octets[1:]---> 43         mev = memoryview(octets).cast(str(typecode))     44         return cls(mev)ValueError: memoryview: destination format must be a native single character format prefixed with an optional '@'```<jupyter_code># 实现frombytes类方法
octets = bytes(v1)
v4 = myVector_v1.frombytes(octets)
v4
type(v1[1:4])<jupyter_output><empty_output><jupyter_text>支持切片  理解切片<jupyter_code>class mySeq:
    def __getitem__(self, index):
        return index
s = mySeq()

# 一个确定的值
s[1]
# 范围连续取值
s[1:2]
# 范围设置步幅取值
s[1:5:2]
# 自动不全内容
s[:3:]
# 支持多组区间或确定值取值
s[1:5,9]
# 支持多组区间或确定值取值
s[1:5,5:9]
dir(slice)
help(slice.indices)
v1[2]<jupyter_output><empty_output><jupyter_text>简单返回内部数据，并不能返回切片，或者说返回的切片是array而不是自定义的类型如果```pythondef __getitem__(self, index):    return self._componets[index]```运行```v1[:]``` 返回array('d', \[1.0, 2.0, 3.0, 4.0, 5.0, 6.0\])<jupyter_code>import math
from array import array
import reprlib
import numbers

class myVector_v2:

    typecode = 'd'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            return cls(self._componets[index])
        elif isinstance(index, numbers.Integral):
            return self._componets[index]
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    def __eq__(self, other):
        return tuple(self) == tuple(other)

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)
v1 = myVector_v2([4,5,6,7,8,9,0,1])
v2 = v1[3:6]
type(v2)<jupyter_output><empty_output><jupyter_text>动态获取属性，使用v.x、v.y这样的方式获得分量  以某个字母作为分量获得方法可以使用\_\_getattr\_\_内置方法> 注意，不要实现\_\_getattribute\_\_方法，这不是同一个方法，get_attr方法的调用优先等级低。> 属性查找失败后，解释器会调用 __getattr__ 方法。简单来说，对 my_obj.x 表达式，Python 会检查 my_obj 实例有没有名为 x 的属性; 如果没有，到类(my_obj.__class__)中查找;如果还没有，顺着 继承树继续查找。4 如果依旧找不到，调用 my_obj 所属类中定义的 __getattr__ 方法，传入 self 和属性名称的字符串形式(如 'x')。<jupyter_code>import math
from array import array
import reprlib
import numbers

class myVector_v3:

    typecode = 'd'
    shortcut = 'xyzw'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            return cls(self._componets[index])
        elif isinstance(index, numbers.Integral):
            return self._componets[index]
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __getattr__(self, attr):
        cls = type(self)
        if len(attr) == 1:
            index = cls.shortcut.find(attr)
            if 0<=index<len(self._componets):
                return self._componets[index]
        else:
            msg = '{.__name__!r} has no attribute : {!r}'
            raise AttributeError(msg.format(cls, attr))
    
    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    def __eq__(self, other):
        return tuple(self) == tuple(other)

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)

    
myv3 = myVector_v3(range(10))
myv3.y
myv3
# 但是会有一个访问优先级的问题：
myv3.y = 10
myv3.y<jupyter_output><empty_output><jupyter_text>由上面的例子可以看出，当只实现了\_\_getAttr\_\_函数，是不行的。当我们给myv3.y赋值时，其实是给实例添加了一个属性。其实此时是用到了\_\_setattr\_\_函数，因此我们还需要实现该函数，让xyzw成为只读属性， 同时，如果像使用a\[1\]=3方式赋值，需要实现\_\_setitem\_\_方法，这个下个实例详细解释。<jupyter_code>import math
from array import array
import reprlib
import numbers

class myVector_v3_set:

    typecode = 'd'
    shortcut = 'xyzw'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            return cls(self._componets[index])
        elif isinstance(index, numbers.Integral):
            return self._componets[index]
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __getattr__(self, attr):
        cls = type(self)
        if len(attr) == 1:
            index = cls.shortcut.find(attr)
            if 0<=index<len(self._componets):
                return self._componets[index]
        else:
            msg = '{.__name__!r} has no attribute : {!r}'
            raise AttributeError(msg.format(cls, attr))

    # 实现属性只读模式
    def __setattr__(self, attr, value):
        cls = type(self)
        if len(attr) == 1 :
            if attr in cls.shortcut:
                msg = 'read only attribute : {attr_name}'
            elif attr.islower():
                msg = '{cls_name} can not set attribute name in a to z'
            else:
                msg = ''
            if msg:
                out = msg.format(attr_name = attr, cls_name = cls)
                raise AttributeError(out)
        
        super().__setattr__(attr, value)
    
    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    def __eq__(self, other):
        return tuple(self) == tuple(other)

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)

    
myv3_1 = myVector_v3_set(range(10))
myv3_1.w
myv3_1.w = 10<jupyter_output><empty_output><jupyter_text>我们知道，在类中声明 \_\_slots\_\_ 属性可以防止设置新实 例属性;因此，你可能想使用这个功能，而不像这里所做的，实现 \_\_setattr\_\_ 方法。可是，正如 9.8.1 节所指出的，不建议只为了避免创建实例属性而使用 \_\_slots\_\_ 属性。\_\_slots\_\_ 属性 只应该用于节省内存，而且仅当内存严重不足时才应该这么做。  10.6 散列和快速等值测试  散列实现- 用到了 functools 中的reduce函数，他可以利用第一个参数（有两个参数的函数），将第二个参数的数组进行聚合成一个值。- 避免在reduce的函数中使用匿名函数，所以可以利用operator类，里面包含全部的中辍操作符的函数形式。- reduce第三个参数是初始化参数，防止传入空数组而报错 实现等值测试- 用到了zip函数，但是其有个问题，就是当两个数组不等长的时候，其不会报错。- 因此在第一个判断中，确认数组长度是否一样。- 使用all函数，可以类似 and 的逻辑判断<jupyter_code>import math
from array import array
import reprlib
import numbers
import operator
import functools

class myVector_v4:

    typecode = 'd'
    shortcut = 'xyzw'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            return cls(self._componets[index])
        elif isinstance(index, numbers.Integral):
            return self._componets[index]
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __getattr__(self, attr):
        cls = type(self)
        if len(attr) == 1:
            index = cls.shortcut.find(attr)
            if 0<=index<len(self._componets):
                return self._componets[index]
        else:
            msg = '{.__name__!r} has no attribute : {!r}'
            raise AttributeError(msg.format(cls, attr))

    # 实现属性只读模式
    def __setattr__(self, attr, value):
        cls = type(self)
        if len(attr) == 1 :
            if attr in cls.shortcut:
                msg = 'read only attribute : {attr_name}'
            elif attr.islower():
                msg = '{cls_name} can not set attribute name in a to z'
            else:
                msg = ''
            if msg:
                out = msg.format(attr_name = attr, cls_name = cls)
                raise AttributeError(out)
        
        super().__setattr__(attr, value)
    
    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    # 采用更加准确和高效的方法：
    def __eq__(self, other):
        # return tuple(self) == tuple(other)
        return len(self) == len(other) and all( a == b for a,b in zip(self, other))

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    # 实现散列，需要实现hash函数
    def __hash__(self):
        hashes = map(hash, self._componets)
        return functools.reduce(operator.xor,hashes，0)

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)

    
v4 = myVector_v4([3.1,4.2])
hash(v4)
v4
hash(myv3_1)
v1 = myVector_v4([3,5])
v2 = myVector_v4([3.0,5.0])
v3 = myVector_v4([3.1,5.1])

v1 == v2, v1 == v3<jupyter_output><empty_output><jupyter_text>格式化<jupyter_code>import math
from array import array
import reprlib
import numbers
import operator
import functools
import math
import itertools

class myVector_v5:

    typecode = 'd'
    shortcut = 'xyzw'

    def __init__(self, componets):
        self._componets = array(self.typecode, componets)

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

    def __len__(self):
        return len(self._componets)

    def __getitem__(self, index):
        cls = type(self)
        if isinstance(index, slice):
            return cls(self._componets[index])
        elif isinstance(index, numbers.Integral):
            return self._componets[index]
        else:
            msg = '{cls.__name__} indices must be integers'
            raise TypeError(msg.format(cls=cls))

    def __getattr__(self, attr):
        cls = type(self)
        if len(attr) == 1:
            index = cls.shortcut.find(attr)
            if 0<=index<len(self._componets):
                return self._componets[index]
        else:
            msg = '{.__name__!r} has no attribute : {!r}'
            raise AttributeError(msg.format(cls, attr))

    # 实现属性只读模式
    def __setattr__(self, attr, value):
        cls = type(self)
        if len(attr) == 1 :
            if attr in cls.shortcut:
                msg = 'read only attribute : {attr_name}'
            elif attr.islower():
                msg = '{cls_name} can not set attribute name in a to z'
            else:
                msg = ''
            if msg:
                out = msg.format(attr_name = attr, cls_name = cls)
                raise AttributeError(out)
        
        super().__setattr__(attr, value)
    
    def __repr__(self):
        componets = reprlib.repr(self._componets)
        componets = componets[componets.find('['):-1]
        return "myVector({})".format(componets)
    
    def __str__(self):
        return str(tuple(self))

    # 采用更加准确和高效的方法：
    def __eq__(self, other):
        # return tuple(self) == tuple(other)
        return len(self) == len(other) and all( a == b for a,b in zip(self, other))

    def __abs__(self):
        return math.sqrt(sum((x*x for x in self._componets)))

    def __bool__(self):
        return bool(abs(self))

    def __bytes__(self):
        return (bytes([ord(self.typecode)])+
                bytes(self._componets))

    # 实现散列，需要实现hash函数
    def __hash__(self):
        hashes = map(hash, self._componets)
        return functools.reduce(operator.xor,hashes,0)

    def angle(self, n):
        r = math.sqrt(sum( x * x for x in self[n:]))
        a = math.atan2(r, self[n-1])
        if n == len(self)-1 and self[-1]<0:
            return math.pi * 2 - a
        else:
            return a

    def angles(self):
        return (self.angle(n) for n in range(1, len(self)))

    def __format__(self, fmt_spec=''):
        if fmt_spec.endswith('h'): # 超球面坐标
            fmt_spec = fmt_spec[:-1]
            coords = itertools.chain([abs(self)], self.angles())
            outer_fmt = '<{}>'
        else:
            coords = self
            outer_fmt = '({})'
        components = (format(c, fmt_spec) for c in coords)
        return outer_fmt.format(', '.join(components))

    @classmethod
    def frombytes(cls, octets):
        typecode = chr(octets[0])
        octets = octets[1:]
        mev = memoryview(octets).cast(typecode)
        return cls(mev)


v11 = myVector_v5(range(10))

format(v11, '.05fh')<jupyter_output><empty_output><jupyter_text>总结理解鸭子模式。只要看山去像即可。 实现序列化实现\_\_getitem\_\_和\_\_len\_\_两个内置方法即可支持序列化 实现切片利用slice函数实现复杂切片 只读属性设置\_\_getattr\_\_方法的同时也要记得设置\_\_setattr\_\_方法，在后者里进行添加只读权限。\_\_slot\_\_函数应作为内存优化，而非控制属性权限的方法 散列实现\_\_hash\_\_可以是类支持散列特性使用了reduce和operator的中辍函数 等值判断目前是一个不准确的等值判断利用了 zip和len 格式化自定义了一种格式——超球坐标<jupyter_code># 如何改进该方法呢？

import functools
my_list = [[1, 2, 3], [40, 50, 60], [9, 8, 7]]
functools.reduce(lambda a,b: a+b, [sub[1] for sub in my_list])
# 简化掉列表推导式

import functools
my_list = [[1, 2, 3], [40, 50, 60], [9, 8, 7]]
functools.reduce(lambda a,b: a+b[1], my_list, 0)
# 简化掉匿名函数

import functools
import operator
my_list = [[1, 2, 3], [40, 50, 60], [9, 8, 7]]
functools.reduce(operator.add, [sub[1] for sub in my_list], 0)
# 使用numpy

import numpy as np
my_list = [[1, 2, 3], [40, 50, 60], [9, 8, 7]]
my_array = np.array(my_list)
np.sum(my_array[:,1])
# 为什么不能这样？

total = 0
for sub in my_list:
    total += sub[1]

total<jupyter_output><empty_output><jupyter_text>为什么不能这样？ 如果你想计算列表中各个元素的和，写出的代码应该看起来像 是在“计算元素之和”，而不是“迭代元素，维护一个变量 t，再 执行一系列求和操作”。如果不能站在一定高度上表明意图， 让语言去关注低层操作，那么要高级语言干嘛?<jupyter_code># 之后，python官方内置了sum函数，可见python的艺术就是要简洁

my_list = [[1, 2, 3], [40, 50, 60], [9, 8, 7]]

sum(sub[1] for sub in my_list)


# 这利用了sum内置函数，并且支持了生成器表达式<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13109931941400393, 'fraction_numerical': 0.01661091244664898, 'mean_word_length': 2.6357726986789682, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '10', 'dir': 'jupyter-structured-clean-dedup', 'id': '396607', 'license': 'MIT', 'n_tokens_mistral': 6935, 'n_tokens_neox': 6951, 'n_words': 1251, 'path': 'FluentPython/Chapter10_seq_hacking.ipynb', 'repo_name': 'Liuzkai/PythonScript', 'size': '17338'}