目标
有些工程上的脚本语言,采用python。学以致用为目的。主要是针对文本操作。
简单了解一下,与perl比较一下。为啥比perl火?
从0学习,边学变记录,下文有错,概不负责。
教程,看完一遍,是需要迭代去看的。直到所有内容都理解消化。最后还要利用帮助手册和百度,才算是学明白了。
中文教程
Python教程 - 廖雪峰的官方网站 http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
因为之前看过他的git教程,相对网上其它资源,应该正式一些。
python版本有两种,建议使用2.x版本。记得以前碰到过,3.x不兼容2.x代码。现在常见的都是2.x版本代码。
gui和终端。
gui下,执行交互式程序。
终端,执行脚本。
编辑器用emacs
因为emacs的排版效果好一些,不会因为空格等乱七八糟排版的问题,影响脚本的运行失败。
python自带help的命令
这个是必须熟悉,并经常使用的。有时候忘记if的语法,就可以利用这种方法,快速得到答案,比百度要快很多倍。极大提高学习效率,即不需要知道if的语法,只需要知道有if命令就可以。
先输入help()
,然后直接输入命令,就可以看帮助手册。比如
>>>print
print的简单帮助手册
>>>abs
abs的简单帮助手册,包括语法、功能描述等。参数的类型,也有说明。
>>>help
help的简单帮助手册。
>>>modules
显示所有python功能命令
>>>keywords
显示所有python的if/elif、for等非功能性命令
>>>topics
显示python所有主题
>>>任意命令或者主题名,就可以显示帮助手册。不需要任何前缀命令。
相对perl或者其它语言,python的一些语法特点
不需要;结尾。有点另类。
参数不一样
注意r参数后面没有空格。r的意思是不让''
之内的字符串转义。
>>> print '\\\t\\'
\ \
>>> print r'\\\t\\'
\\\t\\
True、False、None,要注意大小写
变量.方法。感觉很多这样的写法。比如aaa.replace等;反正就是对变量aaaa进行replace命令操作。
打印不同数据格式,类似其它语言的print
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
>>> '%.2f' % 3.1415926
'3.14'
>>> 'growth rate: %d%%' % 7
'growth rate: 7%'
变量定义
普通变量、数组
疑问:print有什么用处?!
>>> aaaa=123
>>> aaaa
123
>>> aaaa="adfadf"
>>> aaaa
"adfadf"
>>> classmates = ['Michael', 'Bob', 'Tracy']
>>> classmates
['Michael', 'Bob', 'Tracy']
>>> len(classmates)
3
>>> classmates[-1]
'Tracy'
#下述命令对文本操作很合适。list数据结构,在文本操作中,经常使用。
>>> classmates.append('Adam')
>>> classmates
['Michael', 'Bob', 'Tracy', 'Adam']
>>> classmates.insert(1, 'Jack')
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']
>>> classmates.pop()
'Adam'
>>> classmates
['Michael', 'Jack', 'Bob', 'Tracy']
>>> classmates.pop(1)
'Jack'
>>> classmates
['Michael', 'Bob', 'Tracy']
tuple
有别与数组或者list,还有一种数据结构叫tuple,是有序数组,一经定义,不能改变。
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
>>> t[2][1] = 'Y'
>>> t
('a', 'b', ['X', 'Y'])
dict
dict类似perl的哈希结构,是一对对出现的。是{}表示的
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
set
暂时没理解,有什么应用场景。
[]不意味着是list结构。
两个set可以做数学意义上的交集、并集等操作:
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
set([2, 3])
>>> s1 | s2
set([1, 2, 3, 4])
list、tuple、array、dict的区别
Python中的列表(list)类似于C#中的可变数组(ArrayList),用于顺序存储结构。它可以方便、高效的的添加删除元素,并且列表中的元素可以是多种类型。
列表很多操作都跟元组一样,它们的不同在于元组是只读的,那更新列表的操作,比如切片操作来更新一部分元素的操作,就不能用于元组。
tuple可以用list的 [],:操作符提取元素。就是不能直接修改元素。
dict类似perl的哈希结构,是一对对出现的。
个人理解认为,list和dict会在日常应用中常见。
参考文档:
[Python] List(列表),tuple(元组)和array的区别(转) | 一路向北的博客
http://www.showerlee.com/archives/1430
教程怎么没讲全局变量和局部变量?
去百度了一下:
如果你想给在顶层的程序(即未在任何类型的范围如函数或类之中)定义的变量赋值,那么你必须告诉Python,变量不是局部的,而是全局的。我们使用global语句,没有global语句赋值给一个在函数外定义的变量是不可能的。
全局变量,要尽量少的定义;但需要的时候,还是不要犹豫。
条件判断
注意冒号的使用。冒号代表下面一行是代码段,类似perl的{...}
age = 20
if age >= 6:
print 'teenager'
elif age >= 18:
print 'adult'
else:
print 'kid'
循环
names = ['Michael', 'Bob', 'Tracy']
for name in names:
print name
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print sum
函数
简单函数
pass的作用,就是保留判断分支,没有任何功能作用。
def my_def(x):
if x >= 0:
return x
else:
pass
多个参数
下面的math,可以利用help(),然后输入math就可以查询到很多帮助信息。
math应该是一个类,类里面可以有很多方法(即函数)。math是内置module。
疑问:math是内置module,需要import math吗?导入math类?!
答案:需要,不导入,会提示math未定义。纳闷!
虽然函数move定义的返回值是多个变量;但是返回值是一个tuple,move(1,2,3)调用后,是一个变量。这个要注意,假如想返回到多个变量里,那需要对这个tuple变量进行处理。
另外,注意,下述函数的angle参数是可选的,因为有默认值0。
import math
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny
>>> r = move(100, 100, 60, math.pi / 6)
>>> print r
(151.96152422706632, 70.0)
可变长度的参数
参数长度不确定,这种情况。参考下例。
看起来像C语言的指针参数,指针指向的变量地址(指针做形参 - - 博客频道 - CSDN.NET
http://blog.csdn.net/yynetsdk/article/details/7012721)。但python不是这样的。
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
>>> calc(1, 2)
5
>>> calc()
0
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
关键字参数
作用就是传递0个或多个dict类型参数。
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
**extra
表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw
参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
这种情况,经常遇到。比如我在项目仿真环境中的case_list,里面有case_name、dummy、ddrmode等,谁知道哪天仿真环境脚本又需要增加新的选项。
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
def person(name, age, **kw):
if 'city' in kw:
# 有city参数
pass
if 'job' in kw:
# 有job参数
pass
print('name:', name, 'age:', age, 'other:', kw)
>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer
参数组合
小结
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
要注意定义可变参数和关键字参数的语法:
*args
是可变参数,args接收的是一个tuple;
**kw
是关键字参数,kw接收的是一个dict。
以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3)
,又可以先组装list或tuple,再通过*args
传入:func(*(1, 2, 3))
;
关键字参数既可以直接传入:func(a=1, b=2)
,又可以先组装dict,再通过**kw
传入:func(**{'a': 1, 'b': 2})
。
使用*args
和**kw
是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*
,否则定义的将是位置参数。
递归函数
递归函数,要注意溢出问题。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
可以拿下面的例子,作为模板。
def fact(n):
return fact_iter(n, 1)
def fact_iter(num, product):
if num == 1:
return product
return fact_iter(num - 1, num * product)
函数名,也可以作为参数。
def add(x, y, f):
return f(x) + f(y)
>>> add(-5, 6, abs)
11
切片
把list、tuple、string类型的变量,切出一部分。这部分,理解都简单,不记得,就直接百度就可以。熟能生巧。
>>> L = list(range(100))
>>> L
[0, 1, 2, 3, ..., 99]
>>> L[:10:2]
[0, 2, 4, 6, 8]
列表生成式
感觉下面的情况经常遇到
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
功能等同与下例,但是比较而言,上面的例子更简洁易懂。
>>> L = []
>>> for x in range(1, 11):
... L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
debug手段(很重要,一般脚本遇到不是编译报错的bug。需要调试手段才能找到bug点。比如perl -d就可以设置断点,用这个方法解决过很多bug。)
错误和异常处理(这个很重要)
一些有用的函数命令(按字母排序,不懂的可以利用help(isinstance)这样去查找内置帮助手册)
abs
cmp
isinstance
是否属于某种类型。
>>> x = 'abc'
>>> y = 123
>>> isinstance(x, str)
True
>>> isinstance(y, str)
False
int
range
range(101)可以生成0-100的整数序列
>>>range(3)
[0 1 2]
raw_input
等待用户输入的字符串。
注意int的使用。因为raw_input的返回值是字符串,所以要使用int。
birth = int(raw_input('birth: '))
if birth < 2000:
print '00前'
else:
print '00后'
replace
注意,replace命令后,源变量不会被破坏。
>>> a = 'abc'
>>> a.replace('ab', '123123')
'123123c'
>>> a
'abc'
内容太多,待续……………..