python自学笔记
1.输出
print
用逗号隔开多个输出字符串,也可以用“+”来代替“,”
print "李帅",“王子轩”
2.输入
name = raw_input()
#有提示的输入:
name = raw_input('please enter your name: ')
print 'hello,', name
3.零碎
- 如果字符串里面有很多字符都需要转义,就需要加很多\,为了简化,Python还允许用r”表示”内部的字符串默认不转义
- 如果字符串内部有很多换行,用\n写在一行里不好阅读,为了简化,Python允许用”’…”’的格式表示多行内容
- 第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。
#!/usr/bin/env python
# -*- coding: utf-8 -*-+
4.数据结构
4.1 list 类比于java中的数组
classmates = ['Michael', 'Bob', 'Tracy']
用索引来访问list中每一个位置的元素,记得索引是从0开始的:
classmates[0]
如果要取最后一个元素,除了计算索引位置外,还可以用-1做索引,直接获取最后一个元素:
classmates[-1]
list是一个可变的有序表,所以,可以往list中追加元素到末尾:
classmates.append(‘Adam’)
也可以把元素插入到指定的位置,比如索引号为1的位置python
classmates.insert(1, 'Jack')
p = ['asp', 'php']
s = ['python', 'java', p, 'scheme']
要拿到’php’可以写p[1]或者s[2][1],因此s可以看成是一个二维数组,类似的还有三维、四维……数组,不过很少用到。
4.2 tuple 元祖
tuple和list非常类似,但是tuple一旦初始化就不能修改
classmates = ('Michael', 'Bob', 'Tracy')
5.条件判断和循环
5.1 条件判断
if <条件判断1>:
<执行1>
elif <条件判断2>:
<执行2>
elif <条件判断3>:
<执行3>
else:
<执行4>
5.2 循环
Python的循环有两种
- 一种是for…in循环,依次把list或tuple中的每个元素迭代出来
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print name
- 第二种循环是while循环,只要条件满足,就不断循环,条件不满足时退出循环。比如我们要计算100以内所有奇数之和,可以用while循环实现:
sum = 0
n = 99while n > 0:
sum = sum + n
n = n - 2print sum
6.使用dict和set
6.1 dict
dict的支持,dict全称dictionary,在其他语言中也称为map
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
dict查找速度比较快的原因:给定一个名字,比如’Michael’,dict在内部就可以直接计算出Michael对应的存放成绩的“页码”,也就是95这个数字存放的内存地址,直接取出来,所以速度非常快。
和list比较,dict有以下几个特点:
- 查找和插入的速度极快,不会随着key的增加而增加;需要占用大量的内存,内存浪费多。
而list相反: - 查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少。
所以,dict是用空间来换取时间的一种方法。
6.2 set
set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。
要创建一个set,需要提供一个list作为输入集合:
s = set([1, 2, 3])
7.函数的使用
7.1函数返回多个值,同时接受多个值
python中函数可以直接返回多个值。其实是个假象,是以tuple的形式返回的
__author__ = 'shuai.li'import math
def distance(x, y, step, angle=45):
nx = x + step * math.cos(angle)
ny = y + step * math.sin(angle)
return nx, ny
# main functionif __name__ == "__main__":
nx, ny = distance(5, 10, 1)
print nx, ny
>>>C:\pythonTest>python function.py
>>>4.55192638387 10.8939966636
下面的输出可以看出其实际上为一个tuple类型
if __name__ == "__main__":
r = distance(5, 10, 1)
print r
>>>C:\pythonTest>python function.py
>>>(5.52532198881773, 10.850903524534118)
7.2函数参数的默认值
函数默认值的坑
def add_end(L=[]):
L.append('END')
return L
>>> add_end()
['END']
但是,再次调用add_end()时,结果就不对了:
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
原因是L实际上在python里面是个变量,它指向对象[],当使用的时候改变了L的值,那么其指向的内容就发生了变化,所以函数参数的默认值最好是个不可变对象
7.3可变参数的函数
在参数前面加上 * 就把函数的参数变成可变参数
def cal(*numbers):
sum = 0
for num in numbers:
sum = sum + math.pow(num, 2)
return sum
# main functionif __name__ == "__main__":
r = cal(1, 2)
print r
r1 = cal(1, 2, 3)
print r1
>>> C:\pythonTest>python function.py
>>> 5.0
>>> 14.0
但是我本来就是一个tuple或list不能让我再把里面的对象一个个提出来吧。不用,python提供了一种变通的方案,就是直接在你的tuple或者list前面加上” *“其余操作交给python吧。
def cal(*numbers):
sum = 0
for num in numbers:
sum += math.pow(num, 2)
return sum
# main functionif __name__ == "__main__":
r = (1, 2)
print cal(*r)
>>> C:\pythonTest>python function.py
>>> 5.0
7.4可变个数带参数名的入参
** 这样就可以传入0个或者多个带参数名的参数,用在有必填参数和非必填参数的情况,和可变参数的函数类似在参数中直接传入键值对,也可以不传参数
def student(name, age, **city):
print name, age, city
# main functionif __name__ == "__main__":
city = {"city": "beijing", "street": "suzhoujie"}
student("lishuai", 12, city="beijing", street="suzhoujie")
>>>C:\pythonTest>python function.py
>>>lishuai 12 {'city': 'beijing', 'street': 'suzhoujie'}
当然传入的参数可以直接为一个dict,这样可以像可变参数那样直接传入
def student(name, age, **city):
print name, age, city['city'], city['street']
# main functionif __name__ == "__main__":
city = {"city": "beijing", "street": "suzhoujie"}
student("lishuai", 12, **city)
7.5参数类型组合
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。
!!!当这四种类型都有的时候,可以直接传入 tuple和dict。注意此时tuple会自动填充前面的必填项所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
def func(a, b, c=0, *args, **kw):
print 'a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw
>>> args = (1, 2, 3, 4)
>>> kw = {'x': 99}
>>> func(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'x': 99}
使用*args和**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。???
经过尝试,是不能去掉参数前面的”“和”*“
8.关于函数递归
递归时当心栈溢出。函数的调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就要增加一层,每当函数返回,栈就会减少一层。计算的内存里面的栈是有限的。
解决递归调用栈溢出的方法是通过尾递归优化,实际上就是每次调用函数递归时,传入的参数是已经提前算好的,这样就不用栈层层堆叠。
9.python的高级特性
9.1切片
- 切片相当于直接取其中一块
- -1可以代表最后一个对象
- []中左边的对象在list中也在左边,若是颠倒了顺序,将得到空list
__author__ = 'shuai.li'
if __name__ == "__main__":
l = ["lishuai", "wangwang", "lili", "shuai"]
print l[0:3]
print l[-1]
print l[-3:-1]
print l[-1:-3]
print l[-3:]
print l[::2]
>>>C:\pythonTest>python special.py
['lishuai', 'wangwang', 'lili']
shuai
['wangwang', 'lili']
[]
['wangwang', 'lili', 'shuai']
['lishuai', 'lili'] #特别注意这个的用法,每两个取一个
9.2遍历
__author__ = 'shuai.li'
if __name__ == "__main__":
student = {"name": "lishuai", "age": 12}
for k, v in student.items():
print k+":"+str(v)
C:\pythonTest>python iteration.py
age:12
name:lishuai
9.3列表生成器
9.3.1 怎么用?
列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。
前面写要怎样生成每一项(每一项的内容),后面加上要生成几个(每一项的条件),从点到线
__author__ = 'shuai.li'if __name__ == "__main__":
print [x + x * x for x in range(0,10,2)]
>>>C:\pythonTest>python listGenerate.py
>>>[0, 6, 20, 42, 72]
可以在for循环后面加上 if条件.
if __name__ == "__main__":
print [x for x in range(0, 50) if x % 3 == 0 if x % 4 == 0 ]
注意如果后面有if条件。程序会忽略步长。
if __name__ == "__main__":
print [x for x in range(0, 50, 2) if x % 3 == 0 if x % 4 == 0 ]
>>>C:\pythonTest>python listGenerate.py
>>>[0, 12, 24, 36, 48]
还可以多层循环
if __name__ == "__main__":
print [m+n for m in 'xyz' for n in 'abc' ]
C:\pythonTest>python listGenerate.py
['xa', 'xb', 'xc', 'ya', 'yb', 'yc', 'za', 'zb', 'zc']
前面的条件还可以写成函数的形式
l = ['HELLO', 'Fuck', 'yoU']
print [s.lower() for s in l]
9.3.2用在哪?
需要列出一长串的,并且每一个对象都类似。
如:列出当前目录下所有的文件和目录
import os
if __name__ == "__main__":
print [d for d in os.listdir(".")]
C:\pythonTest>python listGenerate.py
['.idea', 'function.py', 'iteration.py', 'listGenerate.py', 'special.py']
9.4生成器
生成器的好处是边生成边计算,这样就不会像列表生成器那样需要占用很大的空间,尤其是在很大的列表时比较有用。
写法就是将列表生成式的[]改成(),就创建了一个generator:
但是我们可以直接打印出列表生成器list的每一个元素,但是不能直接打印 出生成器的元素,需要借助于next()函数,还可以使用for循环来迭代对象。
还有一种写法是:包含yield关键字
最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
带yield的函数是一个生成器,可以使用for in iterate的方式遍历元素,或者使用 function.next()来遍历元素
下面是一个生成3的整数倍数的生成器
__author__ = 'shuai.li'# coding:utf-8
# 一个返回3的整数倍的生成器def odd(n):
a = 0
while n > 0:
a += 3
n -= 1
yield a
if __name__ == "__main__":
for a in odd(5):
print a
input:
>>> C:\pythonTest>python generator.py
3691215
10.函数式编程
函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。
函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
10.1高阶函数
函数可以像变量一样赋值给变量
if __name__ == "__main__":
f = abs
print f(-1)
上面的程序可以看出f现在已经指向了abs函数本身
那么函数名是什么呢?函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!
传入函数
def add(a, b, f):
return f(a) + f(b)
if __name__ == "__main__":
print add(5, -10, abs)
编写高阶函数,就是让函数的参数能够接收别的函数。
10.2 map()和reduce()函数
map函数就是传入一个函数对传入的另一个对象中每一个元素进行相同的处理。reduce()就是首先处理后面对象的前两个元素,之后合成一个元素然后与第三个元素作用,一直到所有元素处理完毕。
把一个list中的数字转换为字符串:
map的简单使用
if __name__ == "__main__":
print map(str, [1, 2, 3, 4, 5])
>>> C:\pythonTest>python mapAndreduce.py
>>> ['1', '2', '3', '4', '5']
reduce的效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
转换字符串为int类型:
# str转换为int的函数def strtoint(s):
# 首先要把str判断下是否全是数字类型的字符,不做
# 一个个字符转换为数字,然后数字列表
l = map(int, s)
# 数字列表变成int
return reduce(numtoint, l)
def numtoint(a, b):
return 10 * a + b
if __name__ == "__main__":
print strtoint("356546")
print isinstance(strtoint("356546"),int)
>>> C:\pythonTest>python mapAndreduce.py
>>> 356546>>> True
10.2.1 lambda函数
可以用来写单行函数,这样当需要一个简单的逻辑处理的时候就不用写一个函数来处理,直接用lambda来处理
这样可以讲上面的函数简化一下:
# str转换为int的函数def strtoint(s):
# 首先要把str判断下是否全是数字类型的字符,不做
# 一个个字符转换为数字,然后数字列表
l = map(int, s)
# 数字列表变成int
return reduce(lambda x, y: 10 * x + y, l)
if __name__ == "__main__":
print strtoint("356546")
print isinstance(strtoint("356546"), int)
10.2.2练习
1.利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:[‘adam’, ‘LISA’, ‘barT’],输出:[‘Adam’, ‘Lisa’, ‘Bart’]。
if __name__ == "__main__":
print map(lambda s:s[0].upper()+s[1:].lower(),['adam', 'LISA', 'barT'])
>>> C:\pythonTest>python exersize1.py
>>> ['Adam', 'Lisa', 'Bart']
2.Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积。
def prod(l):
if not isinstance(l, list):
return "错误的输入参数类型"
else:
return reduce(lambda x, y: x + y, l)
if __name__ == "__main__":
print prod([23,34,1,2])
10.3 filter
和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
if __name__ == "__main__":
print filter(lambda x: x % 2 == 0, range(1, 100))
10.4 sort
通常规定,对于两个元素x和y,如果认为x < y,则返回-1,如果认为x == y,则返回0,如果认为x > y,则返回1,这样,排序算法就不用关心具体的比较过程,而是根据比较结果直接排序。因此我们需要改写排序算法的时候
倒序排列的函数
def revert(x, y):
if x > y:
return -1
elif x == y:
return 0
else:
return 1
if __name__ == "__main__":
print sorted([34, 67, 89, 32, 56, 23, 12, 567, 3], revert)
>>> C:\pythonTest>python filter.py
>>> [567, 89, 67, 56, 34, 32, 23, 12, 3]
11高级函数
11.1匿名函数
如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!
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
<function sum at 0x10452f668>
调用函数f时,才真正计算求和的结果:
>>> f()25
在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:
>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False
f1()和f2()的调用结果互不影响。
11.2装饰器
我自己的理解:
后面跟一个函数,会将下面的函数给@后面的函数作为参数。
装饰器要有一个内部函数,将需要的逻辑做处理之后将函数返回,最后返回的是装饰器。
def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
@logdef sum():
print "lishuai"
if __name__ == "__main__":
sum()
12模块
在Python中,一个.py文件就称之为一个模块(Module)
为了避免模块名冲突,Python又引入了按目录来组织模块的方法,称为包(Package)。
1)为什么要有 模块和包?
便于组织代码,同时避免冲突。
2)怎样表示一个包?
每一个包目录下面都会有一个init.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。init.py可以是空文件,也可以有Python代码,因为init.py本身就是一个模块,而它的模块名就是mycompany。
3)怎样确定模块的名字?
包名+模块的名字
12.1使用模块
12.1.1直接在命令行使用
if __name__=='__main__':
test()
当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
12.1.2使用别名导入模块
好处是可以根据实际情况选择库
try:
import cStringIO as StringIO
except ImportError: # 导入失败会捕获到ImportError
import StringIO
在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。
正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;
类似xxx这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的author,name就是特殊变量,hello模块定义的文档注释也可以用特殊变量doc访问,我们自己的变量一般不要用这种变量名;
类似_xxx和xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,abc等;
之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。
12.2模块的搜索路径
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:
>>> import sys
>>> sys.path
['', '/usr/lib64/python26.zip', '/usr/lib64/python2.6', '/usr/lib64/python2.6/plat-linux2', '/usr/lib64/python2.6/lib-tk', '/usr/lib64/python2.6/lib-old', '/usr/lib64/python2.6/lib-dynload', '/usr/lib64/python2.6/site-packages', '/usr/lib/python2.6/site-packages']
>>>
如果我们要添加自己的搜索目录,有两种方法:
一是直接修改sys.path,添加要搜索的目录:
>>> import sys
>>> sys.path.append('/Users/michael/my_py_scripts')
这种方法是在运行时修改,运行结束后失效。
第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。???