0%

目前是python3.5

print() 和 n=input()

单行注释# 多行’’’

编码声明

1
# -*- coding:utf-8 -*-

缩进

Python没有分割代码块符号,以缩进以及冒号:区分层次,一般以4个空格为基本缩进单位。

命名规范

  • 模块名:全部小写 + 下划线_
  • 包名:全部小写,不推荐使用下划线
  • 类名:Pascal风格(首字母大写)
  • 模块内部类型: + Pascal风格

    使用单下划线
    开头的变量和函数是受保护的,在使用from xxx import * 时不会被导入;使用双下划线__开头的变量或方法是类私有的
  • 函数、类的属性和方法:同模块命名
  • 常量:全部大写

字符串类型’’和””和’’’’’’

使用’’’表示多行字符,使用r’’屏蔽转义

列表和元组

字符串操作

global关键字

在python中,变量不需要先声明,直接使用即可,那我们怎么知道用的是局部变量还是全局变量呢?
首先:python使用的变量,在默认情况下一定是用局部变量。
其次:python如果想使用作用域之外的全局变量,则需要加global前缀。

执行脚本

1
$ python test.py arg1 arg2 arg3

脚本内容如

1
2
3
4
5
6
7
#!/usr/bin/python
# -*- coding: UTF-8 -*-

import sys

print '参数个数为:', len(sys.argv), '个参数。'
print '参数列表:', str(sys.argv)

关于python2.7和python3.5的一万种冲突方式

目前的很多情况下,linux的软件管理工具仍然会将python2.7作为默认安装版本,然后在某个时刻你会看到

1
error: xxxx requires python 3.5 or above

于是你再安装一个python3,然而python -V依然是2.7

于是乎卸载python

做link: alias python=python3 均是徒劳

最后

1
sudo apt install python-is-python3

唉,行吧。。

pip 升级issue

1
2
python -m ensurepip
python -m pip install --upgrade pip

python packages 国内源

1
pip install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple ****

查看package版本

控制台

1
2
pip list
pip list | grep opencv-python

程序中
1
2
import cv2
print(cv2.__version__)

参考CSDN zssure 文集。

将DICOM协议当做是专属于医疗领域的“HTTP”传输协议,常见的HTTP协议是通过上表中的各种服务来实现浏览器与服务器之间HTML格式数据的传输;DICOM协议是通过上表中的各种服务实现了医疗设备与数据中心之间DCM格式数据的传输。

对比 HTTP DICOM
OSI层 应用层 应用层
数据 HTML文件 .DCM文件
服务 GET、POST、HEAD、PUT、DELETE、TRACE、CONNECT、OPTIONS C-ECHO、C-FIND、C-STORE、C-MOVE、C-GET、N-GET、N-SET、N-ACTION、N-CREATE、N-DELETE、N-EVENT-REPORT
应用 互联网B/S模式,也可以用于C/S模式 C/S模式,也可以用于WADO(B/S模式)

非关系型数据库

来自Mongodb开发者的话,出自知乎

「让开发者更高效」概括了 MongoDB 相较于关系型数据库带来的全部价值。这要放在最近十年整个行业的大背景下理解。软件行业的工资水平是出了名得高。这意味着软件开发的成本中,人力成本已经超越了硬件成本,成为成本里的大头。曾经长周期、瀑布式的开发流程被强调快速迭代的开发流程所替代。所有这些,加上你经常听说的热词,比如敏捷开发,微服务,DevOps,都指向「让开发者更高效」。这一背景下,基于关系表的关系型的数据模式也被灵活的非关系型数据模式替代。

使用文档模型

文档模型与面向对象的数据表达方式更相似更自然。与关系型数据库中表结构不同,文档中可任意嵌入数组和子文档,就像程序中的数组和成员变量一样。这是关系型数据库三范式不允许的。但实际中我们经常看到一对多和一对一的数据。比如,一篇博客文章的 Tag 列表作为文章的一部分非常直观,而把 Tag 与文章的从属关系单独建立一张关系表就不那么自然。再比如,一个订单下面的收货地址,包括省、市、区、街道和门牌,作为一个子文档,与订单的信用卡地址很容易区分开。更方便的是,嵌入的数组和子文档之上可以直接建立索引,比如我可以很快找到所有 Tag 包含 MongoDB 的文章。

性能

在关系数据库中,为了满足一个查询,多个表的数据都要参与 Join,每一个表都对应着磁盘的一次读取。这和数据放在一个地方,一次读完,当然完全不同。更简单的数据访问模式也让开发者更容易理解数据库的性能表现,尤其是当涉及到索引时。

灵活

关系数据库,常见的运维问题是给已有数据加一个新的属性,从数据表到应用数据层都要改。尽管有些工具可以把它自动化,这仍然是一个复杂的工作,尤其是更新产品线上数据库的时候。MongoDB 没有定义 Schema(模式)的话,就不需要改动数据库,只需要在应用层做必要的改动。

另一个问题是,纯粹业务需要的自定义属性,如不同商品的各种特性,我能理解的是在商品筛选的时候,这些特性可能临时成为区分用的指标,产品这个表应该怎么设计?最简单的方案,是把每个可能的属性都变成单独一列,当然这个方案不能扩展。另一个例子,一个通讯录允许用户随意添加新的联系方式,你有 Facebook,他有 Twitter。一种方案是在程序里把所有自定义属性序列化,比如用 JSON 放到同一字段里。另一种方案,叫做 Entity-attribute-value Model,把自定义属性和他们的数据类型,进一步抽象,增加关系表来表现。这时,相比这些复杂方案,MongoDB 没有 Schema 的优点就显现出来了。

扩展

数据一台机器放不下了,就需要 sharding(分片)把它放到几台机器上去。分片是 MongoDB 多年以来的原生功能,与 MongoDB 其他功能高效整合。例如,分片集群中一个复杂的聚合查询会自动地根据 Shard Key(片键)分配到多个结点上运行,尽可能将计算任务下推到数据结点上,最后在一个结点上聚合所有结点的结果。分片还可以在各个结点间自动迁移数据,均衡其数据量。

为了升级数据库容量,相较于关系型数据库分库分表需要同时改动应用和数据库,MongoDB分片的运维也简单很多,能够做到对应用透明。

我们希望即使机器硬件有问题,数据也不要丢,服务不受影响。分片后机器更多,任一机器出问题的概率也就更高。Replication 复制解决了这个问题。它把同一份数据实时地复制到多个结点,自动地在其中切换。MongoDB 的商业客户中,不论规模大小,使用复制集已经成了一个标准,因为数据丢失的代价远大于冗余机器的成本。

关系型数据库

第一范式

实体中的某个属性不能有多个值或者不能有重复的属性。即要求数据库表的无重复列,同一列不能有多个值。

如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的多个属性构成,新实体与原实体之间为一对多关系

第二范式

非主属性完全依赖于主关键字。
经典的例子是考察一个学生在某门课程中的信息,以(学号,课程)为主关键字的话,考察成绩、教室、教师、上课时间等都没有问题,考察教材时,因为教材应该仅依赖课程,考察学生信息(姓名、性别、专业),因为学生信息只依赖学生。这里存在违反第二范式的隐患。

上述表大致为
serialNo|姓名|专业|上课时间|上课地点|任课教授|资料|成绩
:———|:—:|:—:|:—:|:—:|:—:|:—:|:—:
120022001|王丫蛋|声乐|周三|12教102|Professor Steven|人教版|90
120022201|李铁锤|机械|周四|11教412|Professor Johnson|人教版|75
360022201|李铁锤|机械|周五|12教308|Professor Hassan|人教版|75
首先,调整部分依赖的字段会很麻烦:因考研大纲修改,开课改用外研社教材。需修改大量记录,李铁锤改名李婉如,修改大量记录,即数据冗余

其次,学校新设电子竞技课程,指定了教材,尚未有学生选课,数据是写不进去的,即插入异常

然后,哪天这门课程被教育部指定有悖社会主义核心价值体系,学校偷偷删除了所有选课记录,此时导致表中的学生信息大量遗失,即删除异常
因此应有课程-教材关系表 学号-学生信息关系表

第三范式

符合第二范式的关系模式(具备必要的关系表)中,不应出现依赖于非主属性的属性

例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在的员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。即消除了传递依赖

BCNF

根据候选键关系进一步消除传递依赖(没看懂)

第四范式

满足BCNF,属性不应含有多值,如联系方式相关字段的设计

D3.js 和 Echart

原文:D3.js与echart.js的应用场景

echarts和D3都是常用的数据可视化库,实现了能应用于各场景的图表等插件,两者之间的不同之处就在于echarts是使用canvas来绘制图形的,而D3是通过Svg来绘制图形的。svg可以操作dom支持事件处理器,想要实现某个操作,直接调用相关的方法实现效果就行,svg操作存在链式语法,与jQuery的链式调用差不多,简单易读。canvas不支持事件处理器所以只能展示数据,而不能修改。

  • D3使用svg绘制图形,echarts使用canvas绘制图形
  • D3兼容IE9及以上主流浏览器,echarts兼容IE6及以上主流浏览器
  • D3使用灵活,学习成本大,echarts封装好的,使用简单,不够灵活

因为D3支持事件处理器可以操作dom,所以如果在项目开发中如果有较多用户交互的场景,可以使用D3.如果项目中一般没有用户交互的场景,我们只需要将图表展示给用户看,而不需要更改,可以使用echarts。因为D3它展示的每一个数据都是一个标签,所以当数据发生改变的时候图表会重新渲染,会不停的操作dom,这对性能的消耗是非常大的(存疑,对于同样需要交互的需求,究竟是D3因为绑定了数据的dom频繁渲染消耗大,还是任意修改都需要重绘整个canvas的Echart消耗大呢?)。

“修改默认操作”

面试题:

对于对象o有N个属性,不修改下面代码,编写一段程序获取到对象o的所有属性。

1
2
3
4
5
6
7
8
9
10
var foo = (function(){
var o = {
a: 1,
b: 2,
/**更多属性**/
};
return function(key) {
return o[key];
}
})();

对象o只是函数作用域中的一个局部变量,而对外提供的唯一接口foo(key)可以获取到对象o单独的某个key对应的value,如:foo(‘a’)返回1。但是这里要求获取一个未知属性个数对象o的所有属性。

在 ES5 中可以使用 getter 和 setter 部分改写默认操作,但是只能应用在单个属性上,无法应用在整个对象上。getter是一个隐藏函数,会在获取属性值时调用。setter也是一个隐藏函数,会在设置属性值时调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var test = {
get o(){
console.log('监听到正在获取属性o的值');
return this._o;
},
set o(v){
console.log('监听到正在设置属性o的值为:' + v);
this._o = v;
return this._o;
}
}

test.o = 14; // 监听到正在设置属性o的值为:14
console.log(test.o); // 监听到正在获取属性o的值

答题提示:添加一个属性,并且借助修改其默认get方法暴露this (闭包应用)

答案:

1
2
3
4
5
6
7
8
Object.defineProperty(Object.prototype, 'self', {
get() {
return this;
}
});

var o = foo('self');
console.log(Object.keys(o)); // ['a', 'b']

评论:因为o上的属性有若干个,你不确定o上是否存在属性名为self的的属性,如果存在,你就获取不到原型上的self了,所以最好使用Symbol。
改进:

1
2
3
4
5
6
7
8
9
var key = Symbol();
Object.defineProperty(Object.prototype, key, {
get() {
return this;
}
});

var o = foo(key);
console.log(Object.keys(o)); // ['a', 'b']

触发其他操作

搞一个方块,移动10像素

1
2
3
4
5
6
var box =document.createElement("div");
box.setAttribute("id","box");
box.setAttribute("style","width:30px;height:30px;background:red;");

var transformText = 'translateX(' + 10 + 'px)';
box.style.transform = transformText;

封装让方块移动的操作 当然可以这样
1
2
3
function moveBox(distance){
box.style.transform = 'translateX(' + distance + 'px)';
}

其实也可以这样
1
2
3
4
5
6
7
8
9
Object.defineProperty(box, 'move', {
set: function(value) {
var transformText = 'translateX(' + value + 'px)';
box.style.webkitTransform = transformText;
box.style.transform = transformText;
}
})
//调用
box.move = 100;

熔断逻辑

Express.js 版本弃用一些旧版本的中间件,为了让用户能够更好地发现,有下面这段代码,通过修改get属性方法,让用户调用废弃属性时抛错并带上自定义的错误信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
[
'json',
'urlencoded',
'bodyParser',
/* 此处省略很多包名 **/
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});

参考原文:关于Object的getter和setter   不会Object.defineProperty你就out了

之前只知道

1
JSON.parse(JSON.stringify(obj))

简单实用,可以应付一般对象的场景,其实,这种方式还是有缺陷的————抛弃了原型及构造方法(原类型变成Object),另外JSON序列化会忽略违法安全原则的类型,如undefined、function、symbol(ES6+)、RegExp对象,以及循环引用无法复制,
1
2
ajson = {a:undefined,b:function(){return 1;}} //{a: undefined, b: ƒ}
bjson = JSON.parse(JSON.stringify(ajson)) //{}

深拷贝是各种库都会涉及的工具,也是面试老生常谈的问题

jQuery

jQuery提供了拷贝DOM对象的clone()方法

1
2
3
4
5
6
7
8
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

return this.map( function() {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
} );
},

.clone( [withDataAndEvents ] [, deepWithDataAndEvents ] )

withDataAndEvents Type:Boolean(default: false)

deepWithDataAndEvents Type: Boolean(default: value of withDataAndEvents)


通过调用extend()实现深拷贝:
1
2
var x={a:1, b: { f: { g: 1 } }, c: [ 1, 2, 3 ]};
var y = $.extend(true, {}, x);

合并对象方法,将第三个及之后的参数对象的各属性合并到target:

jQuery.extend( [deep ], target, object1[, objectN ] )

deep = true 则以深拷贝处理 无此参数相当于false

lodash

一个JavaScript工具库,lodash提供_.cloneDeep()方法,该方法用了大量代码实现对ES6新标准对象的支持。

原型拷贝方式

作者: Jerry Zhou 原文:
深入剖析 JavaScript 的深复制

该方法对各种类型进行了细致的分类处理,并且考虑到了存在环形引用关系,以及保留对象所属自定义类型

定义defineMethod,用于向各种类型的原型上面添加自定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
* protoArray需修改的原型的集合
* nameToFunc自定义方法的map
*/
function defineMethods(protoArray, nameToFunc) {
protoArray.forEach(function(proto) {
var names = Object.keys(nameToFunc),
i = 0;

for (; i < names.length; i++) {
Object.defineProperty(proto, names[i], {
enumerable: false,
configurable: true,
writable: true,
value: nameToFunc[names[i]]
});
}
});
}

关于Object.defineProperty()存目

首先对于Number, Boolean 和 String

1
2
3
4
5
6
7
defineMethods([
Number.prototype,
Boolean.prototype,
String.prototype
], {
'$clone': function() { return this.valueOf(); }
});

私以为,按照作者的理念此处应该返回对象(String,Number,Boolean),然而valueOf()出来的都是值类型(string,number,bool),如果返回对象,需要分开写比如 function() { return new String(this.valueOf()) 像他处理Date类型一样
1
2
3
defineMethods([ Date.prototype ], {
'$clone': function() { return new Date(this.valueOf()); }
});

重点在于Object 和 Array 对象,需要递归深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
defineMethods([ Array.prototype, Object.prototype ], {
'$clone': function (srcStack, dstStack) {
var obj = Object.create(Object.getPrototypeOf(this)),
keys = Object.keys(this),
index,
prop;

srcStack = srcStack || [];
dstStack = dstStack || [];
srcStack.push(this);
dstStack.push(obj);

for (var i = 0; i < keys.length; i++) {
prop = this[keys[i]];
if (prop === null || prop === undefined) {
obj[keys[i]] = prop;
}else if()


if (!prop instanceOf Function) {
if (prop.constructor.name==='Object') {
index = srcStack.lastIndexOf(prop);
if (index > 0) {
obj[keys[i]] = dstStack[index];
continue;
}
}
obj[keys[i]] = prop.$clone(srcStack, dstStack);
}
}
return obj;
}
})

注意 原生的js中没有一个可靠的方法确定对象的类型,人家本来就是这样的精神————‘弱类型’,typeof 和 instanceof 都会混淆各种类型,而上面的constructor.name返回构造方法名称,而未必就是类名,因此也是不严谨的,原文作者为每种类型定义了$isFunction、$isPlainObject等属性方法来区分类型

此外$clone()还需处理RegExp对象 Function等
1
2
3
4
5
6
7
8
9
10
defineMethods([ RegExp.prototype ], {
'$clone': function () {
var pattern = this.valueOf();
var flags = '';
flags += pattern.global ? 'g' : '';
flags += pattern.ignoreCase ? 'i' : '';
flags += pattern.multiline ? 'm' : '';
return new RegExp(pattern.source, flags);
}
});

ES6

实现一个完美的深拷贝方法是很繁琐复杂甚至是没有必要的,有些轮子是必要的,而在生产实践中,不说因地制宜,实现方式的复杂度是必须考量的。探究比较深拷贝方法的优劣,其实是对原型,类型等概念的深刻理解的比较好的实践。

图像格式

Images(or voxel)

dcm (DICOM Image): DICOM的全称是 Digital Imaging and Communications in Medicine (医疗数位影像和传输协定)
它是一组通用的标准协定,可以整合不同厂商的医疗影像仪器、伺服器、工作站、列印机和网络设备
和其他格式不同的是它統合了所有的資訊在同一個資料內,也就是說,如果有一張胸腔X光影像在你的病人個人資料內,這個影像決不可能意外地再從你的病人資料中分離。

Meshes

stl (STereoLithography, 立體光刻),用于表示三角形网格的一种文件格式。它的文件格式非常简单,只能描述三维物体的几何信息,不支持颜色材质等信息。
以二进制.stl文件为例,文件起始的80个字节是文件头,用于存贮文件名;紧接着用 4 个字节的整数来描述模型的三角面片个数,后面逐个给出每个三角面片的几何信息。每个三角面片占用固定的50个字节

1
2
3
4
5
6
7
8
UINT8//Header//文件头
UINT32//Numberoftriangles//三角面片数量
//foreachtriangle(每个三角面片中)
REAL32[3]//Normalvector//法线矢量
REAL32[3]//Vertex1//顶点1坐标
REAL32[3]//Vertex2//顶点2坐标
REAL32[3]//Vertex3//顶点3坐标
UINT16//Attributebytecountend//文件属性统计

ply (Polygon File Format, 多边形档案),该格式主要用以储存立体扫描结果的三维数值,透过多边形片面的集合描述三维物体,是相较stl更丰富的方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
ply
format ascii 1.0 ...{ 文件类型:ascii或binary,版本号 }
comment made by anonymous ... { 注释行 }
comment this file is a cube ...{ 注释行 }
comment texture file {纹理贴图文件}
element vertex 8 ...{ 定义“顶点”元素,其数量为8个 }
property float32 x ...{ 顶点的x属性,数据类型为float32 }
property float32 y ...{ 顶点的y属性,数据类型为float32 }
property float32 z ...{ 顶点的z属性,数据类型为float32 }
property float32 textureu {纹理坐标}
property float32 texturev
element face 6 ...{ 定义“面”元素,其数量为6个 }
property list uint8 int32 vertex_index ...{ 面的顶点索引属性,类型为uint8的列表 }
end_header ...{ 文件头结束标志 }
0 0 0 ...{ 顶点元素列表 }
0 0 1
0 1 1
0 1 0
1 0 0
1 0 1
1 1 1
1 1 0
4 0 1 2 3 ...{ 面元素列表 顶点数 顶点编号 }
4 7 6 5 4
4 0 4 5 1
4 1 5 6 2
4 2 6 7 3
4 3 7 4 0

Marching Cubes Algorithm

维基百科

Surface Extraction: Creating a mesh from pixel-data using Python and VTK

图像处理工具库

pydicom

1
2
import pydicom
ds = pydicom.dcmread(file)

vtk

三维计算机图形学、图像处理和可视化软件,内核C++构建,具备多种转换界面,支持Java、Python等方式调用
render: camera actor light
data set:

xslt

PACS

医学影像存档与通信系统(英语:Picture archiving and communication system,PACS)

process模块和process.env环境变量

vscode debug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}\\server.js",
"args": ["--trace-sync-io"],
"env":{
"NODE_ENV":"production",
"PORT":"3001"
}
}
]
}

关于设置环境变量 Node及Express入门

node.js 程序调用命令行

exec方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var exec = require("child_process").exec;
var LangLocale = {
fr: 'fr_FR',
fr_FR: 'fr-FR',
zh_CN: 'zh-CN',
zh_TW: 'zh-TW',
en: 'en_US',
en_US: 'en_US',
ja: 'ja_JP',
es: 'es_ES',
de: 'de_DE',
da: 'da_DK',
}
var langs = Object.values(LangLocale)

function runCMD(cmd) {
return new Promise((resolve, reject) => {
exec(`yarn extract src/locales/${cmd}.json `, {
maxBuffer: 1024 * 2000
}, function (err, stdout, stderr) {
if (err) {
console.log(err);
reject(err);
} else if (stderr.lenght > 0) {
reject(new Error(stderr.toString()));
} else {
console.log(stdout);
resolve();
}
});
})
}
langs.forEach(async (lang) => {
await runCMD(lang)
})