Python一等兵:函数

一、有用的None:
None是Python中一个特殊的值,虽然它不表示任何数据,但仍然具有重要的作用。虽然None作为布尔值和False是一样的,但是它和False有很多差别。需要把None和不含任何值的空数据结构区分。0值的整型/浮点型、空字符串、空列表、空元组、空字典、空集合都等价于False,但是不等于None。

二、位置参数

>>> def players(mvp,best_scorer,best_reb):
...             return{'mvp':mvp,'best_scorer':best_scorer,'best_reb':best_reb}
...
>>> players('Lebron James','Koby Brant','Ying Mu')
{'best_scorer': 'Koby Brant', 'best_reb': 'Ying Mu', 'mvp': 'Lebron James'}
位置参数的值是按照顺序依次复制过去的,但是位置参数的一个弊端是必须熟记每个位置参数的含义,位置记错了结果就错了。

三、关键字参数
如果同时出现两种参数形式,首先 应该考虑的是位置参数。
>>> players('Lebron James',best_reb = 'Ying Mu',best_scorer = 'Koby Brant')
{'best_scorer': 'Koby Brant', 'best_reb': 'Ying Mu', 'mvp': 'Lebron James'}

四、指定默认参数值
>>> def menu( wine, entree, dessert=' pudding'): 
...             return {'wine': wine, 'entree': entree, 'dessert': dessert}

#默认参数不传递新值时输出默认值,传递新值时输出新值
>>> menu(' chardonnay', 'chicken') 
{'dessert': 'pudding', 'wine': 'chardonnay', 'entree': 'chicken'}

>>> menu(' dunkelfelder', 'duck', 'doughnut') 
{'dessert': 'doughnut', 'wine': 'dunkelfelder', 'entree': 'duck'}
经常犯的一个错误是把可变的数据类型(如列表或者字典)当做默认参数值。

五、使用*收集位置参数
>>> def print_ args(* args): 
...             print(' Positional argument tuple:', args) 
...

#给函数传入的所有参数都会以元组的形式返回输出
>>> print_ args( 3, 2, 1, 'wait!', 'uh...') 
Positional argument tuple: (3, 2, 1, 'wait!', 'uh...')

#如果你的函数同时有限定的位置参数,那么*args会收集剩下的参数
>>> def print_ more( required1, required2, *args): 
...             print(' Need this one:', required1) 
...             print(' Need this one too:', required2) 
...             print(' All the rest:', args) .
.. 
>>> print_ more(' cap', 'gloves', 'scarf', 'monocle', 'mustache wax') 
Need this one: cap 
Need this one too: gloves 
All the rest: ('scarf', 'monocle', 'mustache wax')

六、使用**收集关键字参数
使用两个星号可以将参数收集到一个字典中,参数的名字是字典的键,对应参数的值是字典的值。
>>> def print_ kwargs(** kwargs): 
...             print(' Keyword arguments:', kwargs) 
...

>>> print_ kwargs( wine=' merlot', entree=' mutton', dessert=' macaroon') 
Keyword arguments: {'dessert': 'macaroon', 'wine': 'merlot', 'entree': 'mutton'}
如果把带有*args和**kwargs的位置参数混合起来,它们会按照顺序解析。

七、文档字符串

建议在函数体开始的部分附上函数定义说明的文档
def print_ if_ true( thing, check): 
        ''' 
        Prints the first argument if a second argument is true. 
        The operation is: 
                1. Check whether the *second* argument is true. 
                2. If it is, print the *first* argument. 
        ''' 
        if check: 
                print( thing)

调用Python函数help()可以打印输出一个函数或模块的文档字符串。

八、函数

>>> def answer():
...         print(42)
...
>>> answer()
42

>>> def run_something(func):
...         func()
...
>>> run_something(answer)
42

>>> def add_args(arg1,arg2):
...         print(arg1 + arg2)
...
>>> def run_sth_with_args(func,arg1,arg2):
...         func(arg1,arg2)
...

>>> run_sth_with_args(add_args,5,9)
14

>>> def sum_arg(*args):
...         return sum(args)
...
>>> def run_with_positional_args(func,*args):
...         return func(*args)
...
>>> run_with_positional_args(sum_arg,1,2,3,4)
10

九、内部函数

当需要在函数内部多次执行复杂任务时,内部函数是非常有用的,从而避免了循环和代码的堆叠重复。
>>> def knights( saying): 
...             def inner( quote): .
..                     return "We are the knights who say: '%s'" % quote .
..             return inner( saying) ...

十、闭包
内部函数可以看作一个闭包。闭包是一个可以 由另一个函数动态生成的函数,并且可以改变和存储函数外创建的变量的值。
>>> def knights2( saying): .
..             def inner2(): 
...                     return "We are the knights who say: '%s'" % saying 
...             return inner2 
...
注意闭包inner2和内部函数的区别:
  • inner2()直接使用外部的sanying参数,而不是通过另外一个参数获取;
  • knights2()返回为inner2函数,而不是调用它。
>>> a = knights2(' Duck') 
>>> b = knights2(' Hasenpfeffer')

#a和b既是函数也是闭包
>>> type( a) 
< class 'function'> 
>>> type( b) 
< class 'function'>

>>> a 
< function knights2.< locals>. inner2 at 0x10193e158> 
>>> b 
< function knights2.< locals>. inner2 at 0x10193e1e0>

>>> a() 
"We are the knights who say: 'Duck'" 
>>> b() 
"We are the knights who say: 'Hasenpfeffer'"

十一、匿名函数——lambda()函数 

# -*- Coding : UTF-8 -*-
#Author: Da Chen
#Date: 2018/4/2



def edit_story(words,func):
'''
words—— 单词列表;
func—— 遍历单词列表里单词的函数

'''
    for word in words:
        print (func(word))

stairs = [ 'thud' , 'meow' , 'thud' , 'hiss' ]

def enliven(word):
    return word.capitalize() + '!'

edit_story(stairs,enliven)


Thud!
Meow!
Thud!
Hiss!

如果用lambda的话,enliven()函数可以简介地用下面一个lambda代替:
>>> edit_ story( stairs, lambda word: word. capitalize() + '!'
Thud! 
Meow! 
Thud! 
Hiss!

十二、生成器

生成器是用来创建Python序列的一个对象。使用它可以迭代庞大的序列,且不需要在内存中创建和存储整个序列。通常,生成器是为迭代器产生数据的。如range()。
每次迭代生成器时,它会记录上一次调用的位置,并且返回下一个值。这一点和普通的函数是不一样的,一般函数都不记录前一次调用,而且都会在函数的第一行开始执行。
如果想创建一个比较大的序列,使用生成器推倒的代码会很长,这时可以尝试写一个生成器函数。生成器函数和普通函数类似,但是它的返回值使用yield语句声明而不是return。
>>> def my_range(first=0,last=10,step=1):
...     number = first
...     while number < last:
...             yield number
...             number += step
...
>>> my_range
<function my_range at 0x7ffda0bbbea0>
>>> ranger = my_range(1,6)
>>> type(ranger)
<class 'generator'>

#生成器对象可以进行迭代
>>> for i in ranger:
...     print(i)
...
1
2
3
4
5

十三、装饰器

有时候需要在不改变源代码的情况下修改已经存在的函数。常见的例子是增加一句调试声明,以查看传入的参数 。
装饰器实质上是一个函数。它把一个函数作为输入并且返回另外一个函数。
在装饰器中,通常使用下面这些Python技巧:
  • *args和**kwargs
  • 闭包
  • 作为参数的函数
def document_func(func):
'''
定义一个装饰器,实现如下功能:
1 、打印输出函数的名称和参数的值
2 、执行含有参数的函数
3 、打印输出结果
4 、返回修改后的函数
'''
    def new_function(*args,**kwargs):
        print ( 'Running Function:' ,func. __name__ )
        print ( 'Positional arguments:' ,args)
        print ( 'Keyword arguments:' ,kwargs)
        result = func(*args,**kwargs)
        print ( 'Result:' ,result)
        return result
    return new_function

通过人工赋值来使用装饰器:
>>> def add_ ints( a, b): 
...             return a + b ... 
>>> add_ ints( 3, 5) 
>>> cooler_ add_ ints = document_ it( add_ ints) # 人工 对 装饰 器 赋值 
>>> cooler_ add_ ints( 3, 5) 
Running function: add_ ints 
Postitional arguments: (3, 5) 
Keyword arguments: {} 
Result: 8 
8
或者直接@
>>>@document_func
       def add_num(a,b):
           return a + b

>>>add_num( 2 , 8 )


Running Function: add_num
Positional arguments: (2, 8)
Keyword arguments: {}
Result: 10

同样一个函数可以有多个装饰器,靠近函数定义(def上面)的装饰器最先执行,然后依次执行上面的
>>> def square_it(func):
...     def new_function(*args,**kwargs):
...             result = func(*args,**kwargs)
...             return result * result
...     return new_function
...

#注意不同装饰器顺序导致结果的不同
>>> @document_ it 
...      @square_ it .
..       def add_ ints( a, b): 
...             return a + b 
... 
>>> add_ ints( 3, 5) 
Running function: new_ function 
Positional arguments: (3, 5) 
Keyword arguments: {} 
Result: 64 
64

>>> @square_ it 
...      @document_ it 
...      def add_ ints( a, b): 
...             return a + b 
... 
>>> add_ ints( 3, 5) 
Running function: add_ ints 
Positional arguments: (3, 5) 
Keyword arguments: {} 
Result: 8 
64

每个程序的主要部分定义了全局命名空间,在这个命名空间的变量是 全局变量
为了读取全局变量而不是函数中的局部变量,需要在变量前面显式地加关键字global。
>>> animal = 'fruitbat' 
>>> def change_ and_ print_ global(): 
...             global animal 
...             animal = 'wombat' 
...             print(' inside change_ and_ print_ global:', animal) 
... 
>>> animal 'fruitbat' 
>>> change_ and_ print_ global() 
inside change_ and_ print_ global: wombat 
>>> animal 
'wombat'

如果在函数中不声明关键字global,Python会使用局部命令空间,同时变量也是局部的。函数执行后回到原来的命名空间。
Python提供了两个获取命名空间内容的函数:
  • locals()返回一个局部命名空间内容的字典;
  • globals()返回一个全局命名空间内容的字典。
>>> animal = 'cat'
>>> def change_local():
...     animal = 'dog'
...     print('locals:',locals())
...
>>> animal
'cat'
>>> change_local()
locals: {'animal': 'dog'}
>>> print('globals:',globals())
globals: {'__name__': '__main__', 'run_sth_with_args': <function run_sth_with_args at 0x7ffda34417b8>, 'my_range': <function my_range at 0x7ffda0bbbea0>, 'run_with_positional_args': <function run_with_positional_args at 0x7ffda3465400>, 'run_something': <function run_something at 0x7ffda3441730>, 'time': <module 'time' (built-in)>, 'answer': <function answer at 0x7ffda34bf488>, 'players': <function players at 0x7ffda3f5c9d8>, '__builtins__': <module 'builtins' (built-in)>, 'this': <module 'this' from '/usr/lib/python3.5/this.py'>, '__spec__': None, 'sum_arg': <function sum_arg at 0x7ffda3f5cae8>, '__doc__': None, 'animal': 'cat', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'square_it': <function square_it at 0x7ffda0bbbf28>, 'add_args': <function add_args at 0x7ffda3441510>, 'ranger': <generator object my_range at 0x7ffda0b9bca8>, '__package__': None, 'change_local': <function change_local at 0x7ffda0bbc0d0>, 'i': 5}
>>> animal
'cat'

名称中_和__的用法
以两个下划线__开头和结束的名称都是Python的保留用法。因此,在自定义的变量中不能使用它们。
例如,一个函数的名称是系统变量function.__name__,它的文档字符串是function.__doc__:
>>> def amazing(): 
...             '''This is the amazing function. 
...             Want to see it again?''' 
...             print(' This function is named:', amazing.__ name__) 
...             print(' And its docstring is:', amazing.__ doc__) 
... 
>>> amazing() 
This function is named: amazing 
And its docstring is: This is the amazing function. Want to see it again?

十四、使用try和except处理错误

“Do, or do not. There is no try.”
                                                    ————Yoda
当你执行可能出错的代码时,需要适当的异常处理程序用于阻止潜在的错误发生。
在异常可能发生的地方添加异常处理程序,对于用户明确错误是一种好方法。即使不会及时解决问题,至少会记录运行环境并且停止程序执行。
>>> short_ list = [1, 2, 3] 
>>> while True: 
...             value = input(' Position [q to quit]? ')
...             if value == 'q': 
...                     break 
...             try: 
...                     position = int( value) 
...                     print( short_ list[ position]) 
...             except IndexError as err: 
...                     print(' Bad index:', position) 
...             except Exception as other: 
...                     print(' Something else broke:', other) 
... 
Position [q to quit]? 1 
Position [q to quit]? 0 
Position [q to quit]? 2 
Position [q to quit]? 3 
Bad index: 3 
Position [q to quit]? 2 
Position [q to quit]? two 
Something else broke: invalid literal for int() with base 10: 'two' 
Position [q to quit]? q

编写自己的异常:
>>> class UppercaseException(Exception):
...             pass
...
>>> words = ['eeenie','meenie','miny','MO']
>>> for word in words:
...             print(word)
...             if word.isupper():
...                     raise UppercaseException(word)
...
eeenie
meenie
miny
MO
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
__main__.UppercaseException: MO
一个异常是一个类,即类Exception的一个子类。即使没有定义UppercaseException的行为(注意到只使用pass),也可以通过继承其父类Exception在抛出异常时输出错误提示。


























































































猜你喜欢

转载自blog.csdn.net/PyDarren/article/details/79835826