1.简介
Python是一种什么样的语言?
它是一种面向对象的解释型计算机程序设计语言。Python语法简洁清晰,特色之一是强制用空白符(white space)作为语句缩进。
Python具有丰富和强大的库。它常被昵称为胶水语言,能够把用其他语言制作的各种模块(尤其是C/C++)很轻松地联结在一起。常见的一种应用情形是,使用Python快速生成程序的原型(有时甚至是程序的最终界面),然后对其中有特别要求的部分,用更合适的语言改写,比如3D游戏中的图形渲染模块,性能要求特别高,就可以用C/C++重写,而后封装为Python可以调用的扩展类库。
Python是一种相当高级的语言,比如,完成同一个任务,C语言要写1000行代码,Java只需要写100行,而Python可能只要20行。但是代价是运行速度慢,C程序运行1秒钟,Java程序可能需要2秒,而Python程序可能就需要10秒。它不能做的事情是开放操作系统,手机应用。对于3D游戏,最好用C或C++。
它能做的事情很多,但是缺点也很明显。第一个缺点就是运行速度慢,作为一门解释型语言,要翻译成机器能够理解的代码需要耗很多时间。第二个缺点就是代码不能加密,发布python,实际上是发布源代码,因为解释型语言发布都是发布代码。
2. 安装 python
安装python的时候,你要知道你装的是python2还是python3,我的是mac系统自带python2.7,不过我还是装了python3.6。
简单点的装法就是用anaconda。conda是anaconda下的用于包管理和环境管理的工具,可以环境管理操作,conda中,anything is a package。
#查看帮助
conda -h
#基于python3.6创建环境
conda create --name python36 python=3.6
#查看python版本
python -v
#安装matplotlab
conda install matplotlab
#查看已安装的包
conda list
#更新matplotlab包
conda update matplotlab
#删除matplotlab包
conda remove matplotlab
#更新conda
conda update conda
#更新anaconda
conda update anaconda
#更新python
conda update python
#安装jupyter notebook
conda install jupyter notebook
#启动notebook服务器
jupyter notebook
#运行幻灯片
jupyter nbconvert notebook.ipynb --to slides
#转换幻灯片并立即看到它
jupyter nbconvert notebook.ipynb --to slides --post serve
notebook服务器的运行地址是http://localhost:8888,如果被占用,就用http://localhost:8889。
3. python语法
这里主要讲的是python2的语法,3稍微有些变动。
从Python的官方网站查看文档:http://docs.python.org/2/library/
1)输入以及输出:
用print加上字符串,就可以向屏幕上输出指定的文字。
比如输出'hello, world'
print 'hello, world'
print语句也可以跟上多个字符串,用逗号“,”隔开:
print 'Python is','the best language','in the world'
Python提供了一个raw_input,可以让用户输入字符串,并存放到一个变量里。
name = raw_input()
当你输入 stephen,输入name就可以查看内容了。
name => stephen
数据类型:
整数,浮点数,布尔值,字符串,空值。
特别对于字符串,可以有很多操作。你可以输入:
print 'I\'m \"OK\"!' => I'm "OK"!
print '\\\t\\' => \ \
print r'\\\t\\' => \\\t\\ (用r''表示''内部的字符串默认不转义)
变量:
变量的概念基本上和初中代数的方程变量是一致的,只是在计算机程序中,变量不仅可以是数字,还可以是任意数据类型。
理解变量在计算机内存中的表示也非常重要.
a = 'ABC'
Python解释器干了两件事情:
在内存中创建了一个'ABC'的字符串;在内存中创建了一个名为a的变量,并把它指向'ABC'。
常量:
所谓常量就是不能变的变量,比如常用的数学常数π就是一个常量。
2) 字符串和编码:
字符编码:
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。
浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器。
Python的字符串:
Python添加了对Unicode的支持,以Unicode表示的字符串用u'...'表示。
print u'中文'
len()函数可以返回字符串的长度。
len(u'中文') => 2
把UTF-8编码表示的字符串'xxx'转换为Unicode字符串u'xxx'用decode('utf-8')方法。
print '\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8') => 中文
在Python中,采用的格式化方式和C语言是一致的,用%实现。
'Hi,my name is %s.' % ('Stephen') => 'Hi,my name is Stephen.'
常见的占位符有:
%d整数 , %f浮点数 , %s字符串 , %x十六进制整数。
3) list和tuple:
list = ['Stephen','Adrian','alan']
t = (1,)
list和tuple是Python内置的有序集合,一个可变,一个不可变。
4) 条件判断:
age = 20
if age >= 18:
print 'your age is', age
print 'adult'
elif是else if的缩写,完全可以有多个elif,所以if语句的完整形式就是:
if <条件判断1>:
<执行1>
elif<条件判断2>:
<执行2>
else:
<执行3>
if语句执行有个特点,它是从上往下判断,如果在某个判断上是True,把该判断对应的语句执行后,就忽略掉剩下的elif和else。
5)dict和set
Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
d = {'Stephen':95,'Adrian':75,'alan':85}
为什么dict查找速度这么快?因为dict的实现原理和查字典是一样的。假设字典包含了1万个汉字,我们要查某一个字,一个办法是把字典从第一页往后翻,直到找到我们想要的字为止,这种方法就是在list中查找元素的方法,list越大,查找越慢。第二种方法是先在字典的索引表里(比如部首表)查这个字对应的页码,然后直接翻到该页,找到这个字,无论找哪个字,这种查找速度都非常快,不会随着字典大小的增加而变慢。dict就是第二种方法。
和list比较,dict有以下几个特点:
查找和插入的速度极快,不会随着key的增加而增加;需要占用大量的内存,内存浪费多。
而list相反:
查找和插入的时间随着元素的增加而增加;占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
6)函数
在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
你可以看到,angle=0是一个默认参数。
如果想定义一个什么事也不做的空函数,可以用pass语句:
def nop():
pass
pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
递归函数:
如果一个函数在内部调用自身本身,这个函数就是递归函数。举个例子,我们来计算阶乘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时需要特殊处理。
def fact(n):
if n ==1:
return 1
return n * fact(n -1)
递归函数的优点是定义简单,逻辑清晰。使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
4. 高级特性
1)切片
Python提供了切片(Slice)操作符。
list = ['Stephen','Adrian','alan']
list[0:3]
字符串'xxx'或Unicode字符串u'xxx'也可以看成是一种list,每个元素就是一个字符。因此,字符串也可以用切片操作,只是操作结果仍是字符串。
'ABCDEFG'[:3]
2) 迭代
在Python中,迭代是通过for ... in来完成的。
for ch in 'ABC':
print ch
可以通过collections模块的Iterable类型判断一个对象是可迭代对象。
from collections import Iterable
isinstance('abc', Iterable)
Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身。
for i, value in enumerate(['A','B','C']):
print i, value
3)列表生成式
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
range(1, 11) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错。
4)生成器
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator。
L = [x * x for x inrange(10)]
g = (x * x for x inrange(10))
一个一个打印出generator的每一个元素,可以通过generator的next()方法。
g.next()
比如斐波拉契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max):
n, a, b = 0,0,1
while n < max:
yield b
a, b = b, a + b
n = n +1
5)高阶函数
变量可以指向函数
f = abs => 函数本身也可以赋值给变量,即:变量可以指向函数。
函数名也是变量
abs = 10
abs(-10) => 把abs指向10后,就无法通过abs(-10)调用该函数了
传入函数
def add(x, y, f):
return f(x) + f(y)
Python内建了map()和reduce()函数。
map(str,[1, 2, 3, 4, 5, 6, 7, 8, 9])
再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
def add(x, y):
return x + y
reduce(add, [1,3,5,7,9]) => 25
Python内建的filter()函数用于过滤序列。和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
def not_empty(s):
return s and s.strip()
filter(not_empty, ['A','','B',None,'C',' ']) => ['A', 'B', 'C']
排序算法:
通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1。
sorted([36, 5, 12, 9, 21]) => [5, 9, 12, 21, 36]
返回函数:
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数。
f = lazy_sum(1,3,5,7,9)
调用函数f时,才真正计算求和的结果。
f()
闭包:当一个函数返回了一个函数后,其内部的局部变量还被新函数引用。返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
匿名函数:
f = lambda x: x * x
匿名函数lambda x: x * x实际上就是:
def f(x):
return x * x
关键字lambda表示匿名函数,冒号前面的x表示函数参数。匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数。
装饰器:在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。本质上,decorator就是一个返回函数的高阶函数。
def log(func):
def wrapper(*args, **kw):
print'call %s():'% func.__name__
return func(*args, **kw)
return wrapper
偏函数:Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。
functools.partial就是帮助我们创建一个偏函数的。
import functools
int2 = functools.partial(int, base=2)
functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数。
4. 总结
好了,python语言的基础就到这里,还有额外的需要看官自己慢慢研究。我只做了些总结而已,更多都要向前辈学习。
很多参考了别人的文章。很感谢那些作者们的奉献。