Jimmy那些事儿


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

  • 搜索
close
Jimmy那些事儿

Anaconda_使用指南

发表 2017-06-16 | 更新 2018-02-13 | 分类 软件应用 , 程序编程 , anaconda | 阅读次数

Conda的包管理

1
2
3
4
5
6
7
8
# 安装包
conda install numpy
# 查看已经安装的packages
conda list
# 在当前环境下安装anaconda包集合
conda install anaconda
阅读全文 »
Jimmy那些事儿

《文明是副产品》读书笔记_郑也夫

发表 2017-06-06 | 更新 2018-11-11 | 分类 阅读书籍 | 阅读次数

《文明是副产品》郑也夫

阅读全文 »
Jimmy那些事儿

《理性乐观派》读书笔记_马特.里德利

发表 2017-05-20 | 更新 2018-11-11 | 分类 阅读书籍 | 阅读次数

《理性乐观派》_[英] 马特 • 里德利

Matt Ridley

  1. 交易(贸易)在人类发展中起的作用
  2. 交换,是通往繁荣的道路(而非自给自足)。交换 $\to$ 专业化 $\to$ 劳动分工 $\to$ 集体智慧,使得生产效率发生质的飞越;
    • 自给自足的生活,需要花费大量时间在满足生理需求(即生存上),使得几乎没有时间去发展技术
    • 交换,交换的是不同的东西;
    • 交换实质上是不平等的,但却仍然能让双方都受益
  3. 集体大脑。没有集体智慧,很难进行复杂工具的生产。知识,从来都不是以浓缩或者综合的形式存在,而是以不完整甚至往往是自相矛盾的知识比特的形式存在,为不同个体所占有。
    • 要让交换可行,两个人不需要提供同等价值的东西。这是因为,人类往往会自己无法拥有的东西赋予高价值;对交换依赖越多,交换的吸引就越大,就越会促成专业化。
  4. 所谓繁荣,是你以同样工作量换取的商品或服务的数量增加了。贫穷与富裕的定义是,以你的时间换取 ( 需要的 /想要的) 产品的价格
    • 消费简单化,生产多样化 $\to​$ 消费多样化,生产简单化
  5. 人类会与同类的陌生人和平相处。这是其他动物所没有的。
阅读全文 »
Jimmy那些事儿

Python_数据处理_pandas

发表 2017-05-17 | 更新 2018-01-24 | 分类 软件应用 , 程序编程 , Python | 阅读次数

pandas 指引 : http://pandas.pydata.org/pandas-docs/stable/api.html#function-application-groupby-window

  • DataFrame 单独取出一列是 Series 格式
阅读全文 »
Jimmy那些事儿

Python_基本概念与操作

发表 2017-05-17 | 更新 2018-02-13 | 分类 软件应用 , 程序编程 , Python | 阅读次数

数据类型

  • Number(数字)
    • int(整型)
    • float(浮点型)
    • complex(复数)
  • String(字符串)
  • List(列表)
  • Tuple(元组)
  • Set(集合)
  • Dictionary(字典)
  • Number(数字)


字符串

  • 字符串的输入

    • 单引号/双引号; 单引号
    • 三个引号
      1
      2
      3
      4
      5
      6
      7
      - **字符转义**:
      - `\ (反斜杠)`
      - `r`` ` 引号内部的字符串默认都不转义
      ```python
      r`ABC\.CSV$`
  • 合并 :运用加号 ( + ) 来进行合并字符串

  • 空白

    • 添加空白:制表符 (\t) 、换行符(\n)
    • 删除空白:两侧 - strip();左侧 - lstrip();右侧 - rstrip()
  • 赋值与变更 : 必须将变更后的对象赋值,因为字符串是不可更改的; f = f.strip()

  • 字符串 *(星号) 数字;表示字符串重复输出n次 print("." * 10)

  • 转换 : str()

  • 长度:len(string)

  • 格式化

    • 用%来实现字符串的格式化
1
2
3
4
binary = "binary"
do_not = "don't"
y = "Those who know %s and those whe %s." % (binary, do_not)
print(y)
字符串 含义
%d - digit 整数
%f - float 浮点数
%s - string 字符串
%x 十六进制整数
%% 一个%

如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串


布尔值

  • and / or / not

空值

  • None,一个特殊的空值

可变与不可变对象

  1. str是不变对象,而list是可变对象
    • 对于可变对象,比如list,对list进行操作,list内部的内容是会变化的
    • 对于不可变对象,比如str,对str进行操作,str内部是不变的。
1
2
3
4
5
6
7
8
9
10
11
12
# 可变对象
>>> a = ['c', 'b', 'a']
>>> a.sort()
>>> a
['a', 'b', 'c']
# 不可变对象
>>> a = 'abc'
>>> a.replace('a', 'A')
'Abc'
>>> a
'abc' # 虽然字符串有个replace()方法,也确实变出了'Abc',但变量a最后仍是'abc'
  1. 始终牢记的是,a是变量,而’abc’才是字符串对象!有些时候,我们经常说,对象a的内容是’abc’,但其实是指,a本身是一个变量,它指向的对象的内容才是’abc’ 。
    • 当我们调用a.replace(‘a’, ‘A’)时,实际上调用方法replace是作用在字符串对象’abc’上的,而这个方法虽然名字叫replace,但却没有改变字符串’abc’的内容。相反,replace方法创建了一个新字符串’Abc’并返回,如果我们用变量b指向该新字符串,就容易理解了,变量a仍指向原有的字符串’abc’,但变量b却指向新字符串’Abc’了
    • 对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。相反,这些方法会创建新的对象并返回,这样,就保证了不可变对象本身永远是不可变的。

a-b-to-2-strs


数据类型转换

函数 描述
int(x [,base]) 将x转换为一个整数
long(x [,base] ) 将x转换为一个长整数
float(x) 将x转换到一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(s) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组。
frozenset(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
unichr(x) 将一个整数转换为Unicode字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串


数据结构

元组 - tuple

  • what :元组是一种不可变序列
    • 元组和列表一样可以使用索引、切片来取值。
    • 创建元组后不能在原地进行修改替换等操作
    • 元组支持嵌套,可以包含列表、字典和不同元组
  • why :元组的不可变性,在保证一个程序安全方面起到很大作用。

创建tuple

  • 元组是用小括号( )包括起来的,( )括号中的元素用逗号分割,这样就完成元组的创建了
  • 用tuple函数进行创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>>(1,2,3)
(1,2,3)
# 如果新建时没有用( )括号包括,只用逗号进行分隔python也会把它认做为元组
>>>1,2,3
(1,2,3)
# 如果你新建的元组中只有一个值,那么请记得在这个值后边加上逗号
>>>1,
(1,)
# 如果没有逗号,python只当把它当做整型来处理。
>>>1
----------------------------------------------------------------------------------------------------------------------------------------
# 用到tuple函数的功能:它可以一个列表为参数,把它转换为元组。
>>>tuple([7,8,9])
(7,8,9)
>>>tuple('hello') # 把字符串'hello'中的每一个字母,都做为一个新的元素添加到新元组中
('h', 'e', 'l', 'l', 'o')

修改元组

元组是不可变的,类似字符串,不能在原处修改内容,但我们可以把它的类型做下转换,例如把一个元组转换为一个列表进行修改,之后再转换成元组。

索引 - 切片


列表list - 基本功能

  • what :可以包含不同类型的数据对像,同时它是一个有序的集合;同时,它支持添加 append、插入 insert、修改、删除del等操作

1. 创建

  1. list列表理解为任意对像的序列,只要把需要的参数值放入到中括号[ ]里面就可以了
  2. 用函数list()创建
1
2
3
4
5
6
names = ['ada','amy','ella','sandy']
list()
# 列表可以包含不同类型对像,也支持嵌套:
>>>a = ['a',567,['adc',4,],(1,2)]

2. 查找(索引) - 切片

方括号中索引值,半闭半开区间;左侧包括,右侧不包括

  1. 使用方括号[ ] 与 冒号 :
  2. 索引从0开始;
  3. 最后一个列表的元素为-1 (倒数第二个为-2,从末尾开始数正常)
1
names[1:2]

3. 修改

  1. 列表是有序的,可以通过list下标来修改特定位置的值
1
2
3
4
>>>a = [1,9,9]
>>>a [0] = 9
>>>a
[9,9,9]

4. .append() / .insert() - 添加

  1. 末尾添加 - append(obj) / append(“string”)
  2. 插入元素 - insert(n, obj) /insert(n, “string”) motorcycles.insert(0, 'ducati')
    • 第一个实参n表示插入的索引位置;这种操作会使得表中所有位于该索引之后的元素往右移一个位置;


5. del & pop & remove - 删除

  1. 根据位置直接删除 - del del motocycles[0]

  2. 根据位置删除 - pop()

    • 默认情况下,弹出列表末尾的一个元素 motorcycles.pop()
    • 指定索引位置,则弹出该位置的元素 motorcycle.pop(1)
    • 每次只能删除一个索引位置的元素
  1. 根据值删除 - remove()

    • remove 只删除第一个指定的值;若要删除的值在列表中出现多次,需要用循环来操作
  • motorcycles.remove('string') / motorcycles.remove(obj)

如果被弹出的元素不再需要使用,就选择del


6. .sort() / sorted() - 排序

  1. 永久性排序 - 方法sort() cars.sort(reverse=True) 默认按字母顺序进行升序排列
  2. 临时性排序 - 函数sorted() sorted(cars, reverse = True)

7. .reverse - 反转

  1. 方法reverse() cars.reverse()

反转是在原有的基础上进行颠倒;不同于按倒序排列

8. 长度 - len()

Python计算列表list元素时从1开始。但索引是从0开始的;所以,在确定列表长度时会遇到差一


列表 - 操作

1. 遍历列表 - 循环

  1. for循环对列表的每个元素进行访问。
1
2
for magician in magicians:
print(magician.title() + ", that was a great trick!")

使用单数、复数的名称,有利于判断是单个列表元素还是整个列表

冒号的使用

缩进的代码必须是循环的一部分;没有缩进的代码只执行一次

2. 创建数值列表- range

  1. 函数range() ,半闭半开区间;
1
range(1,100,2) # c为步长

3. 列表推导式

  1. 将for循环和创建新元素的代码合并成一行;(语法糖)
1
2
3
4
5
6
7
8
9
10
11
12
13
resutl = [ expr_value for value in collection if condition]
# expr_value 为value的表达式 squares = [value**2 for value in range(1,11)]
# 若缺少变量result,则直接返回符合的值
# ----等价于---------
result = []
for value in collction:
if condition:
result.append(value)
# ---------示例--------------
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
[x.upper() for x in strings if len(x) > 2]

字典推导式

1
2
> dict_result = { key-expr: value-expr for value in collection if condition} # 区别在与用 花括号
>

>

集合推导式

1
2
> set_result = {expr for value in collection if condition}
>


4. 使用列表的一部分 - 切片/复制

  1. 切片 :指定第一个元素、最后一个元素的索引;
1
2
3
4
5
players[0:3] # 列表中实际的 1~3个元素;
players[:4] # 未指定第一个元素的索引,则从0开始
players[2:] # 未指定最后一个元素的索引,则到末尾; 等价于players[2:-1]
players[-3:] # 从倒数第3个元素的开始到末尾
players[:] # 列表的所有元素
  1. 复制列表 :复制,两者之间没有联系。通过复制来实现
1
friend_food = my_food[:]
  1. 若直接赋值,则表示指向同一个对象;两者之间有关联;
1
2
3
4
5
6
7
8
9
10
11
12
13
friend_food = my_food
# --------------示例----------------
my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods
my_foods.append('cannoil')
print(my_foods)
print(friend_foods)
>>>
['pizza', 'falafel', 'carrot cake', 'cannoil']
['pizza', 'falafel', 'carrot cake', 'cannoil']


字典 - dict

  • what :字典是一系列键-值对。每个键都与一个值相关联。

一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉

dict是用空间来换取时间的一种方法,并且需要牢记的第一条就是dict的key必须是不可变对象。

字符串、整数等都是不可变的,因此,可以放心地作为key

dict全称dictionary,在其他语言中也称为map

1. 创建与访问

  1. 创建:
    • 用花括号、冒号来实现
    • dict()
1
2
3
4
p = {}
p = {'color': 'green',
'points': 5, # 最后一个仍留有逗号,为以后添加键值做准备
}
  1. 访问:指定方括号内的键
1
p['color']

2. 添加与删除

  1. 添加键-值对:直接赋值,若键不存在则创建
1
2
p['x_position'] = 0
p['y_position'] = 25
  1. 删除
1
2
3
del p['color']
p.pop('color') # 指定的是键,而非值; 在列表list中,pop指定的是索引

3. 遍历字典

  1. 遍历所有的键-值对 - .items()
  2. 遍历所有的键 - .keys()
  3. 遍历所有的值 - .values()
1
2
3
4
5
6
for key, value in user_0.items():
pass
for key in user_0.keys():
pass
for value in user_0.values():
pass
  1. 按顺序遍历所有的键 - for key in sorted(user_0.keys()):


集合 - set

  • what :没有重复的键。
  • why :重复元素在set中自动被过滤

set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象

1. 创建

创建一个set,需要提供一个list作为输入集合

1
2
3
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}

传入的参数[1, 2, 3]是一个list,而显示的{1, 2, 3}只是告诉你这个set内部有1,2,3这3个元素,显示的顺序也不表示set是有序的>>> s = set([1, 2, 3])>>> s{1, 2, 3}

2.添加与删除

  1. 添加 - .add()
  2. 删除 - .remove()


条件判断

1.条件测试

  1. 相等 ==
  2. 不相等 !=
  3. 检查多个条件:and / or
    • 为改善可读性,建议加上括号 (age > 21) and (age_1 > 21)

2. 检查特定值是否包含在[列表]

  1. in / not in

3. if语句

  1. if语句
  2. if - else 语句
  3. if - elif - else 语句

它是从上往下判断,如果在某个判断上是True,把该判断对应的语句执行后,就忽略掉剩下的 elif 和 else

只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# if语句
if x:
print(x)
# if-else 语句
if x:
pass
else:
pass
# if-elif-else语句
if x:
pass
elif y:
pass
else:
pass


4. input - 有问题的条件判断

input()返回的数据类型是str,str不能直接和整数比较,必须先把str转换成整数

1
2
3
4
5
birth = input('birth: ')
if birth < 2000:
print('00前')
else:
print('00后')


循环

break & continue

break语句可以在循环过程中直接退出循环,而continue语句可以提前结束本轮循环,并直接开始下一轮循环。

  1. break
    • 立即退出循环; 即该for/while循环停止,不在运行任何代码
    • 嵌套循环中,仅跳出当前所在for/while循环
  2. continue
    • 忽略余下代码,直接返回for/while循环的开头。即立刻开始第二次循环
1
2
3
4
5
6
7
8
9
10
## 返回100以内的质数
# k = ''
for i in range(50:101): # 第1层循环
for a in range(2:i): # 第2层循环 (从2开始作为除数,并且终止于i-1)
if i % a == 0:
break # 此处break跳出的是for a 这个第2层循环;即该for a循环不在执行,i 从 50增加到51
if a == i - 1:
print(i)
# k = k +str(i) + '\n'
# print(k)


函数

1. 定义函数

定义函数时,需要确定函数名和参数个数;

如果有必要,可以先对参数的数据类型做检查;

  1. 定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
  2. 函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。
  3. 如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。
1
2
3
4
5
def my_abs(x):
if x > 0:
return x
else x < 0:
return -x

如果想定义一个什么事也不做的空函数,可以用pass语句:pass语句什么都不做.

实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

1
2
3
> def nop():
> pass
>
  1. 参数检查
    • 调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError:
    • 当传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义的my_abs没有参数检查,会导致if语句出错,出错信息和abs不一样。
1
2
3
4
5
6
7
def my_abs(x):
if not isinstance(x, (int, float)):
raise TypeError(('bad operand type'))
if x >= 0:
return x
else:
return -x
  1. 返回多个值

    1
    2
    3
    4
    5
    import math
    def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

2. 参数

1. 形参与实参

  • 形参:函数完成工作时所需的一项信息
  • 实参:调用函数时传递给函数的信息
  • 位置实参:顺序很重要
  • 关键字实参:传递给函数的 名称 - 值对

2. 参数的默认值

  • 在形参部分赋值
  • 必选参数在前,默认参数在后
1
2
3
4
5
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L

3. 可选参数(实参)

  1. 使用默认值让实参变为可选的:空字符串 + 置于末尾
1
2
def get_formatted_name(first, last, middle=''):
print(first + middle + last)

4.1 任意数量的(可变)实参

允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple 【关键区别】。

  1. 在形参之前加上一个星号(*) : 创建一个名为numbers的空元组tuple,并将所有收到的值封装到这个元组中
1
2
3
4
5
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
  1. 如果已经有一个list或者tuple,要调用一个可变参数;允许你在list或tuple前面加一个星号(*),把list或tuple的元素变成可变参数传进去:
1
2
3
4
5
6
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
# ---------其他方式-------------
calc(nums[0], nums[1], nums[2])
  1. 位置实参 + 任意数量实参 :将位置实参写在前 + 任意数量实参仍用 *形参名
1
2
def make_pizza(size, *toppings):
print(size + toppings)

4.2 任意数量的关键字实参

允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict 【关键区别】

  1. 形参之前加上两个星号(\) :创建一个名为person的空字典,并将收到的所有名称-值对封装到这个字典中**
    • 该方式不限制关键字参数的名字
1
2
3
4
5
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
person('bob' , 35, city = 'Beijing', tall =32)
>>>name: bob age: 35 other: {'city': 'Beijing', 'tall': 32}
  1. 限制关键字参数的名字,就可以用命名关键字参数

    • 命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数 【建议采用此种命名方法】
    1
    2
    3
    4
    5
    def person(name, age, *, city, job):
    print(name, age, city, job)
    person('Kate', 21, args=32, city='shanghai', job='doctor')
    [out]: Kate 21 32 shanghai doctor
    • 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
      • 但该可变参数为元组,会用圆括号括起来
    1
    2
    3
    4
    5
    def person(name, age, *args, city, job):
    print(name, age, args, city, job)
    person('Kate', 21, 32, city='shanghai', job='doctor')
    [out]: Kate 21 (32,) shanghai doctor
  1. 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
  2. 使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数

5. 参数组合

  1. 参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
    • 可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
# *args 作为一个任意数量的实参,为一个元组
f1(1, 2, 3, 'a', 'b', x=99)
[out]: a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
--------------------------------------------------------------------
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
# *,d 作为一个整体,为命名关键字参数
# **kw 为关键字参数(实参名字可任意命名)
f2(1, 2, d=99, ext=None)
[out]: a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
  1. 通过一个tuple和dict,你也可以调用上述函数:
1
2
3
4
5
6
7
args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)
[out]: a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
f2(*args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
  • 其他

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名” a =abs ; a(-1)

6. 参数小结

  1. 默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
  2. 要注意定义可变参数和关键字参数的语法:
  3. *args是可变参数,args接收的是一个tuple;
  4. **kw是关键字参数,kw接收的是一个dict。
  5. 调用函数时如何传入可变参数和关键字参数的语法:
    1. 可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3));
    2. 关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})。
  6. 使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
  7. 命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
  8. 定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数


3. 传递实参 - 列表

1
2
3
4
5
6
7
8
9
10
11
12
13
def greet_users(names):
'''doc strings'''
for name in names:
msg = "Hello, " + name.title() + "!"
print(msg)
usernames = ['hanah', 'ty', 'magto']
greet_users(usernames)
[out]:
Hello, Hannah!
Hello, Ty!
Hello, Magot!

4. 返回值

函数体内部可以用return随时返回函数结果;

函数执行完毕也没有return语句时,自动return None。

函数可以同时返回多个值,但其实就是一个tuple。

  1. 使用return语句将值返回到函数的调用行
1
2
3
4
5
6
7
8
def get_formatted_name(firsr, last):
full_name = first + ' ' + last
return full_name.title()
#--------------------------------------------------------
def get_formatted_name(firsr, last):
full_name = {'first': first, 'last': last} # 返回字典
return full_name

5. 递归函数

每个函数应只负责一项具体的工作。若执行的任务太多,可在函数中调用另一个函数

在函数内部,可以调用其他函数。所谓递归函数,一个函数在内部调用自身本身 。

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理

1
2
3
4
def fact(n):
if n==1:
return 1
return n * fact(n - 1)

使用递归函数的优点是逻辑简单清晰,理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。缺点是过深的调用会导致栈溢出。

针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

5. 保存与调用

如果你已经把my_abs()的函数定义保存为abstest.py文件了,那么,可以在该文件的当前目录下启动Python解释器,用from abstest import my_abs来导入my_abs()函数,注意abstest是文件名(不含.py扩展名)

1
from abstest import my_abs # 导入my_abs() 函数


函数式编程

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。

  • what :函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。
    • 计算机(Computer)和计算(Compute)
      • 计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。
      • 计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。
    • 对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。
    • 函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量
    • 任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。
      • 允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
  • why :函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

高阶函数

  1. 变量可以指向函数

    • 函数本身赋值给变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> abs(-10)
    10
    >>> abs
    <built-in function abs>
    # abs(-10)是函数调用,而abs是函数本身。
    -----------------------------------------------------------------------------
    >>> f = abs
    >>> f
    <built-in function abs>
    # 说明变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同。
  2. 函数名也是变量

    函数名其实就是指向函数的变量 。对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!

  3. 传入函数

    1
    2
    3
    4
    5
    6
    7
    8
    def add(x, y, f): # f = abs
    return f(x) + f(y)
    x = -5
    y = 6
    f = abs
    f(x) + f(y) ==> abs(-5) + abs(6) ==> 11
    return 11

    ​


切片&迭代

1. 切片

tuple也是一种list,唯一区别是tuple不可变。因此,tuple也可以用切片操作,只是操作的结果仍是tuple

字符串’xxx’也可以看成是一种list,每个元素就是一个字符。

  1. 切片 :指定第一个元素、最后一个元素的索引;
1
2
3
4
5
players[0:3] # 列表中实际的 1~3个元素;
players[:4] # 未指定第一个元素的索引,则从0开始
players[2:] # 未指定最后一个元素的索引,则到末尾; 等价于players[2:-1]
players[-3:] # 从倒数第3个元素的开始到末尾
players[:] # 列表的所有元素
  1. 切片的第三个值为步长step
1
2
3
4
5
6
7
8
# 前10个数,每两个取一个:
>>> L[:10:2]
[0, 2, 4, 6, 8]
# 所有数,每5个取一个:
>>> L[::5]
[0, 5, 10, 15, 20, 25]
  1. 字符串的选取
1
2
3
# 字符串'xxx'也可以看成是一种list,每个元素就是一个字符。
>>> 'ABCDEFG'[:3]
'ABC'
  1. 复制列表 :复制,两者之间没有联系。通过复制来实现
1
friend_food = my_food[:]

2. 迭代

  • what :如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。
    • 这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
      • 集合数据类型:列表list、元组tuple、字典dict、字符串string、集合set
      • generator,包括生成器和带yield的generator function
    • 可以使用isinstance()判断一个对象是否是Iterable对象

迭代操作

  1. list或tuple迭代
1
2
for i in list:
print(i)
  1. 字典dict迭代

dict迭代的是key。

如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for key, value in d.items()。

1
2
3
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d: # value in d.values() / key, value in d.items()
print(key)
  1. 字符串迭代
1
2
>>> for ch in 'ABC':
print(ch)
  1. 索引和元素同时迭代:Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身:
1
2
3
4
5
6
>>> for i, value in enumerate(['A', 'B', 'C']):
print(i, value)
0 A
1 B
2 C

判断迭代

  • 判断是否可迭代:通过collections模块的Iterable类型判断
1
2
3
4
5
6
7
8
9
10
11
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False


3. 列表生成式

  1. 将for循环和创建新元素的代码合并成一行;(语法糖)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
resutl = [ expr_value for value in collection if condition]
# expr_value 为value的表达式 squares = [value**2 for value in range(1,11)]
# 若缺少变量result,则直接返回符合的值
# ------------------------等价于---------------------------------
result = []
for value in collction:
if condition:
result.append(value)
# ---------------------示例-------------------------
strings = ['a', 'as', 'bat', 'car', 'dove', 'python']
[x.upper() for x in strings if len(x) > 2]
[x * x for x in range(1, 11) if x % 2 == 0]

字典推导式

1
2
> dict_result = { key-expr: value-expr for value in collection if condition} # 区别在与用 花括号
>

>

集合推导式

1
2
> set_result = {expr for value in collection if condition}
>
  1. 两层循环
1
2
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']


4. 生成器

  • what :一边循环一边计算的机制,称为生成器:generator。

如果列表元素可以按照某种算法推算出来,这样就不必创建完整的list,从而节省大量的空间。

  1. 创建生成器generator
    • 只要把一个列表生成式的 [] 改成 (),就创建了一个generator:
1
2
3
4
5
L = [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
g = (x * x for x in range(10))
<generator object <genexpr> at 0x1022ef630>

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

  1. 返回值
    • next()函数获得generator的下一个返回值
    • 通过迭代
1
2
3
4
5
6
7
8
9
>>> next(g)
0
>>> next(g)
1
# ---------------------通过迭代----------------------------
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

  • 生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
    • 把list、dict、str等Iterable变成Iterator可以使用iter()函数:
1
2
3
4
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

list、dict、str等数据类型不是Iterator 。

因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。


类

面向过程 vs. 对象的程序设计

  • what :面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

  • 面向过程 vs. 对象编程:

    • 面向过程的程序设计:把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。
    • 面向对象的程序设计:把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

    在Python中,所有数据类型都可以视为对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

  • 面向过程

1
2
3
4
5
6
7
8
## 假设我们要处理学生的成绩表,为了表示一个学生的成绩
# 面向过程的程序可以用一个dict表示
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
# 处理学生成绩可以通过函数实现,比如打印学生的成绩
def print_score(std):
print('%s: %s' % (std['name'], std['score']))
  • 面向对象
    • 采用面向对象的程序设计思想,我们首选思考的不是程序的执行流程,而是Student这种数据类型应该被视为一个对象,这个对象拥有name和score这两个属性(Property)
1
2
3
4
5
6
7
8
9
# 如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象,然后,给对象发一个print_score消息,让对象自己把自己的数据打印出来。
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))


创建 - 类

类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;

方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;

通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同:

class后面紧接着是类名,即Dog,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念我们后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

attribute为该类的属性;def 定义的该类的行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Dog():
"""一次模拟小狗的简单尝试"""
# ----------直接定义属性----------------- # 调用类时无需再传入外部参数,此时已默认其属性值
name = 'Kite'
age = 3
#------------初始化属性------------------ # 调用类时必须传入外部参数
def __init__(self, name, age):
"""初始化属性 name 和 age"""
self.name = name
self.age = age
self.color = 'white' # 直接定义属性,且该属性无需出现在()中;调用类时也无需再传入外部参数,此时已默认其属性值
def sit(self):
"""模拟小狗被命令时下蹲"""
print(self.name.title() + " is now sitting.")
def roll_over(self,n):
"""模拟小狗被命令时打滚n次"""
self.n = n
print(self.name.title() + " rolled over " + self.n + "times!")
  • __init__ : 初始化属性,此类方式在调用类时需传入外部参数

    有了init方法,在创建实例的时候,就不能传入空的参数了,必须传入与init方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:

  • self :在类中定义属性,第一个参数永远是self,表示创建的实例本身。因此,在方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

    即,将外部参数的属性传入到内部


创建 - 实例

因为类时一个抽象的概念,在创建具体的实例之前,必须先有一个容器;

1
2
3
4
5
6
# 已创建了默认属性
my_dog = Dog()
my_dog
# 未创建默认属性,而是初始化属性
my_dog = Dog('willie', 6) # 必须传入外部参数

访问

  1. 采用方法的方式来进行访问
1
2
3
4
my_dog.name
[out]: 'willie'
my_dog.roll_over(2)
  1. 限制访问
  • 要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
1
2
3
4
5
6
7
8
9
10
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
bart = Student('Bart Simpson', 98)

改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name和实例变量.__score了:

1
2
3
4
>>> bart.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
  • 获取限制访问的变量 :增加方法 - 给Student类增加get_name和get_score这样的方法
1
2
3
4
5
6
7
8
9
10
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
bart.get_name
  • 允许外部代码修改 : 增加方法 - set_score方法
1
2
3
4
5
class Student(object):
...
def set_score(self, score):
self.__score = score

需要注意的是,在Python中,变量名类似xxx的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用name、score这样的变量名。

有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。


修改属性

  1. 直接修改属性的值
1
my_dog.color = "black"
  1. 通过方法修改属性
1
2
3
4
5
6
7
class Dog():
--snip--
def update_color(self, color):
self.color = color
my_dog.color('black')


继承与重写

一个类继承另一个类时,会自动获得另一个类的所有属性和方法。原有的类:父类;新的类:子类;

  • 创建子类时,父类必须包含在当前文件夹,且位于子类的前面
  • 必须在括号内指定内类的名称
  • 使用super().__init__将父类和子类关联起来,使其包含父类的所有属性
1
2
3
4
5
6
7
8
9
10
11
class Car():
--snip--
class ElectricCar(Car): # 括号中为父类的名称
def __init__(self, make, model, year):
super().__init__(make, model, year) # 通过super().__init__将父类和子类关联,并获得父类的所有属性
self.batter_size = 70 # 可同时新建属性,同时指定默认值
# --------------重写父类中的方法---------------------------
def fill_gas_tank(): # 当定义的方法中括号中的内容为空,表示忽略该方法
print("This car doesn't need a gas tank.")

导入类

1
2
3
4
5
6
7
8
9
10
# 导入指定的类
from filename import classname1, classname2
from car import Car, ElectricCar
# 导入整个模块
import filename
# 导入模块中的所有类
from filename import *



##主要函数


对象类型

  1. type() - 判断对象类型
  2. instance() - 判断一个对象是否为某种类型:返回布尔值Ture/Falses
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 指定判断类型
>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
# 先创建判断的对象
>>> a = Animal()
>>> d = Dog()
>>> h = Husky()
>>> isinstance(h, Husky)
True
# 还可以判断一个变量是否是某些类型中的一种
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True

能用type()判断的基本类型也可以用isinstance()判断

  1. 获得对象的所有属性与类型 - dir()


字符串操作

替换 - replace

1
2
3
4
5
replace(old, new[, max]) # max,可选字符串, 替换不超过 max 次
relpace("a","b") # 将a替换为b
val.replace(",", "::")

分隔 - split - string转list

spilt - 通过指定的分隔符将字符串拆分为一组子串

  • 字符串会转为列表list
1
2
3
4
5
spilt(",") # 分隔后的字符串会转变为列表格式list
val = 'a,b, guido'
val.split(',')
# ['a', 'b', ' guido']

去空格 - strip

strip - 去除空格(含换行符),相当于对各个元素执行x.strip()

1
2
3
4
5
strip()
val.strip()
val.lstrip()
val.rstrip()

联接 - join - list转string

join - 联接其他字符串序列的分隔符

  • [列表转字符串]
1
2
3
4
','.join(val) # 将val转为string
"::".join(val) # 将::作为分隔符,联接对象val中的各个子串
## 转化之后,可将list转变为str


其他

1
2
3
4
count # 返回子串在字符串中出现的次数(非重叠)
startswith / endswith # 判断是否以某子串开始或结束,返回True或False
find / frind # 返回第一个/最后一个发现的第一个只字符所在的位置;若没有找到,则返回 -1 val.find(",")
index # 返回子串第一个字符所在的位置;若没有找到,引发 ValueError


函数 VS. 方法

若为方法,也直接在符合的对象之后进行引用。

  • DataFrame.xxx :数据框类型的对象
  • datetime.xxx:时间类型的对象


函数

函数function —— A series of statements which returns some value toa caller. It can also be passed zero or more arguments which may beused in the execution of the body.

  • 从定义的角度上看,函数(function)就相当于一个数学公式,它理论上不与其它东西关系,它只需要相关的参数就可以。所以普通的在module中定义的称谓函数是很有道理的。
  • 函数是一段代码,通过名字来进行调用。它能将一些数据(参数)传递进去进行处理,然后返回一些数据(返回值),也可以没有返回值。所有传递给函数的数据都是 显式传递 的。


方法

方法method —— A function which is defined inside a class body. Ifcalled as an attribute of an instance of that class, the methodwill get the instance object as its first argument (which isusually called self).

  • 方法,它是与某个对象相互关联的,也就是说它的实现与某个对象有关联关系。这就是方法。虽然它的定义方式和函数是一样的。也就是说,在Class定义的函数就是方法。
    • 方法的定义可以是这样的,与某个对象进行绑定使用的函数。注意哦。绑定不是指” .”这个符号,这个符号说实在的只有域名的作用。绑定在这里是指,会默认赋值该绑定的对象。
  • 方法也是一段代码,也通过名字来进行调用,但它跟一个对象相关联。方法和函数大致上是相同的,但有两个主要的不同之处:
    1. 方法中的数据是隐式传递的;
    2. 方法可以操作类内部的数据(请记住,对象是类的实例化 。类定义了一个数据类型,而对象是该数据类型的一个实例化)


  • 从上面可以看出, 别的编程语言一样, Function也是包含一个函数头和一个函数体, 也同样支持0到n个形参,而Method则是在function的基础上, 多了一层类的关系, 正因为这一层类, 所以区分了 function 和 method.而这个过程是通过 PyMethod_New实现的
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
PyObject *
PyMethod_New(PyObject *func, PyObject *self, PyObject *klass)
{
register PyMethodObject *im; // 定义方法结构体
im = free_list;
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
PyObject_INIT(im, &PyMethod_Type); // 初始化
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
if (im == NULL)
return NULL;
}
im->im_weakreflist = NULL;
Py_INCREF(func);
/* 往下开始通过 func 配置 method*/
im->im_func = func;
Py_XINCREF(self);
im->im_self = self;
Py_XINCREF(klass);
im->im_class = klass;
_PyObject_GC_TRACK(im);
return (PyObject *)im;
  • 以本质上, 函数和方法的区别是: 函数是属于 FunctionObject, 而 方法是属 PyMethodObject
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def aa(d, na=None, *kasd, **kassd):
pass
class A(object):
def f(self):
return 1
a = A()
print '#### 各自方法描述 ####'
print '## 函数 %s' % aa
print '## 类方法 %s' % A.f
print '## 实例方法 %s' % a.f
#输出结果:
#### 各自方法描述 ####
## 函数 <function aa at 0x000000000262AB38>
## 类方法 <unbound method A.f>
## 实例方法 <bound method A.f of <__main__.A object at 0x0000000002633198>>

【Bound Method 和 Unbound Method】

method 还能再分为 Bound Method 和 Unbound Method, 他们的差别是什么呢? 差别就是 Bound method 多了一个实例绑定的过程!
A.f 是 unbound method, 而 a.f 是 bound method, 从而验证了上面的描述是正确的!

详细参见:https://segmentfault.com/a/1190000009157792


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
>>> def fun():
pass
>>> type(fun)
<class'function'> #没有问题
>>> class Cla():
def fun():
pass
@classmethod
def fun1(cls):
pass
@staticmethod
def fun2():
pass
>>> i=Cla()
>>>Cla.fun.__class__
<class'function'> #为什么还是函数
>>>i.fun.__class__ #这个还像话
<class 'method'>
>>>type(Cla.fun1)
<class 'method'>   #这里又是方法
>>> type(i.fun1)
<class 'method'>    #这里仍然是方法
>>>type(Cla.fun2)
<class 'function'>   #这里却是函数
>>> type(i.fun2)
<class 'function'>    #这里却是函数
  1. 普通方法(老版中直接就是”instancemethod”)在module中与在Class中定义的普通函数,从其本身而言是没有什么区别的,他们都是对象函数属性。 之所以会被说在Class中的定义的函数被称为方法,是因为它本来就是面向将来的实例对象的,其实他们就是实例方法,这些方法是与实例相联系的(从实例出发访问该函数会自动赋值)。所以你从Class访问仍然是一个函数
  2. 类方法(”classmethod”),因为类同样是对象,所以如果函数与类进行联系了话(与实例方法一样的模式)那么就能够这么说了!
  3. 静态方法,虽然定义在内部,并且也较方法,但是却不与任何对象联系,与从类访问方法是一样的,他们仍然是函数。



【实战演练】

for循环

1
2
3
4
5
6
7
for i in range(1,4):
a = str(i) + '.' + i*'caihf'
print (a)
1.caihf
2.caihfcaihf
3.caihfcaihfcaihf


打开与写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
with open ('whodata.txt') as f:
a = f.readlines()
['This is a test.\n', '\n', 'Beautiful is better than ugly.\n', 'Explicit is better than implicit.\n', 'Simple is LbOMONEetter than complex.\n']
# ---------------------------
c=''
for i in range(0,len(a)):
b = str(i+1) + '.' + a[i]
c= b+c
print(c)
1.This is a test.
2.
3.Beautiful is better than ugly.
4.Explicit is better than implicit.
5.Simple is LbOMONEetter than complex.
6.Complex is better than complicated.
Jimmy那些事儿

数据分析 vs. 数据挖掘

发表 2017-05-16 | 更新 2018-02-21 | 分类 数据分析 | 阅读次数

Surface data, not mining it(呈现数据,而非挖掘)

阅读全文 »
Jimmy那些事儿

atom_设置

发表 2017-05-05 | 更新 2018-02-13 | 分类 软件应用 , 程序编程 , atom | 阅读次数

插件备份与还原

官方插件管理方式;( 登录 https://atom.io/)

首先你需要拥有一个 Github 账户,在 atom.io 看到什么好插件,只需点击 star 收藏。某天,你想一次把收藏插件全部安装,只需执行命令:

1
2
3
win + R > cmd
apm install stars # 会提示你输入自己的 token

按照提示一步一步来就可以。更多操作执行 apm stars --help 查看。

阅读全文 »
Jimmy那些事儿

R语言_自动化

发表 2017-05-02 | 更新 2018-02-13 | 分类 软件应用 , 程序编程 , r | 阅读次数

R实现自动化 - knitr 、 rmarkdown

阅读全文 »
Jimmy那些事儿

《企业生命周期》读书笔记_爱迪思

发表 2017-05-01 | 更新 2018-02-13 | 分类 阅读书籍 | 阅读次数

《企业生命周期》_[美] 伊查克 • 爱迪思

《Managing Corporate Lifecycles 》_Ichak Adizes; 写于1996

在生命周期某一阶段属正常的问题有可能在另外一个阶段就是不正常的。

(未完)

阅读全文 »
Jimmy那些事儿

Hexo+Github搭建个人博客

发表 2017-04-23 | 更新 2018-02-13 | 分类 软件应用 , 程序编程 , hexo | 阅读次数

Hexo+Github搭建个人博客

title-picture
  前段时间本人利用业余时间,在网上查询各种资料,使用Hexo+Github的方式搭建起了我个人的博客——BrightLoong。相信网上已经有无数前辈写了类似的文章来记录如何搭建博客的过程和步骤,我也不哗众取宠或者班门弄斧了,把我在搭建博客中使用 资料做一个收集,同时也将我在搭建博客过程中遇到的坑列举出来,以及对应的解决方法,也是对搭建博客过程的一个记录,毕竟好记性不如烂笔头。那话不多说,接下来就是一个简单的介绍以及如何搭建的步骤(本文基本也是安照官方的步骤在介绍,我只是在有些地方记了下自己踩过的坑,强烈建议大家跟着Hexo官方文档操作)。

本文适用于Windows搭建

什么是Hexo

  在Hexo官网上如此描述:Hexo is a fast, simple and powerful blog framework. You write posts in Markdown (or other languages) and Hexo generates static files with a beautiful theme in seconds.(Hexo是一个快速,简单和强大的博客框架。你可以使用Markdown(或其他语言)写博客,之后Hexo能在几秒钟生成具有美观主题的静态文件。)如果你想了解更多关于Hexo的东西,请移步Hexo官网。
  Hexo是一款基于Node.js的静态博客框架,可以deploy到Github上,所以首先要在电脑上安装git和node.js,并在Github上注册自己的账号,由于这些东西不是本篇博客要涉及到的主要内容,你可以谷歌、百度,也可以参考我下面提供的链接。

Git安装

  你可以去官网下载Git,因为国外资源可能很慢,你也可以下载我在网盘上提供的Git镜像。具体如何使用,请参照廖雪峰老师关于Git的教程,如果你仅仅是想安装git那看看Git安装的那个章节

Node.js安装配置

  关于Node.js的安装以及配置,可以参照菜鸟教程上面关于Node.js安装配置的教程,上面也有下载的链接,本人就是参照上面安装的。具网上有些文章说,安装完成后最好重启电脑,以免之后无法使用hexo的相关命令,我倒是没有遇到,不过如果大家遇到这种问题就重启吧。

Hexo安装

  必须要在你安装了上述的Git以及Node.js之后才能进行Hexo的安装。

1. 用以下命令安装Hexo

  在任意地方点击右键,选择Git Bash Here

1
$ npm install -g hexo-cli

  如果安装过程中遇到一下错误:

1
ERROR Deployer not found : github

  运行

1
$ npm install hexo-deployer-git --save

2. 创建博客存放目录,并进行初始化,安装依赖包(最好不要使用带中文的路径,以免后面出现不必要的麻烦)

  打开一个目录,在这个地方点击右键选择Git Bash Here,执行以下命令

1
2
3
$ hexo init <folder> #创建目录并执行初始化
$ cd <folder>
$ npm install #安装依赖包

<folder>改为你想要的目录。
  当然你也可以自己新建一个目录,比如我在F盘中创建了myblog目录,进入目录中点击右键选择Git Bash Here,直接执行以下命令

1
2
$ hexo init
$ npm install

  不管你用哪种方式,执行完毕后你会发现以下目录结构

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes

3. 启动服务

  执行以下命令来启动服务

1
2
$hexo g #hexo generate,生成静态文件
$ hexo s #hexo server,启动本地服务器

  如果启动过程中没有报错,此时你用浏览器访问http://localhost:4000/,是不是看到了一个Hello World的博客页面,hexo3.0使用的默认主题是landscape(之后我会讲如何更换主题,以及集成第三方的工具),而且此时的服务是本地启动的,别人并不能看到(继续我接下来的操作就好了)。
  这个时候如果在浏览器没看到漂亮的博客页面怎么办,别急,先确认你在启动过程中是不是报错了,如过有的话估计是上面的操作有误,如果没有并且发现页面一直在加载中,估计是端口被占用了,我就遇到了这个问题。怎么办?把4000端口给杀死,还有更简单的——在hexo s命令后面加上启动参数,修改默认端口:hexo s -p <port>,比如我用的 hexo s -p 8000,现在重新访问http://localhost:8000/记得把地址的8000改成你自己对应的端口号,是不是看到了美丽的界面。

4. 注册Github账号,并创建仓库。

  想要别人也访问到你的页面,跟着继续吧。首先在Github官网上注册一个账号,有账号的跳过注册,直接登录。登录后找到new repository按钮创建一个新的仓库。

new repository

  然后填写repository name就行了,要注意的是:这个名字的格式必须为youname.github.io,并且必须和你的账户名相同,比如我的账户名是BrightLoong,我的地址就是brightloong.github.io(最开始我就是将name随意填写,虽然是这个格式但是根本访问不了,会报404的错误)。
creat repository

5. 将本地文件推送到github

  最后,剩下的就是将本地文件推送到github上了,首先打开站点配置文件_config.yml,比如我的路径是:F:\myblog_bonfig.yml。找到最后的deploy属性,如果没有就自己添加,将配置修改为:

1
2
3
4
deploy:
type: git #推送方式
repository: https://github.com/BrightLoong/BrightLoong.github.io.git #你的推送地址
branch: master #你要推送的分支

这个地方要注意的是属性后面的冒号必须要有一个空格,否则会报错

  配置好之后使用以下命令将服务部署到github上。

1
2
3
$ hexo clean
$ hexo g
$ hexo d

  使用hexo d命令,第一次会要求你输入用户名和密码,用户名和密码就是你注册github时候使用的用户名和密码。如果遇到以下错误:

1
ERROR Deployer not found : github

  运行

1
$ npm install hexo-deployer-git --save

  再执行上面的命令。

1
$ npm install hexo-deployer-git --save

  如果你没有配置Github的SSH,那么可能需要配置一下,你可以用以下命令查看一下

1
ssh -T git@github.com

  如果成功会有以下提示(我的账户名叫BrightLoong)

1
Hi BrightLoong! You've successfully authenticated, but GitHub does not provide shell access.

  如果没有,可以参考博客git添加ssh-key查看config。

  如果没有报错误,那么博客就已经搭建起来,并发布到Github上了,在浏览器输入youname.github.io就能看到自己的博客了,如果中途报错说未识别的用户名,那么如果你确定你填写是正确的,重复使用hexo d命令,我当时就遇到过这种情况,我估计是网络不好引起的。

配置&主题

发布新的博客

  既然博客已经搭建好了,那么不发几篇博文有就没有意义了,使用下面的命令来新建一篇叫做”brightloong”的文章。

1
hexo new 'brightloong'

  命令执行之后,你会在你文件博客根目录的source/_post目录下找到你刚刚新建的md后缀的文件,比如我的是F:\myblog\source_posts\brightloong.md,hexo博客是使用markdown语法来书写的,如果不熟悉markdown语法可以快速的看一下markdown语法说明,或者是认识与入门Markdown,后者也有推荐一些不同平台下使用的编辑Markdown的工具,本人使用的是Cmd Markdown,它既支持在线的编辑,也可以下载下来使用。生成的md文件打开如下:

注意:在冒号后面一定要加上一个空格,否则在生成静态文件的时候会报错,并且也不能将其成功推送到github。

1
2
3
4
5
6
---
title: brightloong #文章标题
date: 2017-02-24 12:03:12 #创建时间
tags: #文章标签,如果有多个标签可以使用[1,2,3]的形式,还有其他形式自己摸索吧
---
#这之后是正文

  文章编写好之后,只用以下命令生成静态文件并推送到github上,执行完成后打开自己的博客页面,是不是发现刚刚编写的文章出现了;如果你想删除某一篇文章,那么在source/_post目录下找到对应的文章将其删除后,同样执行一下命令就OK了。

1
2
3
4
5
6
7
hexo g
hexo s # 在本地预览
hexo clean
hexo g
hexo d

站点配置文件_config.yml

  站点配置文件_config.yml是在你博客保存目录的根目录下,注意将它与主题配置文件进行区分,比如我保存的博客目录为F:\myblog那么我站点配置文件为F:\myblog_config.yml,我使用的主题是Next主题,所以我的主题配置文件为F:\myblog\themes\next_config.yml。下面我先介绍下站点配置文件,我将一些主要的配置做了注释,如果你想了解更多的配置的含义和作用,请访问Hexo官方教程查看。

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
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/
# Site
title: BrightLoong's Blog #博客的标题
subtitle: #子标题
description: Remember what should be remembered, and forget what should be forgotten.Alter what is changeable, and accept what is mutable. #博客描述,可以是一段你喜欢的话,也可以是你博客的描述,只要你开心就好。
author: BrightLoong #作者
language: zh-Hans #语言(我使用的是简体中文)
timezone: #时区(默认使用电脑时间)
##之下的保持默认就好,没有什么需要更改的
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' #and root as '/child/'
url: https://brightloong.github.io
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:
# Directory
source_dir: source #source目录
public_dir: public
tag_dir: tags #标签目录
archive_dir: archives
category_dir: categories #分类目录
code_dir: downloads/code
i18n_dir: :lang
skip_render: static/** #注意这个属性(跳过渲染),你暂时不用配置,我之后会讲到,这个也是我遇到的坑
##之下的保持默认就好,没有什么需要更改的
# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
external_link: true # Open external links in new tab
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace:
# Category & Tag
default_category: uncategorized
category_map:
tag_map:
# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss
# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: next #你设置的主题,接下来我会说到这个
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repository: https://github.com/BrightLoong/BrightLoong.github.io.git
branch: master

主题更换

  搭建自己的博客,最吸引人的莫过于那千变万化的主题了,大家可以在Hexo官网上看到无数漂亮、大方、简洁的主题。本人使用的是简洁的Next主题,你可以选择你喜欢的下载下来,将其解压放入themes目录中,比如我的目录是F:\myblog\themes,然后修改我在上面提到的站点配置文件中的theme属性,为你刚刚放入themes目录中文件的名字(最好是对解压文件修改一个名字,否则名字可能会比较长,我把我下载下来的主题改文了next),做完这些之后并不代表你完成了,你还需要参考你所下载的主题所说的配置步骤进行相关的配置,由于不同的主题配置过程也尽不相同,大家根据自己下载的主题去配置,我在这里只说我使用的Next主题如何配置。

1
theme: next

注意:从下面开始所说的都是Next主题的相关配置。

配置Next主题

  如果你使用的和我一样,也是Next的主题,那么你最好还是看官方提供Next使用文档,并且文档是中文版的,我也仅仅是讲一些容易被忽略的配置,以及我使用的配置,以及在使用过程中遇到的问题;至于如何更换头像,添加分类和标签页面、切换主题样式(Next主题包含3中样式)之类的,大家还是照着官方的做更好。

1. 配置网站图标

  如何让网站前能显示自己想要的图标,我当时也是找了很久,最后发现是在主题配置文件(我的是F:\myblog\themes\next_config.yml)的最前面,有一个favicon属性,我把一个名字叫favicon.ico的图片(通过在线生成ico的网站)放到了F:\myblog\source下,然后配置如下:

1
favicon: /favicon.ico

website ico

2. 首页显示阅读全文按钮

  首页的文章是不是默认展开了,显示出了整篇文章,怎么才能显示出如下的阅读全文的按钮。
button
在主题配置文件中找到auto_excerpt属性进行配置

1
2
3
auto_excerpt:
enable: true #改写为true
length: 150 #默认展示的高度

你也可以在自己的博文中添加来决定在首页展示到什么位置(我就喜欢用这种方式),这个标签后的内容就不会展示到首页啦。

3. 集成多说评论

  登录多说,登录后在首页选择“我要安装”。创建站点,填写表单。多说域名 这一栏填写的即是你的 duoshuo_shortname,如图:
duoshuo
  创建站点完成后在 站点配置文件(我的是F:\myblog_config.yml) 中新增 duoshuo_shortname 字段,值设置成上一步红框中的值。

注意:新增字段的时候一定不要让字段前面有空格,否则会被认为是子字段,无法正确解析

1
2
#多说评论
duoshuo_shortname: brightloong #设置为红框中的值

  多说评论中可以开启热评文章,在站点配置文件中增加字段:

1
duoshuo_hotartical: true

开启后你可能会发现点击热评文章并不能跳转到对应的网页,进入多说后台查看,发现原来网址不正确,那简单,点击编辑修改成正确的网址就OK了。
duoshuo_hot

4. 阅读次数统计

  次数统计又leancloud提供,请参考由由Doublemine 贡献提供的为Next主题添加阅读次数统计功能
leancloud

5. 集成百度分享

  分享功能的集成是最坑的没有之一,我大概花了半天多的时间查找各种方法才将其解决,这里我先说官网的配置:编辑 站点配置文件,添加字段 baidushare,值为 true。

1
baidushare: true #百度分享功能

  欢欢喜喜的打开自己的博客。咦!百度分享功能咋没有添加上啊。不急,听我慢道来。我在主题文件中发现一个文件
F:\myblog\themes\next\layout_partials\share\baidushare.swing,内容如下

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
{% if theme.baidushare.type === "button" %}
<div class="bdsharebuttonbox">
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a>
<a href="#" class="bds_douban" data-cmd="douban" title="分享到豆瓣网"></a>
<a href="#" class="bds_sqq" data-cmd="sqq" title="分享到QQ好友"></a>
<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a>
<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a>
<a href="#" class="bds_tieba" data-cmd="tieba" title="分享到百度贴吧"></a>
<a href="#" class="bds_twi" data-cmd="twi" title="分享到Twitter"></a>
<a href="#" class="bds_fbook" data-cmd="fbook" title="分享到Facebook"></a>
<a href="#" class="bds_more" data-cmd="more"></a>
<a class="bds_count" data-cmd="count"></a>
</div>
<script>
window._bd_share_config = {
"common": {
"bdText": "",
"bdMini": "2",
"bdMiniList": false,
"bdPic": ""
},
"share": {
"bdSize": "16",
"bdStyle": "0"
},
"image": {
"viewList": ["tsina", "douban", "sqq", "qzone", "weixin", "twi", "fbook"],
"viewText": "分享到:",
"viewSize": "16"
}
}
</script>
{% elseif theme.baidushare.type === "slide" %}
<script>
window._bd_share_config = {
"common": {
"bdText": "",
"bdMini": "1",
"bdMiniList": false,
"bdPic": ""
},
"image": {
"viewList": ["tsina", "douban", "sqq", "qzone", "weixin", "twi", "fbook"],
"viewText": "分享到:",
"viewSize": "16"
},
"slide": {
"bdImg": "5",
"bdPos": "left",
"bdTop": "100"
}
}
</script>
{% endif %}
<script>
with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/static/api/js/share.js?cdnversion='+~(-new Date()/36e5)];</script>

  注意到最开始的语句了吗if theme.baidushare.type === “button”,以及之后的else if theme.baidushare.type === “slide”什么意思,在theme下也就是主题配置文件中,baidushare字段下的type字段,我们打开主题配置文件(我的是F:\myblog\themes\next_config.yml),这个配置是不是被注释掉了:

1
2
baidushare:
type: button #百度分享展示的方式button|slide

  修改之后,再启动,发现还是没有(如果你是用的本地启动用local的方式访问可能会看到百度分享功能已经出现了),这个是后打开浏览器F12的调试功能,是不是发现控制台报错了,提示你从https中去访问http的资源是不行的。不知道大家有没有看到刚刚我们修改的主题配置文件中,在上面有一段注释:

1
2
3
# Warning: Baidu Share does not support https.百度分享不支持https
baidushare:
type: button

是的不支持https的方式,自己的域名是用https开头的(除非你自己购买了域名,如何购买更换域名请大家参考【Hexo+Github】域名和github绑定的问题)。并且,JiaThis等都不支持https,怎么办?


1…678…13
Jimmy_Cai

Jimmy_Cai

向死而生。做一个有品质的单身汪。

128 日志
23 分类
23 标签
RSS
简书 知乎 GitHub 微博
© 2021 Jimmy_Cai
由 Hexo 强力驱动
主题 - NexT.Mist