『流畅的Python』第9章_符合Python风格的对象

Python风格对象

以一个二元素向量对象为例

import math
from array import array

class Vector2d:
    typecode = ‘d‘

    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)

    def __iter__(self):
        # 使得Vector2d变成可迭代对象
        # __iter__方法的实现使得本类可以被转化为tuple在内的其他可迭代类
        return (i for i in (self.x, self.y))

    def __repr__(self):
        class_name = type(self).__name__  # type(self): <class ‘__main__.Vector2d‘>
        return ‘{}({!r},{!r})‘.format(class_name, *self)

    def __str__(self):
        return str(tuple(self))

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

    def __abs__(self):
        return math.hypot(self.x, self.y)

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

    def __bytes__(self):
        """将Vector2d对象处理为二进制序列,格式我们自定"""
        # d:double类型数组
        return (bytes([ord(self.typecode)]) +
                bytes(array(self.typecode, self)))

    # —————备用析构方法——————
    @classmethod  # 类方法,cls表示类本身
    def frombytes(cls, octets):
        """对应于上面的方法,这里创建一个新的析构函数,使用特定的二进制序列构造Vector2d类实例"""
        typecode = chr(octets[0])
        memv = memoryview(octets[1:]).cast(typecode)
        return cls(*memv)  # 类名(参数),可见,类方法常用作备用析构

    # —格式化输出—
    def angle(self):
        # math.atan(scope)输入为tan值
        # math.atan2(y, x)输入为对应向量坐标(起点为原点)
        return math.atan2(self.y, self.x)

    def __format__(self, fmt_spec=‘‘):
        """格式化输出,如果格式末尾为p则输出极坐标,
        输入其他格式为数字型格式,一个输入格式指定到两个数上,如:.3ep"""
        if fmt_spec.endswith(‘p‘):
            fmt_spec = fmt_spec[:-1]
            coords = (abs(self), self.angle())
            out_fmt = ‘<{}, {}>‘
        else:
            coords = self
            out_fmt = ‘({}, {})‘
        components = (format(c, fmt_spec) for c in coords)
        return out_fmt.format(*components)

此时这个对象支持大部分python操作,

if __name__ == ‘__main__‘:
    b = bytes(Vector2d(3, 4))
    print(Vector2d.frombytes(b))

    print(format(Vector2d(1, 1), ‘.5fp‘))

(3.0, 4.0)
<1.41421, 0.78540>

但是一个重要的方法还是没能实现,__hash__,这关乎到对象是否可以被存入字典进行高速读取的属性,实际上可以hash对象需要三个条件:

  1. 需要__hash__方法
  2. 需要__eq__方法(已经实现)
  3. 需要对象不可变  # 实例的散列值关乎查找等使用方式,绝对不可以变化

也就是我们指定v.x=1(v为class实例)会报错才行,这需要一些其他操作:

class Vector2d:
    typecode = ‘d‘

    def __init__(self, x, y):
        self.__x = float(x)
        self.__y = float(y)

    @property
    def x(self):
        return self.__x

    @property
    def y(self):
        return self.__y

    def __hash__(self):
        return hash(self.x) ^ hash(self.y)  

其他方法不需要修改,

v1 = Vector2d(3, 4)

v2 = Vector2d(3.1, 4.2)

print(hash(v1), hash(v2))

# 7 384307168202284039

类方法和静态方法

# —对比类方法和静态方法—
class Demo:
    @classmethod
    def klassmeth(*args):
        return args

    @ staticmethod
    def statmeth(*args):
        return args

    def normal(*args):
        return args

和实例方法不同,类方法第一个参数永远是类本身,所以常用于备用析构,静态方法没有默认的首位参数,测试如下:

print(Demo.klassmeth("hello"))
print(Demo.statmeth("hello"))
demo = Demo()
print(demo.normal("hello"))

# (<class ‘__main__.Demo‘>, ‘hello‘)
# (‘hello‘,)
# (<__main__.Demo object at 0x000000000289F978>, ‘hello‘)

原文地址:https://www.cnblogs.com/hellcat/p/9220598.html

时间: 2024-10-09 17:30:39

『流畅的Python』第9章_符合Python风格的对象的相关文章

『流畅的Python』第9章_对象

一.Python风格 以一个二元素向量对象为例 import math from array import array class Vector2d: typecode = 'd' def __init__(self, x, y): self.x = float(x) self.y = float(y) def __iter__(self): # 使得Vector2d变成可迭代对象 # __iter__方法的实现使得本类可以被转化为tuple在内的其他可迭代类 return (i for i i

进击的Python【第五章】:Python的高级应用(二)常用模块

Python的高级应用(二)常用模块学习 本章学习要点: Python模块的定义 time &datetime模块 random模块 os模块 sys模块 shutil模块 ConfigParser模块 shelve模块 xml处理 re正则表达式 一.Python模块的定义 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt这个函数,必须用语句"#include<math.h>"引入math.h这个头文件,否则是无法正常进行调用的.那么在Python中,如

进击的Python【第七章】:Python的高级应用(四)面向对象编程进阶

Python的高级应用(三)面向对象编程进阶 本章学习要点: 面向对象高级语法部分 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 一.面向对象高级语法部分 静态方法 要在类中使用静态方法,需在类成员函数前面加上@staticmethod标记符,以表示下面的成员函数是静态函数.使用静态方法的好处是,不需要定义实例即可使用这个方法.另外,多个实例共享此静态方法. 类方法 类方法与普通的成员函数和静态函数有不同之处,在接触的语言中好像也没见过这种语义,看它的定义: 

进击的Python【第六章】:Python的高级应用(三)面向对象编程

Python的高级应用(三)面向对象编程 本章学习要点: 面向对象编程介绍 面向对象与面向过程编程的区别 为什么要用面向对象编程思想 面向对象的相关概念 一.面向对象编程介绍 面向对象程序设计(英语:Object-oriented programming,缩写:OOP)是一种程序设计范型,同时也是一种程序开发的方法.对象指的是类的实例. 已经被证实的是,面向对象程序设计推广了程序的灵活性和可维护性,并且在大型项目设计中广为应用. 此外,支持者声称面向对象程序设计要比以往的做法更加便于学习,因为它

『Python』MachineLearning机器学习入门_极小的机器学习应用

一个小知识: 有意思的是,scipy囊括了numpy的命名空间,也就是说所有np.func都可以通过sp.func等价调用. 简介: 本部分对一个互联网公司的流量进行拟合处理,学习最基本的机器学习应用. 导入包&路径设置: import os import scipy as sp import matplotlib.pyplot as plt data_dir = os.path.join( os.path.dirname(os.path.realpath(__file__)), "..

『python』科学计算专项_科学绘图库matplotlib学习之绘制动画(待续)

示例代码 简单调用绘图 from matplotlib import pyplot as plt import matplotlib.animation as animation import numpy as np def update_point(num): fig_points.set_data(data[:, 0:num]) return fig_points, fig1 = plt.figure() num_point = 50 data = np.random.rand(2, num

『python』科学计算专项_科学绘图库matplotlib学习

思想:万物皆对象 作业 第一题: import numpy as np import matplotlib.pyplot as plt x = [1, 2, 3, 1] y = [1, 3, 0, 1] def plot_picture(x, y): plt.plot(x, y, color='r', linewidth='2', linestyle='--', marker='D', label='one') plt.xticks(list(range(-5,5,1))) plt.yticks

『python』科学计算专项_科学绘图库matplotlib学习(下)

基本的读取csv文件并绘制饼图 由于之前没有过实际处理的经验,所以这个程序还是值得一看,涉及了处理表格数据的基本方法: import matplotlib.pyplot as plt import pandas as pd # csv读取文件 data = pd.read_csv('OutOrder.csv',encoding='gb2312') # 每一列都兼容numpy的方法 a = data['方式'].values # 获取本列的内容的各种可能 typename = [] for i i

『Python』MachineLearning机器学习入门_效率对比

效率对比: 老生常谈了,不过这次用了个新的模块, 运行时间测试模块timeti: 1 import timeit 2 3 normal = timeit.timeit('sum(x*x for x in range(1000))', number=10000) 4 native_np = timeit.timeit('sum(na*na)', # 重复部分 5 setup="import numpy as np; na = np.arange(1000)", # setup只运行一次