1. Python函数参数
1. 位置参数
调用时根据定义参数的顺序传参,如下例:
def fun(a, b):
return a-b
fun(1, 2) # 结果为 1-2 = -1
2. 默认参数
定义函数时写入默认参数,即便不传参也不会显示错误,如下例:
def function (param = 0)
return param
规范: 将默认的、变化不大的写在后面,变化大的参数写在前面
3. 可更改与不可更改参数
所有的变量都可以理解是内存中一个对象的“引用”,而对象有两种,“可更改”(mutable)与“不可更改”(immutable)对象。在python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象,看下例:
a = 1
def fun(a):
a = 2
print a # 结果为1,不会随函数调用而更改
a = []
def fun(a):
a.append(1)
print a # 结果为[1],随函数调用而更改
4. 可变参数
可变参数在函数调用时自动组装成tuple,直接上栗子:
定义:
def fun(*args):
pass
调用方法一:
fun(1,2,3)
调用方法二:
params = [1,2,3]
fun(*params)
5. 关键字参数
关键字参数在函数调用时自动组装成dict, 可不传,也可传入任意个数的关键字参数(必须传入参数名),上栗子:
定义:
def fun(**kwargs):
return kw
调用方法一:
fun(city = 'Beijing') # 返回{'city':'Beijing'}
调用方法二:
fun(gender ='M', job = 'Coder') # 返回{'gender':'M', 'job':'Coder'}
备注:当传入一个dict时,函数内部对其修改不会影响函数外的dict
6. 命名关键字参数
限制了传入的关键字参数,只接受固定名称参数传入,如下:
def fun(paraA, paraB, *, keyParaA, keyParaB):
pass
则只有key为keyParaA和keyParaB的关键字函数可以传入。
7. *args
and **kwargs
当不确定函数里将要传递多少参数时你可以用*args
,相似的,**kwargs
允许使用没有事先定义的参数名;
你也可以混着使用,命名参数首先获得参数值然后所有的其他参数都传递给*args
和**kwargs
,命名参数在列表的最前端,如:
def table_things(titlestring, **kwargs)
*args
和**kwargs
可以同时在函数的定义中,但是*args
必须在**kwargs
前面。
2. Python方法
Python有三种方法,分别是实例方法,静态方法(staticmethod)以及类方法(classmethod),结合下例说明一下这三种方法的区别:
def fun(x):
print "executing fun(%s)"%(x)
class A(object):
def fun(self,x):
print "executing fun(%s,%s)"%(self,x)
@classmethod
def class_fun(cls,x):
print "executing class_fun(%s,%s)"%(cls,x)
@staticmethod
def static_fun(x):
print "executing static_fun(%s)"%x
a=A()
接下来我们来结合栗子对这三种方法做一下讲解。
对于实例方法,在类里每次定义方法的时候都需要绑定一个实例,在上栗中,fun()就是实例方法,它的调用离不开实例,所以我们把实例自己(self) 作为参数传给方法,便能进行方法与实例的绑定;
显然易见,class_fun()就是类方法了,而它则是通过cls来绑定了类;
而静态方法则不需要对谁进行绑定,那么这三种方法在调用时有什么区别呢?
3. Python中的下划线
废话不说直接上栗子:
>>> class MyClass():
... def __init__(self):
... self.__superprivate = "Hello"
... self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
__foo__
:只是约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突。
_foo
:只是约定,用来指定变量私有.程序员用来指定私有变量的一种方式;
__foo
:这个有真正的意义:解析器用_classname__foo
来代替这个名字,以区别和其他类相同的命名。
4. Python装饰器
1. 两点定义:
- 前有@,将之后出现的函数作为参数传入
- 返回作为参数传入的函数
2、 栗子
def log (func):
@functools.wraps (func)
def wrapper (*args, **kw):
print ( ‘call %s’ %func.name)
return func (*args, **kw)
return wrapper
@log
def now ( ):
print (‘2017-05-09’)
3. 说明
在上栗中,调用now()时,now()方法会作为参数传入log()方法,实际上是调用了以now()为参数的log()方法;
上栗的打印内容是:
call now ( ):
2017-05-09
这么解释或许更加专业,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数log(now),返回wrapper()函数。
5. Lambda
Lambda又称匿名函数,当我们需要使用一个简单的且无需重复调用的函数时,就可以使用lambda,优雅又简洁。其使用方法如下例:
lambda 参数 : 返回值
是不是超简单,那看一下具体使用吧:
map( lambda x: x*x, [y for y in range(10)] )
上述代码等价于:
def sq(x):
return x * x
map(sq, [y for y in range(10)])
使用lambda可以有效减少代码量,这样的写法是将「遍历列表,给遇到的每个元素都做某种运算」的过程从一个循环里抽象出来成为一个函数 map,然后用 lambda 表达式将这种运算作为参数传给 map。Python 之中,类似能用到 lambda 表达式的「高级」函数还有sort,reduce,filter等等。
6. map()
,reduce()
,filter()
既然说到了lambda,那就不得不提map()、reduce()和filter(),下面就一一介绍一下吧:
1. map()
map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
比如我们有一个函数f(x)=x*x,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:
map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
map()传入的第一个参数是f,即需要对列表中的元素进行的操作,第二个参数是迭代列表,返回则是一个新的经过处理后的列表。
map()作为高阶函数,将运算规则抽象了,将列表中的数字转为字符串只需要一行代码:
map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])
2. reduce()
与map()相同,reduce()同样接收两个参数,第一个是函数(这个函数必须接收两个参数),第二个是迭代列表,它的效果如下:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
即列表中的第一个元素与第二个元素作为参数传入f()的返回值,与列表中的第三个元素再次作为参数传入f()......
3. filter()
filter()函数用于过滤序列。
又和map()类似的是,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素,上栗子:
def is_odd(n):
return n % 2 == 1
filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])
# 结果: [1, 5, 9, 15]
7. Python中的拷贝
上个栗子一目了然:
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d
输出结果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
8. Python中的正则表达式
1.预设元字符
-
\w
匹配任意一个单词字符,包括数字和下划线,等价于[A-Za-z0-9_],例如 a\wc 可以匹配 abc、acc -
\W
匹配任意一个非单词字符,与 \w 操作相反,它等价于 [^A-Za-z0-9_],例如: a\Wc 可匹配 a!c -
\s
匹配任意一个空白字符,空格、回车等都是空白字符,例如:a\sc 可以配 a\nc,这里的 \n表示回车 -
\S
匹配任意一个非空白字符 -
\d
匹配任意一个数字,它等价于[0-9],例如:a\dc 可匹配 a1c、a2c ... -
\D
匹配任意一个非数字
2.基本元字符
-
.
匹配除换行符以外的任意一个字符,例如:"a.c" 可以完全匹配 "abc",也可以匹配 "abcef" 中的 "abc" -
\
转义字符,使特殊字符具有本来的意义,例如: 1.2 可以匹配 1.2 -
[...]
匹配方括号中的任意一个字符,例如:a[bcd]e 可以匹配 abe、ace、ade,它还支持范围操作,比如:a到z可表示为 "a-z",0到9可表示为 "0-9",注意,在 "[]" 中的特殊字符不再有特殊意义,就是它字面的意义,例如:[.*]就是匹配 . 或者 * -
[^...]
字符集取反,表示只要不是括号中出现的字符都可以匹配,例如:a[^bcd]e 可匹配 aee、afe等
3.重复匹配
-
*
重复匹配零次或者更多次 -
?
重复匹配零次或者一次 -
+
重复匹配1次或者多次 -
{n}
重复匹配n次 -
{n,}
重复匹配至少n次 -
{n, m}
重复匹配n到m次
4.贪婪与非贪婪
-
贪婪模式
正则表达式重复匹配时,在使整个表达式能得到匹配的前提下尽可能匹配多的字符,我们称之为贪婪模式;
例如: r"a.*b" 表示匹配 a 开头 b 结尾,中间可以是任意多个字符的字符串,如果用它来匹配 aaabcb,那么它会匹配整个字符串 -
非贪婪模式
只需要在量词后面加一个问号" ?",在保证匹配的情况下尽可能少的匹配;
比如刚才的例子,我们只希望匹配 aaab,那么只需要修改正则表达式为 r"a.*?b"
5.正则引擎
re.match(pattern, string)
match方法从字符串的起始位置开始检查,如果刚好有一个子字符串与正则表达式相匹配,则返回一个Match对象,只要起始位置不匹配则退出,返回 Nonere.search(pattern, string)
search 方法虽然也是从起始位置开始检查,但是它在起始位置不匹配的时候会一直尝试往后检查,直到匹配为止,如果到字符串的末尾还没有匹配,则返回 Nonere.findall(pattern, string)
findall 返回的对象是由匹配的子字符串组成的列表,即使匹配到了也不中断,继续匹配
写了那么多,但每次写正则的时候,我还是会用度娘 =.=