数据分析入门到实战-金融量化分析

thu-blogger
清华大学电子系,获得了本科和博士学位。毕业之后一直在国内外知名的对冲基金从事量化投资相关的工作,熟悉Python在金融数据分析和量化投资的应用。撰写这个专刊,在帮助自己温故知新的同时,能够帮助到想要从事金融数据分析工作的学生或是打算转到量化投资行业的在职人士。
立即订阅 2161学习

第2章 第2节 Python语法基础(上)

去手机阅读

在这一部分,我们介绍Python最基础的语法知识。尽管网上关于Python的入门教程浩如烟海,在这一节我们只介绍最基本和最常见的语法。

基本语法

1.0 第一个Python程序

首先我们以最常见的打印Hello world为例,举一个最简单的Python代码:

print('Hello world')

运行这段代码后,就会看到notebook中的输出为Hello world
图片说明

如果直接输入'Hello world'这个字符串,Notebook也会有默认的输出:
图片说明

然而这种方式的输出只能显示每一段代码中最后一个变量的值,因此之后不加说明的话,我们都会使用print语句来显示程序的运行结果

1.1 代码的组织形式

与其它语言,比如C++和JAVA那样使用括号来组织代码不同,Python使用空白字符(包括tab键和空格键)来组织代码。

for x in range(10):
    print(x)

在上面的代码中,冒号标志着缩进代码块的开始,冒号之后的所有代码的缩进量必须相同,直到代码块结束;一般建议用4个空格作为默认的缩进。

再看一段代码:

a = 1; b = 2; c = 3

一般情况下,Python的语句不需要用分号结尾。分号可以用来给同在一行的语句切分,但是不建议将多条语句放到一行,这会降低代码的可读性。因此推荐下面这种多行的写法:

a = 1
b = 2
c = 3

任何前面带有井号#的文本都会被Python忽略,可以用来添加注释。有时,你会想排除一段代码不要运行,但并不删除,最简便的方法就是将其注释掉。

# print(a)
print(b)
print(c)

注释也可以写在代码的后面:

print(a)  # 我把注释放在了代码后面

如果一行代码太长怎么办?Python中可以使用反斜杠\续行,也就是下面两种写法是等价的:

s1 = 'I am very very very very very very very very very very very very very very very very very very very very very very long'
s1 = 'I am very very very very very very very very very very \
very very very very very very very very very very very very long'

1.2 数据类型和变量

1.2.1 变量

变量的概念跟我们代数中的变量相同,不仅可以表示具体的数值、某个字符串,还可以表示我们自定义的任意数据类型。变量在Python中通过一个变量名表示,变量名必须是大小写英文、数字和下划线(_)的组合,并且需要注意:(1)可以单独用英文字母或者下划线作为变量名,同时英文字母需要注意区分大小写;(2)数字不能单独用于变量名;(3)变量名不能用数字开头;(4)变量名尽量简洁易懂。举例如下:

a = 1  # 变量a是一个整数。
t_007 = 'T007'  # 变量t_007是一个字符串。
Answer = True  # 变量Answer是一个布尔值True。

在Python中,等号=是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,举例如下:

a = 123  # a是整数
a = 'ABC'  # a变为字符串

这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。和静态语言相比,动态语言更灵活(但有些时候也意味着更加容易犯错)。
我们也可以将一个变量赋值给另一个变量。由于在一个变量创建的过程中,例如执行a='ABC',Python解释器首先会在我们计算机的内存中创建一个'ABC'的字符串,然后在内存中创建一个名为a的变量,并把它指向'ABC'。可以联系C语言中的指针概念。

a = 'ABC'
b = a
a = 'XYZ'
print(b)

这段代码的输出结果为:

ABC

在执行a = 'ABC'时,Python解释器创建了字符串'ABC'和变量a,并把a指向了'ABC':
图片说明
执行b = a,解释器创建了变量b,并把b指向a指向的字符串'ABC':
图片说明
执行a = 'XYZ',解释器创建了字符串'XYZ',并把a的指向改为'XYZ',但b并没有更改:
图片说明
所以,最后打印变量b的结果自然是'ABC'了。

与变量相对应的,常量就是不能变的变量,比如常用的数学常数π就是一个常量。在Python中,通常用全部大写的变量名表示常量:

PI = 3.14159265359

但本质上PI仍然是一个变量,Python根本没有任何机制保证PI不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量PI的值,也没人能拦住你。

1.2.2 数值类型

在Python中,主要数值类型是int和float:

  • int: 任意精度整数;
  • float: 双精度(64位)浮点数(注意没有double类型)。

int数值可以存储任意大的数:

big_value = 1234567891011121314151617181920
print(big_value)

输出为:

1234567891011121314151617181920

float数值也可以用科学计数法表示:

a = 1314.15
print(a)
a = 1.31415e3
print(a)

输出为:

1314.15
1314.15

需要注意当我们在一个整数后面加上一个小数点,那么它就是一个float数值:

a = 1  # 这里a是int数值
a = 1.  # 这里a是float数值

数值变量之间可以进行加减乘除等二元操作:

a = 3
b = 2
print(a + b)  # 推荐二元运算符前后各加一个空格
print(a - b)
print(a * b)
print(a / b)
print(a // b)  # a除以b,结果只取整数部分
print(a ** b)  # a的b次幂,注意和乘法的区别

输出为:

5
1
6
1.5
1
9

1.2.3 布尔值

Python中的布尔值有两个,True和False,举例如下:

a = True
b = False
print(a)
print(b)

输出为:

True
False

除了直接定义,布尔值变量也可以从比较表达式产生:

a = 3 == 2  # ==表示是否等于
b = 3 != 2  # !=表示是否不等于
c = 3 > 2
d = 3 >= 2
print(a)
print(b)
print(c)
print(d)

输出为:

False
True
True
True

布尔值变量还可以从逻辑表达式中产生,举例如下:

a = True
b = False
print(not a)  #取反操作
print(a & b)  #与操作
print(a and b)  #与操作,与上面等价
print(a | b)  # 或操作
print(a or b)  # 或操作,与上面等价
print(a ^ b)  # 异或操作

输出为:

False
False
False
True
True
True

布尔值变量会用于各种条件判断中:

a = True
if a is True:  # 尽管这里也可以写成a == True,但对于布尔值变量,建议用关键字is
    print(a)

if a is not False:
    print(a)

输出为:

True
True

1.2.4 空值类型

None是Python的空值类型:

a = None
if a is None:
    print(a)
    print(type(a))

输出为:

None
<class 'NoneType'>

None变量会用于变量的初始化,函数的默认参数,函数的默认返回值等。

1.2.5 字符串类型

Python具有强大而灵活的字符串处理能力。Python的字符串类型是str,你可以用单引号或双引号来定义字符串:

a = 'this is a string'
b = "this is another string"
print(a)
print(b)

输出为:

this is a string
this is another string

对于有换行符的字符串,可以使用三引号,'''或"""都行:

c = '''
This is a string
with mutiple lines.
'''
print('c is')
print(c)

输出为:

c is

This is a string
with mutiple lines.

如果你的字符串里面本身有单引号或者双引号:

a = "this's a string"
b = 'this is "another" string'
print(a)
print(b)

# 另一种方式,采用反斜杠
a = 'this\'s a string'
b = "this is \"another\" string"
print(a)
print(b)

输出为:

this's a string
this is "another" string
this's a string
this is "another" string

要计算字符串中包含多少个字符,可以用len()函数:

c = '''
This is a string
with mutiple lines.
'''
print(len(c))

输出为:

38

我们可以使用list函数来查看一个字符串中的具体字符:

c = '''
This is a string
with mutiple lines.
'''
print(list(c))

输出为:

['\n', 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 's', 't', 'r', 'i', 'n', 'g', '\n', 'w', 'i', 't', 'h', ' ', 'm', 'u', 't', 'i', 'p', 'l', 'e', ' ', 'l', 'i', 'n', 'e', 's', '.', '\n']

注意字符串c中包含特殊字符:换行符\n。在python中,反斜杠是转义字符,意思是它被用来表示特殊字符,比如换行符\n和制表符\t。所以在之前的定义方式中,字符串c一共包含了三行内容,第一行只有一个换行符。我们也可以用count函数来计算某一个字符出现的次数。

c = '''
This is a string
with mutiple lines.
'''
print(c.count('\n'))

输出为:

3

重新定义字符串c,体会一下差别:

c = '''This is a string
with two lines.
'''
print(c.count('\n'))

输出为:

2

前面提到,反斜杠是转义字符。那么如果字符串中本身就含有反斜杠呢?一种处理方式是使用连续的两个反斜杠:

a = 'this is a string\n'
print(a)
a = 'this is a string\\n'
print(a)

输出为

this is a string

this is a string\n

如果一个字符串中含有很多反斜杠,但不包含转义字符,那么我们可以在字符串前面加一个r,表明字符就是它自身:

a =  r'this is a string\n'
print(a)

输出为:

this is a string\n

如果我们要取一个字符串的部分内容作为一个新的字符串,那我们可以利用切片:

a = 'this is a string'
print(len(a))
b = a[0]  # 我们选取了a的第1个字符,即t;注意在Python中,无论是字符串还是后面介绍的其他支持切片操作的数据结构,下标都从0开始计数
print(b)
b = a[:4]  # 我们选取了a的第1个到第4个字符,其中第1个字符包含在b中,第5个字符不包含在b中,也就是说Python中的切片是前闭后开
print(b)
b = a[0:4]  # 等价于b=a[:4]
print(b)
b = a[4:]  # 我们选取了a的第5个字符之后的所有字符
print(b)
b = a[4:20]  # 尽管这里我们可以设置超过a的长度的数值,Python没有报错,但建议用上面那种形式
print(b)
b = a[-6:]  # Python也支持负数计数的切片下标,例如取最后6个字符串,等价于b = a[10:]
print(b)
b = a[10:]
print(b)

输出为:

16
t
this
this
 is a string
 is a string
string
string

利用replace函数,我们也可以替换一个字符串的部分内容,从而定义出另一个字符串。

a = 'This is the first string'
b = a.replace('first', 'second')  # 'first'是a中被替换的部分,'second'是用来替换的部分
print(a)
print(b)
a = 'This is the first string'
b = a.replace('is', 'iss')  # replace会替换所有出现的is,使用的时候需要留意
print(b)

输出为:

This is the first string
This is the second string
Thiss iss the first string

数值类型或者其他类型也可以通过str函数变成字符串类型。我们可以用type函数来查看具体的类型。

a = 1
a_str = str(a)
print(type(a))
print(type(a_str))

输出为:

<class 'int'>
<class 'str'>

Python提供了两个字符串直接相加,得到一个新的字符串的功能。

a = 'this is a string'
b = 'this is another string'
c = a + b
print(a)
print(b)
print(c)

c = ' '.join([a, b])
print(c)

输出为:

this is a string
this is another string
this is a stringthis is another string
this is a string this is another string

调用str函数不一定能够得到我们想要的字符串表示形式。Python提供了字符串的模板化或格式化功能,通过百分号实现,举例如下:

a = 'Hello, %s' % 'world'
print(a)
a = 'Hi, %s, you have $%d.' % ('Michael', 1000000)
print(a)

输出为:

Hello, world
Hi, Michael, you have $1000000.

在上面的例子中,%运算符就是用来格式化字符串的。在字符串内部,%s表示用字符串替换,%d表示用整数替换,%f表示用浮点数替换。有几个%?占位符,后面就跟几个变量或者数值,顺序要对应好。如果只有一个%?,括号可以省略。其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数:

a = 'the number is %.4f' % 123.45678  #这里%.4f指定了小数部分保留4位
print(a)
a = 'the number is %.8f' % 123.45678  #如果小数位数不足,Python会补0
print(a)
a = 'the number is %5.f' % 123.45678  #这里%5.f指定了整数部分保留5位,小数部分默认不保留,Python会在前面补上空格,可以用于数据显示的对齐
print(a)
a = 'the number is %2.4f' % 123.45678  #如果整数部分指明的位数小于实际的数值,以实际的数值为准
print(a)

输出为:

the number is 123.4568
the number is 123.45678000
the number is   123
the number is 123.4568

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

a = 'the number is %s' % 123.45678
print(a)

输出为:

the number is 123.45678

与前面出现的情况类似,如果字符串中本身就包含了%,那么可以用两个连续的%%表示:

a = 'the number is %s%%' % 123.45678
print(a)

输出为:

the number is 123.45678%

另一种格式化字符串的方法是使用字符串的format函数,它会用传入的参数依次替换字符串内的占位符{0}、{1}……,不过这种方式写起来比%要麻烦得多,举例如下:

template = '{0:.2f} {1:s} are worth US${2:d}'
# {0:.2f}表示格式化第一个参数为带有两位小数的浮点数。
# {1:s}表示格式化第二个参数为字符串。 
# {2:d}表示格式化第三个参数为一个整数。
a = template.format(4.5560, 'Argentine Pesos', 1)  # 传入对应的具体数值,替换模板template中的占位符
print(a)

1.3 运算符号

1.3.1 基本算术运算符号

Python中包含加法、减法、乘法、除法、幂运算、模运算(取余数)、整除等基础的算术运算。在加法、减法、乘法以及幂运算中,需要注意:

  • 整型和整型之间的运算,得到的结果是整型;
  • 整型与浮点型之间的运算,得到的结果是浮点型;
  • 浮点型与浮点型之间的运算,得到的结果是浮点型。

需要注意的是,除法是一个例外,在Python 2.X版本中,整型除以整型,只能得出整型。而在Python 3.X版本中,得到的除法结果一律是浮点型。

基本算术运算符合举例如下:

print(2 + 3)
print(8 - 7)
print(2 * 1.5)
print(5 ** 2)  # 这里是5的2次方
print(5 / 2)  # 结果是浮点数
print(5 % 2)  # 模运算取余数
print(5 // 2)  # 整除会向下取整

输出为:

5
1
3.0
25
2.5
1
2

1.3.2 关系运算符号

Python中包含了等于、不等于、大于、大于等于、小于、小于等于这六类关系运算符号:

print(2 == 2)  # 等于
print(2 != 3)  # 不等于
print(3 > 2)  # 大于
print(3 >= 2)  # 大于等于
print(2 < 3)  # 小于
print(2 <= 3)  # 小于等于

这些例子输出结果都是True。

1.3.3 成员运算符号

Python的成员运算符号in和not in可以判断一个变量是否在指定的另一个变量(列表、元组、字符串等)中找到相应的值:

print(1 in [1, 2, 3])
print(1 not in [1, 2, 3])  # not in的结果和in相反

输出为:

True
False

1.4 控制流

Python有若干内建的关键字进行条件逻辑、循环和其它控制流操作。这些操作不仅让Python可以实现更多的功能,也增加了代码的可读性。

1.4.1 if、elif和else

if检查一个变量或者语句,如果为True,就执行后面的语句,否则会跳过:

a = 3
if a > 2:  # if语句后面加上一个语句
    print('condition 1 holds')
if a > 3:
    print('condition 2 holds')

b = True
if b:  # if语句后面加上一个变量
    print('condition 3 holds')
c = 1
if c:  # 不为0的数值默认转换为True(建议避免这种默认转换的情况,采用更明确的比较语句)
    print('condition 4 holds')
d = 0
if d:  # 为0的数值默认转换成False
    print('condition 5 holds')

输出为:

condition 1 holds
condition 3 holds
condition 4 holds

if后面可以跟一个或多个elif,所有条件都是False时,还可以添加一个else:

a = 1
if a > 2:
    print('condition 1 holds')
elif a > 1:
    print('condition 2 holds')
else:
    print('condition 3 holds')

输出为:

condition 3 holds

在这个例子中,如果某个条件为True,后面的elif就不会被执行。

在if的判断语句中,当使用and和or时,复合条件语句是从左到右执行:

a = 1
b = 2
c = 4
d = 3
if a < b or c > d:
    print('condition holds')

输出为:

condition holds

在这个例子中,c > d不会被执行,因为第一个比较a < b是True。

if-else语句也可以通过三元表达式放到一行里,举例如下:

a = 3
print('True') if a > 2 else print('False')

输出为:

True

如果a>2成立,就会执行print('True'),否则会执行print('False')。虽然使用三元表达式可以压缩代码,但会降低代码可读性。

1.4.2 range函数

range函数返回一个迭代器,它产生一个均匀分布的整数序列:

print(range(10))
print(list(range(10)))

输出为:

range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range(10)返回的结果是range(0,10)这个迭代器。要查看对应的具体数值,我们可以调用list函数。

range的三个参数是(起点,终点,步进):

print(list(range(10)))  # 当只有一个参数时,默认从0开始,到终点结束(但不包括终点)
print(list(range(1, 10)))  # 当有两个参数时,代表了起点和终点
print(list(range(1, 10, 2)))  # 三个参数是最完整的情况
print(list(range(10, 1, -2)))  # 步进也可以是负数,只要此时起点大于终点,同样会生成一个递减的整数序列

输出为:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 3, 5, 7, 9]
[10, 8, 6, 4, 2]

1.4.3 for循环

for循环是在可迭代的对象(包含字符串、range函数生成的迭代器、后面会讲到的列表、元组、字典的键值对等)中进行迭代。举例如下:

a = 'this is a string'
for s in a:  # 打印字符串a中的每一个字符
    print(s)

for i in range(5):  # 打印一个整数序列中的值
    print(i)

输出为:

t
h
i
s

i
s

a

s
t
r
i
n
g
0
1
2
3
4

可以用关键词continue使for循环提前,跳过剩下的部分:

a = 'this is a string'
for s in a:
    if s == ' ':  # 如果碰到空格,跳过
        continue
    print(s)

输出为:

t
h
i
s
i
s
a
s
t
r
i
n
g

可以用关键词break跳出for循环:

a = 'this is a string'
for s in a:
    if s == ' ':  # 如果碰到空格,跳出for循环,结束打印过程
        break
    print(s)

输出为:

t
h
i
s

当有多层循环存在时,continue和break只会中断它对应的for循环,其余的for循环仍然会运行(注意代码中的缩进代表的内层和外层循环关系):

for i in range(3):
    for j in range(4):
        if j > 2:
            break
        print('j: %d' % j)
    print('i: %d\n' % i)

输出为:

j: 0
j: 1
j: 2
i: 0

j: 0
j: 1
j: 2
i: 1

j: 0
j: 1
j: 2
i: 2

1.4.4 while循环

while循环指定了条件和代码,当条件为False或用break退出循环,代码才会退出:

a = 10
while a > 4:
    print(a)
    a -= 1

输出为:

10
9
8
7
6
5

1.4.5 pass语句

pass是Python中的非操作语句。代码块不需要任何动作时可以使用(作为未执行代码的占位符);因为Python需要使用空白字符划定代码块,所以需要pass:

x = 0
if x < 0:
    print('negative!')
elif x == 0:
    # TODO: put something smart here
    pass
else:
    print('positive!')

pass语句不会产生输出。

小结

在这一部分,我们介绍了Python基本的代码组织形式,特别是利用缩进来表示代码层次的方式需要大家适应一下;然后我们介绍了Python中常用的控制流语句,例如if、while、for语句等。

qrcode
下载牛客APP随时随地学习