学习廖雪峰python3教程(1)
- “//” 是地板除。 如
5//3=1
- 字符串编码ascii->unicode->utf-8(gbk)。 unicode是个中间编码,在内存中使用。显示和存到文件或者传输时是需要编码成utf-8或者gbk编码的,这样可以减少数据传输量。
>>>ord(‘A’)//65, 或者字符的整数表示。这里需要注意的是,python用的是unicode编码,也就是说这里的整数是指unicode编码下,对应字符的整数表示。
>>>chr(65)//或者整数对应的字符。
>>>’中文’.encode(‘utf-8′)// 把unicode的’中文’按utf-8编码的字节是啥。
>>>b’\xe4\xb8\xad\xe6\x96\x87’.decode(‘utf-8’);//把’\xe4\xb8\xad\xe6\x96\x87’按utf-8解码成unicode。 - 函数的参数有必填参数、默认参数、可变参数、关键字参数、命名关键字参数。
1.默认参数
默认参数有个最大的坑,演示如下:先定义一个函数,传入一个list,添加一个END再返回:
def add_end(L=[]):
L.append(‘END’)
return L
当你正常调用时,结果似乎不错:>>> add_end([1, 2, 3]) [1, 2, 3, 'END'] >>> add_end(['x', 'y', 'z']) ['x', 'y', 'z', 'END']
当你使用默认参数调用时,一开始结果也是对的:
>>> add_end() ['END']
但是,再次调用add_end()时,结果就不对了:
>>> add_end() ['END', 'END'] >>> add_end() ['END', 'END', 'END']
很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了’END’后的list。
原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向 对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时 的[]了。
所以,定义默认参数要牢记一点:默认参数必须指向不变对象!
1.可变参数
其中可变参数可以直接把一个元组传进去。
如def test(arg1,arg2,*argn): print(arg1)
arg=(3,4,5)
test(1,2,*arg)
argn在函数内部是一个元组。2.关键字参数
感觉和可变参数很像,区别是关键字参数需要传参时指定keydef test(arg1,**argn); print(arg1, argn)
是这么调用的
test('a',name="go2live",site="演道网")
在函数内部变成了一个dict。3.命名关键字参数。
这个我感觉其实和必填参数和默认参数类似。区别是必填参数是有参数位置的。必须按位置来。
而全名关键字参数因为指定了名字,所以位置不太重要了。def test(key1,*,key2,key3): print(key1,key2,key3)
之所以多了个,是为了区别key1,key2,key3。之前的是必填参数,*之后是的命名关键字参数。
调用如下
test(“key1″,key2=”key2″,key3=”key3″)
4.组合使用
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种 参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键 字参数和关键字参数。
其实这里有个小窍门,必选参数、默认参数、可变参数 都是位置相关的参数,命名关键 字参数和关键字参数 因为有关键字指定,是位置无关的。所以肯定是位置参数在前,关键字参数在后。
又因为命名关键字参数是必传的,关键字参数是选传的。必传的在前。这样一理解就可以记忆了。最终可以发现,所以函数调用都可以用元组和字典来调用。元组就是位置参数。字典就是关键字参数。
形如下面的调用方式。
arg1=(pos1,pos2,…)
arg2=(key1=”,key2=”,…)
test(arg1,*arg2) - 生成器。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
第二种方法
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
5. 装饰器
本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下:
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:
@log
def now():
print('2015-3-25')
调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:
>>> now()
call now():
2015-3-25
把@log放到now()函数的定义处,相当于执行了语句:
now = log(now)
6.偏函数
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。