0%

type()

  • type(obj) 返回对象类型,即返回object的class 或 基本类型变量的类型名
  • type(name, bases, dict) 返回name为类名 bases为基类元组, dict为属性的新类型
1
2
3
4
5
6
7
8
9
>>> type(1)
<class 'int'>
>>> type([])
<class 'list'>
>>> type({})
<class 'dict'>
>>> x=1
>>> type(x)==int
True

目前是python3.5

print() 和 n=input()

单行注释# 多行’’’

编码声明

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

缩进

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

命名规范

  • 模块名:全部小写 + 下划线_连接 如 update_userlist
  • 包名:全部小写,不推荐使用下划线
  • 类名:Pascal风格(首字母大写)如RegularUser
  • 模块内部类型: + Pascal风格
    如_Config
    使用单下划线
    开头的变量和函数是受保护的 protected,在使用from xxx import 时不会被导入;使用双下划线__开头的变量或方法是类私有的 *private
  • 函数、类的属性和方法:同模块命名
  • 常量:全部大写

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

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

列表和元组

arr = [0, 1, 2, 3, 4, 5]
arr.append(6) # [0, 1, 2, 3, 4, 5, 6]
arr.remove(0) # [1, 2, 3, 4, 5]
del arr[2] # [0, 1, 3, 4, 5]
del arr[2:4] # [0, 1, 4, 5]

字符串操作

global关键字

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

1
2
3
def initSettings(self):
global config
config = Configure()

执行脚本

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__)

requirements.txt

requirements.txt is a file that contains a list of packages or libraries needed to work on a project that can all be installed with the file. It provides a consistent environment and makes collaboration easier. 包含项目工作所需的包或库,可以用于一键安装

1
pip install -r requirements.txt

tips: 加如下参数以指定源 -i https://pypi.douban.com/simple

生成requirements.txt:

1
pip freeze > requirements.txt

pip freeze 保存当前Python环境下所有类库

1
2
pip install pipreqs
pipreqs ./ --encoding=utf-8

pipreqs 导出当前项目使用的类库

global

#

参考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消耗大呢?)。

掘金:前端可视化工具库

其中提到 Echarts分享社区

“修改默认操作”

面试题:

对于对象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:

itk

ITK 是一个开放源码、面向对象的软件系统,提供一个医学图像处理、图像分割与配准的算法平台

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)
})

等待用户输入

Azure Functions 是微软云提供的部署Api服务的一种功能,利用Azure Functions部署些Api,无需创建/配置服务器环境。即无需先创建 VM 或发布 Web 应用程序。
Azure Function项目自包含运行环境,不依赖外部服务、框架等

安装Azure Functions Core Tools 2.x

  • 安装 .Net Core 2.x SDK

    用于 Windows 的 .NET Core 2.x SDK
  • 使用npm安装Core Tools包
    1
    npm install -g azure-functions-core-tools
  • VS Code Azure Functions 扩展

    搜索 azure functions,或者在 Visual Studio Code 中打开此链接,安装该扩展。

    命令行调试

    安装Azure Functions .NET Worker
    1
    func host start --dotnet-isolated-debug

    创建Functions

  1. 按 F1 键打开命令面板。 在命令面板中,搜索并选择 Azure Functions: Create new project…。
  2. 按照提示对项目进行预设

    Prompt value description
    Select a language for your function app project C# or JavaScript This article supports C# and JavaScript. For Python, see this Python article, and for PowerShell, see this PowerShell article
    Select a template for your project’s first function HTTP trigger Create an HTTP triggered function in the new function app.
    Provide a function name HttpTrigger Press Enter to use the default name.
    Authorization level Function Requires a function key to call the function’s HTTP endpoint.
    Select how you would like to open your project Add to workspace Creates the function app in the current workspace.
  3. 本地调试

    开启F5 / 停止shift+F5
    local.settings.json 文件存储应用设置、连接字符串和本地开发工具使用的设置。 只有在本地运行项目时,才会使用 local.settings.json 文件中的设置。

    关于调用参数

    上面提到本地调试的参数可存于 local.settings.json,取这些参数的方法同取环境变量方法:

  • System.Environment.GetEnvironmentVariable 或 ConfigurationManager.AppSettings (C#)
  • process.env. Settings (js)

    在 Azure Functions 中,没有所有环境通用的基线配置, 即并非所有Azure Function实现都是从本地开发版本部署的,最初是在云中编辑独立解决方案,而不是部署多个版本具有不同的配置。探索 .NET Core 配置系列二

    发布Functions到Azure

    发布功能需要开启Azure Functions: Advanced Creation,在VS Code settings中可以设置,或者发布失败时根据弹窗提示更新设置

  1. 在 Visual Studio Code 中,按 F1 键打开命令面板。 在命令面板中,搜索并选择 Azure Functions: Deploy to function app…。
  2. Create New Function App in Azure
  3. Enter a global unique name for the new function app
  4. select an OS
  5. select a hosting plan

    托管计划consumption plan 和 app service plan等,参考

使用visual studio发布

连接存储队列