一、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')

三、私有属性和受保护属性

两个前导下划线"__",一个或者没有后置下划线的实例属性(self.属性名)为私有变量,会被存入__dict__中,且名称被改写为"_类名__属性名",主要目的是防止类被继承以后,子类实例的继承属性(未在子类中显式的声明)被错误的改写。

注意,__dict__不仅仅存储私有变量,实例属性均存放在__dict__中(默认情况下)。

四、__slots__类属性节约存储空间

class Vector2d:

    __slots__ = ('__x', '__y')

    typecode = 'd'

类属性__slots__为一个存储字符串的可迭代对象,其中的各个字符串是不同的实例属性名,使用tuple是作者推荐的方式,因为可以保证信息不被改动。使用它可以有效节约存储空间,尤其是需要创建大量实例的时候(运行速度往往也更快)。

  1. 继承会自动忽略__slot__属性,所以子类需要显式的定义它
  2. 定义了__slots__后,用户不可以自行添加其他实例属性,但是如果把__dict__存储在__slots__中,就可以添加了,不过就完全没意义了……
  3. 如果想要支持弱引用,需要手动将__weakref__添加进来,虽然自定义class默认存在__weakref__属性,但是想要让实例成为弱引用目标还是需要添加进来才可以。

五、覆盖类属性

实例调用的实例属性时,如果属性不存在,会去读取同名的类属性(例子中的typecode类属性被self.typecode调用)

实例新建实例属性时,如果已经存在同名的类属性,不会改写类属性,而会对实例新建一个实例属性

『流畅的Python』第9章笔记_对象的更多相关文章

  1. 『流畅的Python』第10章笔记_序列类型

    一.基础知识 “__”前缀:私有属性.方法,在__dict__中存储时被改写为“_类名__”前缀 “_”前缀:是约定俗成的保护属性.方法,不过编译器不会对之采取任何处理 二.class特殊方法介绍 在 ...

  2. 『流畅的Python』第5章笔记_一等函数

  3. 『流畅的Python』第15章:上下文管理器和else块

  4. 『流畅的Python』第14章:可迭代的对象、迭代器和生成器

  5. 『流畅的Python』第13章:正确重载运算符

  6. 『流畅的Python』第12章:继承的优缺点

  7. 『流畅的Python』第1~4章笔记_数据结构、编码

    由于1~4章内容零散且基础,所以统计一下涉及到的内容,记录一下,方便查阅(第一张图右键新页面打开即可看到清晰大图)

  8. 流畅的python第十四章可迭代的对象,迭代器和生成器学习记录

    在python中,所有集合都可以迭代,在python语言内部,迭代器用于支持 for循环 构建和扩展集合类型 逐行遍历文本文件 列表推导,字典推导和集合推导 元组拆包 调用函数时,使用*拆包实参 本章 ...

  9. 《流畅的Python》Data Structures--第7章 colsure and decorator

    Function Decorators and Closures 装饰器是用于增强函数的行为,理解它,就必须先理解闭包. Python3引入关键字nonlocal,如果要理解闭包,就必须了解它的所有方 ...

随机推荐

  1. sed命令详解

    搜索 纠正错误  添加实例 sed 功能强大的流式文本编辑器 补充说明 sed 是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响.处理时,把当前处理的行存储在临时 ...

  2. [转]Flex 布局教程:语法篇

    网页布局(layout)是CSS的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中 ...

  3. Android通过Apk插件调起微信支付

    App对接微信调起微信支付需要在微信平台注册,鉴别的标识就是App的包名,所以将申请的包名单独打包成一个Apk文件,则在其他的App调起此Apk的时候同样可以起到调用微信支付的功能.这样就实现了调起微 ...

  4. 【linux】安装samba服务

    学习linux一般是在虚拟机中进行,这样就需要你在windows与linux虚拟机中切换,Samba是很好的共享服务 下面是在汇文培训时宋老师写的配置samba的过程,很容易就能配置成功.还有一些视频 ...

  5. Django框架的安装

    下载Django框架 创建一个django项目 在E盘Mysite文件夹下创建了一个django项目叫mysite 当前文件夹下会产生一个mysite的文件夹,目录结构如下: manage.py -- ...

  6. OpenCV角点检测goodFeaturesToTrack()源代码分析

    上面一篇博客分析了HARRIS和ShiTomasi角点检测的源代码.而为了提取更准确的角点,OpenCV中提供了goodFeaturesToTrack()这个API函数,来获取更加准确的角点位置.这篇 ...

  7. [sso]搭建CAS单点服务器

    1.下载服务器端文件 Cas Client下载:http://developer.jasig.org/cas-clients/ CAS Server:cas-server-4.0.0-release. ...

  8. egret升级经验记录

    1.StageDelegate.setDesignSize ; 直接去掉,在3.x里是直接在index.html里设置如: data-content-width="960" dat ...

  9. 【BZOJ】1878: [SDOI2009]HH的项链 (主席树)

    题目 传送门:QWQ 分析 莫队也能做,但我想练练主席树. 求k-th一样维护第i个时候的线段树,线段树来维护区间不同数. 然后查询时可以通过上下界小优化一波. 但是我的代码丑陋无比,常数巨大(捂脸 ...

  10. 再谈Unity调用Android的Activity

    这段时间在研究Unity4.3开发环境下.怎样调用由Android SDK4.4.2写的Activity.參考了非常多网上的博客.百度出了几十篇大部分都是转载雨松MOMO的,这里必须向雨松MOMO表示 ...