Tip
https://stackoverflow.com/questions/5286390/mocking-functions-using-python-mock
https://docs.python.org/3/library/unittest.mock.html#where-to-patch
未来可期
CI(Continuous integration)与CD(Continuous Delivery、Continuous Deploy)的区别是什么?https://docs.aws.amazon.com/codepipeline/latest/userguide/concepts.html 该地址链接是亚马逊官方定义。
由上图可以看出,CI主要解决代码频繁提交到代码仓库的问题,通过自动构建和单元测试,可以校验代码质量。CD(Delivery)是CI基础上的扩展,主要关注自动部署,通过人工干预一键操作就可以将代码部署到生产环境。CD(Deploy)是在Continuous Delivery基础上的进一步扩展,代码变更将自动部署到生产环境,缩短软件发布周期。
https://thenewstack.io/understanding-the-difference-between-ci-and-cd/
该文章对上述三个概念及历史进行详细说明,概念理解与亚马逊官方给出的一致。
最近使用jmeter进行性能测试时,找到一个可以统计服务器端资源的插件。插件的使用非常简单,安装jemter插件和被测服务器端启动相应代理。https://www.blazemeter.com/blog/how-monitor-your-server-health-performance-during-jmeter-load-test
上述网站对安装使用进行详细介绍。
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example:1
2
3Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.
1 | # Definition for singly-linked list. |
https://www.quora.com/What-are-some-of-the-most-basic-things-every-programmer-should-know#
25个程序员应该知道的事情。有几个需要在平时工作中加强实践。
2.Code reviews by your peers will make all of you better. 目前公司确实没有code view,不过可以在自己组内尝试实践,增强彼此的能力。
3.Learn to Pseudo code the objective(s) before applying a language to the objective(s). (All programs break down to inputs, outputs, and manipulation, etc.) 学习伪代码,并在工作中尝试且坚持使用。
13.Look and learn constantly, but beware the shortcuts. 持续不断的学习和总结,需要持之以恒。
17.Great troubleshooters and problem solvers are true treasures if you find one. Don’t abuse it! 工作中确实没有与解决问题能力强的人太多交流,后面要关注这一点,多交流。
文中提到一点关于上级,对该观点存疑。
21.Make your boss look good always. If you don’t like or respect or if you can’t learn anything more from your boss, seek a new one immediately.
对网站常用数据指标进行汇总。
PV Page View,页面访问量 用户每次对网站中的网页访问一次记录一次,用户对同一个网页多次刷新,访问量累计。
UV Unique Visitor 独立访客。基于客户端cookie实现,用户对同一个网页多次访问指计算一次,访问量不统计。
DAU Daily Active User 日活跃用户。DAU通常统计一日(统计日)之内,登录或使用了某个产品的用户数(去除重复登录的用户),这与流量统计工具里的访客(UV)概念相似。
TPS Transactions Per Second 每秒处理事务数。
QPS Queries Per Second 每秒处理查询数。
RPS Requests Per Second的缩写,每秒能处理的请求数目,等效于QPS。
并发数 系统同时能处理的请求数量,这个也是反应了系统的负载能力。
峰值QPS:
原理:每天80%的访问集中在20%的时间里,这20%时间叫做峰值时间
公式:( 总PV数 80% ) / ( 每天秒数 20% ) = 峰值时间每秒请求数(QPS)
QPS(TPS)、并发数、响应时间它们三者之间的关系是:
QPS(TPS)= 并发数 / 平均响应时间
并发数 = QPS * 平均响应时间
https://stackify.com/unit-testing-basics-best-practices/
极客时间左耳听风专栏中推荐的一篇文章。文章首先划定什么不是单元测试。然后从最原始的方式开始引入单元测试框架,对于初学者来说值得一看。
Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.
1 | class Solution: |
https://towardsdatascience.com/5-advanced-features-of-python-and-how-to-use-them-73bffa373c84
文章介绍Python的五个高级特性,分别是 Lambda、Maps、Filtering、Itertools、Generators。
Lambda可定义匿名函数,适用于简单函数,无需定义函数名称,使用方便。
map()是python的内置函数,你可以通过提供参数列表(单个或多个列表)调用某个函数。
filter()与map()类似,它会返回使调用函数返回True的参数列表。
Itertools模块中zip_longest()将两个列表合并为元组列表;count()返回从0开始往后递增的迭代器;groupby()可以列表中相邻的相同元素进行分组统计。
Generators可以极大节省内存空间。
近期项目编写单元测试的实践及总结:
https://jingjing0506.github.io/2019/04/26/Python%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E5%AE%9E%E8%B7%B5/
https://uwsgi-docs.readthedocs.io/en/latest/ThingsToKnow.html
使用uwsgi须知,最佳实践的建议。由于平时使用uwsgi的场景比较简单,所以涉及的配置比较少。但是在平常使用过程(nginx+uwsgi+flask)中,会出现请求长时间未响应的情况。该情况下,网络、CPU、内存使用都不高,还不清楚具体耗时出现在哪个环节。后期准备通过对uwsgi进行配置更改,进行压力测试,测试是否是因为uwsgi配置不合理造成的。
根据上面的建议,平时项目使用过程中较受用的包括:
uwsgitop官方文档: https://github.com/xrmx/uwsgitop
Python编写单元测试,单元测试框架使用pytest,pytest比较轻量,使用简单。
mock功能通过unitest的mock模块实现。
下面对pytest和unittest.mock进行简单介绍。
官方文档为: https://docs.pytest.org/en/latest/contents.html
使用pytest编写测试脚本相对简单,示例如下,该脚本文件名为: pytest_test.py1
2
3
4
5
6
7
8#!/usr/bin/env python
# -*- coding: utf-8 -*-
def add(a, b):
return a+b
def test_add():
res = add(1, 2)
assert res == 3
在终端运行 pytest pytest_test.py即可。结果如下:
====================== test session starts ===========
platform darwin -- Python 3.6.8, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: /mock_test
collected 1 item
pytest_test.py . [100%]
======================== 1 passed in 0.01 seconds=======================
pytest搜索测试脚本的规则为:
1. 如果命令行指定脚本目录或文件,则按照命令行的设置执行。
如果命令行没有执行脚本路径,则按照testpaths(如果配置的话)和当前路径开始查找。
2. 递归查找测试脚本。
3. 查找符合test_*.py或*_test.py的文件。
4. 查找类外的以test为前缀方法或模块;
查找以Test为前缀的类(且没有__init__方法)中以test为前缀的方法或模块。
按照上述规则命令测试脚本,使用assert关键字对结果进行校验即可。
很多时候编写单测脚本时需要考虑使用关键字驱动,平时使用pytest.mark.parametrize实现,官方文档为https://docs.pytest.org/en/latest/parametrize.html 。使用简单,示例如下:1
2
3
4
5
6
7
8
9#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
@pytest.mark.parametrize(
"test_input,expected",
[("3+5", 8), ("2+4", 6), ("6*9", 42)],
)
def test_eval(test_input, expected):
assert eval(test_input) == expected
终端执行 pytest pytest_test.py,结果如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22========== test session starts ===========
platform darwin -- Python 3.6.8, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: /mock_test
collected 3 items
pytest_test.py ..F [100%]
================ FAILURES ================
___________ test_eval[6*9-42] ____________
test_input = '6*9', expected = 42
@pytest.mark.parametrize(
"test_input,expected",
[("3+5", 8), ("2+4", 6), ("6*9", 42)],
)
def test_eval(test_input, expected):
> assert eval(test_input) == expected
E AssertionError: assert 54 == 42
E + where 54 = eval('6*9')
pytest_test.py:16: AssertionError
======= 1 failed, 2 passed in 0.07 seconds ===================
pytest.mark.parametrize()共两个参数,第一个参数为数据驱动需要输入参数和预期结果,分别于测试函数入参对应;第二个参数为实际的驱动数据。如果驱动数据较多,可以定义列表变量,单独维护。
pytest中实现初始化(setup)和销毁(teardown)功能也很简单,官网文档: https://docs.pytest.org/en/latest/xunit_setup.html 。平时使用过程中,主要使用测试类中方法级别的setup和teardown,其使用方法为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest
class TestRunAll():
def setup_method(self, method):
"""
setup any state tied to the execution of the given
method in a class. setup_method is invoked for every
test method of a class.
"""
pass
def teardown_method(self, method):
"""
teardown any state that was previously setup with a
setup_method call.
"""
pass
其他类型的定义可在官方文档查找。
官方文档分别为: https://docs.python.org/3/library/unittest.mock.html
编写单元测试脚本时,主要使用patch进行mock,patch可以作为装饰器、上下文管理器(通过with关键字)使用。patch.object()可以对类的方法进行mock,这个是平时使用最多的方式。
如下例所示,我们需要测试use_a()方法,该方法通过type类型的不同值,调用A.judge()时使用不同的参数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#!/usr/bin/env python
# -*- coding: utf-8 -*-
from unittest.mock import patch
class A(object):
def judge(self, a, b):
return a+b
def use_a(type=None):
a = A()
if type=='A':
a.judge(1, 3)
else:
a.judge(2, 4)
@patch.object(A, 'judge', return_value=4)
def test_use(judge_mock):
use_a()
judge_mock.assert_called_with(2, 4)
use_a('A')
judge_mock.assert_called_with(1, 3)
注意:
patch作为装饰器使用时,它以自底向上的顺序将mock对象传递给被装置函数,
也就是说下例中module.ClassName1传递给MockClass1。
from unittest.mock import patch
@patch('module.ClassName2')
@patch('module.ClassName1')
def test(MockClass1, MockClass2):
module.ClassName1()
module.ClassName2()
assert MockClass1 is module.ClassName1
assert MockClass2 is module.ClassName2
assert MockClass1.called
assert MockClass2.called
patch.object()函数参数如下:1
2
3patch.object(target, attribute, new=DEFAULT, spec=None,
create=False, spec_set=None, autospec=None, new_callable=None,
**kwargs)
target为类名称,attribute为需要mock的方法名。通过装饰器和with上下文管理器,使得mock范围为所装饰的函数或with范围内。
mock类提供多个断定函数,如上例中assert_called_with(),下面对mock提供的mock函数进行汇总。详细信息可以参考官方对mock类的说明: https://docs.python.org/3/library/unittest.mock.html#the-mock-class1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24assert_called(*args, **kwargs)
# 断言该mock至少被调用过一次
assert_called_once(*args, **kwargs)
# 断言该mock仅被调用过一次
assert_called_with(*args, **kwargs)
# 断言该mock以指定的参数(*args, **kwargs)被调用
assert_called_once_with(*args, **kwargs)
#断言该mock以指定的参数(*args, **kwargs)被调用过一次
assert_any_call(*args, **kwargs)
# 断言该mock以指定的参数(*args, **kwargs)被调用过,不同于
# assert_called_with、assert_called_once_with判断的是最近一次的调用,
# assert_any_call判断的是mock有被调用过。
assert_has_calls(calls, any_order=False)
# 断言该mock按calls设置的方式被调用,如果any_order为False,则mock的调用
# 顺序必须与calls设置一致;如果any_order为True,则需要calls设置的方式必须
# 被调用过。
assert_not_called()
# 断言该mock没有被调用过
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string “”.
Example 1:1
2Input: ["flower","flow","flight"]
Output: "fl"
Example 2:1
2
3Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
Note:1
All given inputs are in lowercase letters a-z.
1 | class Solution: |
https://fangpenlin.com/posts/2012/08/26/good-logging-practice-in-python/
文章介绍了平时开发过程中使用Python记录日志好的实践方法。其中使用json或yaml格式设置日志配置值得借鉴,目前已在项目中使用该方法。
linux系统中查找某个目录下(如/test)包含特定字符串(如test)的文件,可用命令有如下两种:1
grep -ri "test" -l /test
1 | find /test | xargs grep -ri "test" -l |
xargs能够处理管道或者stdin并将其转换成特定命令的命令参数。
https://docs.python-guide.org/writing/tests/
https://hackernoon.com/untold-stories-about-python-unit-tests-a141501f0ee
上述两篇文章介绍了python编写单元测试的建议,可以指导自己开发过程中编写单元测试。
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
Example 1:1
2
3
4
5Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
Example 2:1
2
3
4
5Given nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.
It doesn't matter what values are set beyond the returned length.
Clarification:1
2
3
4
5
6
7
8
9
10
11
12
13
14Confused why the returned value is an integer but your answer is an array?
Note that the input array is passed in by reference, which means modification to the input array will be known to the caller as well.
Internally you can think of this:s
// nums is passed in by reference. (i.e., without making a copy)
int len = removeDuplicates(nums);
// any modification to nums in your function would be known by the caller.
// using the length returned by your function, it prints the first len elements.
for (int i = 0; i < len; i++) {
print(nums[i]);
}
1 | class Solution(object): |
1 | rabbitmq-plugins enable rabbitmq_management |
启动rabbitmq_management插件,再启动rabbitmq-server即可。
增加用户,设置权限1
2
3rabbitmqctl add_user test test
rabbitmqctl set_user_tags test administrator
rabbitmqctl set_permissions -p / test ".*" ".*" ".*"
https://www.rabbitmq.com/production-checklist.html
生产环境使用rabbit mq时清单。
Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
Example 1:1
2Input: 121
Output: true
Example 2:1
2
3Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
Example 3:1
2
3Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
answer1
2
3
4
5
6
7class Solution(object):
def isPalindrome(self, x):
"""
:type x: int
:rtype: bool
"""
return str(x) == str(x)[::-1]
https://towardsdatascience.com/10-git-commands-you-should-know-df54bea1595c
文章介绍了平时开发过程中常用的git命令,以及如何利用别名更快的使用git命令。
近期在做项目时有一个类似规则引擎的需求,就是根据消息中某些字段的值判断需要执行的处理函数,期望能通过配置实现。调研了部分规则引擎,最终选择business_rules的开源工具,git地址为https://github.com/venmo/business-rules 。使用方式简单,编写变量类,动作类,通过规则配置变量条件与动作的映射关系。实例代码如下: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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
from business_rules.variables import BaseVariables
from business_rules.variables import numeric_rule_variable, string_rule_variable, select_rule_variable
from business_rules.actions import BaseActions, rule_action
from business_rules.fields import FIELD_NUMERIC, FIELD_SELECT
from business_rules import run_all
class ProductVariables(BaseVariables):
def __init__(self, product):
self.product = product
@numeric_rule_variable
def current_inventory(self):
return self.product.current_inventory
@numeric_rule_variable(label='Days until expiration')
def expiration_days(self):
last_order = self.product.orders[-1]
return (last_order.expiration_date - datetime.date.today()).days
@string_rule_variable()
def current_month(self):
return datetime.datetime.now().strftime("%B")
class ProductActions(BaseActions):
def __init__(self, product):
self.product = product
@rule_action(params={"sale_percentage": FIELD_NUMERIC})
def put_on_sale(self, sale_percentage):
self.product.price = (1.0 - sale_percentage) * self.product.price
self.product.save()
@rule_action(params=[{'fieldType': FIELD_SELECT,
'name': 'stock_state',
'label': 'Stock state',
'options': [
{'label': 'Available', 'name': 'available'},
{'label': 'Last items', 'name': 'last_items'},
{'label': 'Out of stock', 'name': 'out_of_stock'}
]}])
def change_stock_state(self, stock_state):
self.product.stock_state = stock_state
self.product.save()
rules = [
# expiration_days < 5 AND current_inventory > 20
{ "conditions": { "all": [
{ "name": "current_inventory",
"operator": "greater_than",
"value": 20,
},
]},
"actions": [
{ "name": "put_on_sale",
"params": {"sale_percentage": 0.25},
},
],
},
]
class Product(object):
def __init__(self):
self.current_inventory = 100
self.price = 1
def save(self):
print("save....{},{}".format(self.current_inventory, self.price))
product = Product()
run_all(rule_list=rules,
defined_variables=ProductVariables(product),
defined_actions=ProductActions(product),
stop_on_first_trigger=True
)
ProductVariables为变量类,定义了某变量与变量类成员变量的关系;ProductActions为动作类,定义了处理函数;
rules定义了某条件下调用的处理函数;通过调用run_all()即可运行该规则引擎。
https://www.cloudamqp.com/blog/2015-05-18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html
对rabbit mq进行介绍的系列文章,可以对rabbit mq有初步认识,理解相关概念。
Given a 32-bit signed integer, reverse digits of an integer.
Example 1:1
2Input: 123
Output: 321
Example 2:1
2Input: -123
Output: -321
Example 3:1
2Input: 120
Output: 21
Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−231, 231 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.
1 | class Solution(object): |
文章详细描述软件架构和软件设计的区别并说明两种设计常用的模式。软件架构是将软件特性如灵活性、可伸缩性、可行性、可重用性和安全性等转换为符合技术和业务预期的解决方案过程。常用的设计模式有Serverless架构、事件驱动架构、微服务架构。软件设计则是在代码层面设计软件,如模块划分、类的范围和函数功能等。常见的模式有工厂模式、适配器模式。文章详细、清晰对两个概念进行解释。
近期做项目的过程中再次接触VUE,虽然磕磕绊绊完成前端页面,但是编写代码过程中仍然对基础知识了解不多。项目完成后对编写代码过程中遇到的知识点汇总并仔细研究。除前端外,做项目过程中也接触了flask_cas和Nginx的日志格式,将相关知识点汇总并记录。
v-if可以有条件的渲染一块内容,这块内容只会在指令的表达式返回 truthy 值的时候被渲染。可以使用v-if控制元素的显示。
v-for根据一组数组的选项列表进行渲染。可以方便的展示列表、下拉框机选项等。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
36
37
38
39
40<template>
<div id="app">
<!-- <img src="./assets/logo.png"> -->
<p v-if="seen">现在你看到我了</p>
<ol>
<li v-for="(todo,index) of todos" :key="index" >
{{ todo.text }}
</li>
</ol>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
seen: true,
todos: [
{'text': '测试1'},
{'text': '测试2'},
{'text': '测试3'},
{'text': '测试4'},
{'text': '测试5'}
]
}
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
启动后,页面展示为:
Prop是可以在组件上注册一些自定义的特性。当一个值传递给prop特性的时候,它就变成了那个实例组件的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中。对于vue-cli生成的vue项目有,我们在components目录下新建一个vhead.vue的文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13 <template>
<h3>{{ title }}</h3>
</template>
<script>
export default{
name: 'vheader',
data () {
return {
}
},
props: ['title']
}
</script>
在App.vue中注册并使用它
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 <template>
<div id="app">
<!-- <img src="./assets/logo.png"> -->
<vhead title="测试组件1"></vhead>
<vhead title="测试组件2"></vhead>
<vhead title="测试组件3"></vhead>
</div>
</template>
<script>
import vhead from './components/vhead'
export default {
name: 'App',
components: {vhead}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
运行之后效果如图,一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
Flask-CAS是提供了方便与cas server进行认证的插件。
使用过程中有两个重要配置,CAS_SERVER是CAS服务器的地址,CAS_AFTER_LOGIN是登录成功后跳转的端点。
某项目上线后,发现有时会出现网页loading特别慢的情况,希望通过Nginx日志查看请求各阶段的时间。通过log_format可以配置Nginx日志的打印格式,access_log使用配置的log_format即可。
log_format设置格式如下1
2
3log_format main 'remote_addr=[$remote_addr] http_x_forward=[$http_x_forwarded_for] time=[$time_local] request=[$request] '
'status=[$status] byte=[$bytes_sent] elapsed=[$request_time] refer=[$http_referer] body=[$request_body] '
'upstream_response_time=[$upstream_response_time] ';
其中各项定义为:1
2
3
4
5
6
7
8
9
10$remote_addr #记录访问网站的客户端地址
$http_x_forwarded_for #当前端有代理服务器时,设置web节点记录客户端地址的配置,此参数生效的前提是代理服务器也要进行相关的x_forwarded_for设置
$time_local #记录访问时间与时区
$request #用户的http请求起始行信息
$status #http状态码,记录请求返回的状态码
$bytes_sent #http状态码,记录请求返回的状态码
$request_time #整个请求的总时间
$http_referer #url跳转来源
$request_body #请求报文中body内容
$upstream_response_time #请求过程中,upstream响应时间
定义好log_format后,access_log或者error_log的配置如下,记录的日志即按照配置的格式记录。1
access_log xxxx(path) main;
https://doc.huodongjia.com/detail-3423.html
文章是互联网时代的持续交付,是阿里某专家在ArchSummit上的会议演讲。文中提到了持续交付过程中经常遇到的一些问题以及他们在实施时采用的方法。对公司实施持续交付有一定参考价值。
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:1
2
3
4Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
Answer:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
length = len(nums)
if length <= 1:
return []
for i in range(length-1):
for j in range(i+1, length):
if nums[i]+nums[j]==target:
return [i,j]
return []
https://medium.freecodecamp.org/code-comments-the-good-the-bad-and-the-ugly-be9cc65fbf83
文章介绍代码中好的、坏的、丑陋的注释。框架或者库类的注释,最好能使用某些工具与线上文档关联,这样就可以保证文档的实时性。在代码中容易让人迷惑的地方添加注释,可以减少后期维护者的时间。不要在代码中添加无用的、宣泄类的注释。
近期在编写server端代码时,准备使用falsk_restful框架,编写过程中发现该框架提供的自定义错误处理方式有限,flask通过注册和装饰器的方式即可实现自定义错误处理。因而对两个框架的自定义错误处理做了研究。
Flask提供两种方式注册自定义错误处理函数:
register_error_handler 函数直接注册
两种方式都可以针对响应码或特定异常注册对应的处理函数
1 | #!/usr/bin/env python |
运行上述代码后,访问http://127.0.0.1:5000/test_flask, 响应为: handle ex。通过自定义的异常处理函数,可以针对特定异常定制特殊操作。
对于有flask自定义异常的应用,对于flask_restful抛出的异常,并不会由flask框架定义的异常处理,flask_restful会直接处理框架内抛出的异常。
1 | #!/usr/bin/env python |
服务启动后,访问http://localhost:5000/test_flask_restful, 得到响应码为500的响应。
flask_restful支持自定义错误消息。
1 | #!/usr/bin/env python |
同样访问http://localhost:5000/test_flask_restful,得到响应码为200的响应 {“message”: “A user with that username already exists.”, “status”: 200}。
目前来看,flask_restful支持的自定义异常处理方式,不如flask框架灵活。
https://mp.weixin.qq.com/s/G-BCXiWJucUzfzvWG2BIQw
CI/CD主要流程及功能大家都比较清晰,如何推进公司的CI/CD进程与建设,自上而下的组织支持对于公司实施与推进CI/CD流程相当重要。