博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Note_python(04)
阅读量:2489 次
发布时间:2019-05-11

本文共 10317 字,大约阅读时间需要 34 分钟。

函数

1、python里的函数可以返回一个值或者对象,知识在返回一个容器对象的时候有点不同,看起来像是能返回多个对象。

>>> def bar():...     return 'abc', '123'...>>> bar()('abc', '123')>>> type(bar())   #返回的其实是元组

简而言之,如果没有显式的返回于元素或者若果返回None时,python会返回一个None。如果函数返回多个对象,python把他们聚集起来并以一个元组返回。

调用函数

1、以一对圆括号调用函数.

>>> bar()('abc', '123')

创建函数

1、def 语句

语法:

def function_name(arguments):    "function_documentation_string"  #函数注释    function_body_suite

示例:

>>> def bar():...     "return a tuple"    #函数注释...     return 'abc', '123'...>>> bar()       #函数调用('abc', '123')

2、前向引用

语言已经无法表达了。

>>> def foo():...     print 'In foo()'...     bar()...>>> def bar():...     print 'In bar()'...>>> foo()In foo()In bar()

3、函数属性

>>> def foo():...     print 'In foo()'... >>> foo.__doc__     #函数注释>>> foo.__name__    #函数名字'foo'>>> foo.version = 0.1   #函数版本>>> foo.__doc__ = 'Make a test function'>>> help(foo)   #可以输出函数的注释文本

4、内部/内嵌函数

eg.

python解释器输出:

>>> def foo():...     def sar():...             print 'sar() called'...     print 'foo() called'...     sar()...>>> foo()foo() calledsar() called>>> sar()Traceback (most recent call last):  File "
", line 1, in
NameError: name 'sar' is not defined

将上述函数整合为一个模块:#inner.py

#!/usr/bin/env python # -*- coding:utf-8 -*- # Script_Name: inner.pydef foo():    def sar():        print 'sar() called'    print 'foo() called'    sar()if __name__ == '__main__':    foo()    sar()

带有内嵌函数的外部函数,其执行顺序依然是顺序执行。

执行inner.py结果:

foo() calledsar() calledTraceback (most recent call last):  File ".\inner.py", line 18, in 
bar()NameError: name 'sar' is not defined

内嵌函数整个函数体都是在外部函数的作用域之内的,如果没有对内部函数的外部引用,那么除了函数体内,任何地方都不会对其起作用。

5、内嵌函数体补充

  • func1():
>>> def func1():...     def fo():...         print 'fo() called'...     return fo...>>> func1()
>>> result = fun1c()>>> type(result)

这里return fo返回的是一个函数对象的引用。

  • func2():
>>> def func2():...     def fo():...         print 'fo() called'...     return fo()...>>> func2()fo() called

这里的返回[return fo()]的是一个函数(对象)的调用。

6、传递函数(函数对象的引用和函数对象的调用)

当对一个对象赋值时,世纪时将相同对象的引用复制给这个变量,如果这个对象是一个函数时,这个对象所有的别名都是可调用的。

eg:

>>> def foo():...     print 'in foo()'...>>> bar = foo #实际上是bar和foo引用了同一个函数对象,foo是函数对象的引用>>> foo()   #foo()是函数对象的调用in foo()>>> bar()in foo()>>>>>> def bar(argfunc):   #传入的参数:argfunc就是函数对象foo...     argfunc()   #()双圆括号是函数调用的操作符,函数调用...>>> bar(foo)in foo()

7、默认参数

实际上就是定义函数时允许设定默认的参数,如下例中的.

>>> def taxMe(cost, rate=0.0825):...     return cost + (cost * rate)...>>> taxMe(100)108.25>>> taxMe(100, 0.05)105.0

切记:所有必须的参数都要在默认参数之前,也就是说默认参数在最后。这是强制规定。

>>> def taxMe(cost = 100, rate):...     return cost + (cost * rate)...  File "
", line 1SyntaxError: non-default argument follows default argument

8、可变长度的参数

  • 非关键字可变长参数参数(元组)
    函数调用时可以接受一个非固定数目的参数,其使用元组的方式。
    可变长参数元组必须在位置和默认参数之后,且使用星号操作符,*(星号操作符)之后的形参座位元组传递给函数,元组保存了所有的传递给函数的额外的参数,如果没有给出额外的参数,那么元组为空。
>>> def test(arg1, arg2 = 'default', *args):...     print 'arg1 ——>> ', arg1...     print 'arg2 ——>> ', arg2...     for each in args:...             print 'another arg ——>> ', each...>>> test('abc')arg1 ———>>  abcarg1 2— —  default>>> test('abc', '123')arg1 ———>>  abcarg1 2— —  123>>> test('abc', '123', 'def', 456)arg1 ———>>  abcarg1 2— —  123another arg ——>>  defanother arg ——>>  456
  • 关键字变量参数(字典)
    与非关键字可变长参数参数(元组)类似,只不过换成了表示了。依然放在最后面,在存在元组的情况下依然在最后。
>>> def test(arg1, arg2 = 'default', **args):...     print 'arg1 -->> %s' % arg1...     print 'arg2 -->> %s' % arg2...     for each in args:...             print '%s -->> %s' % (each, args[each])...>>> test(123, 456, a=789)arg1 -->> 123arg2 -->> 456a -->> 789>>> test(123, 456, a=789, b=101112)arg1 -->> 123arg2 -->> 456a -->> 789b -->> 101112>>> test(123, 456, a=789, b=101112, c='abcdefg')arg1 -->> 123arg2 -->> 456a -->> 789c -->> abcdefgb -->> 101112

元组和字典参数共同存在的情况下:

>>> def test(arg1, arg2 = 'default', *argt, **args):...     print 'arg1 -->> %s' % arg1...     print 'arg2 -->> %s' % arg2...     for each in argt:...             print 'Tuple -->> %s' % each...     for each in args:...             print '%s -->> %s' % (each, args[each])...>>> test(123, 456, 789, dict='abc')arg1 -->> 123arg2 -->> 456Tuple -->> 789dict -->> abc>>> test(123, 456, 789, 'abc', dict1='abc', dict2=135)arg1 -->> 123arg2 -->> 456Tuple -->> 789Tuple -->> abcdict1 -->> abcdict2 -->> 135
  • 调用带有可变长参数对象函数
    我们将非关键字参数放在元组中,将关键字参数放在字典中。
>>> def test(arg1, arg2 = 'default', *argt, **args):...     print 'arg1 -->> %s' % arg1...     print 'arg2 -->> %s' % arg2...     for each in argt:...             print 'Tuple -->> %s' % each...     for each in args:...             print '%s -->> %s' % (each, args[each])...>>>>>>>>> test(10, 20, 30)arg1 -->> 10arg2 -->> 20Tuple -->> 30>>> test(10, 20, 30, 40)arg1 -->> 10arg2 -->> 20Tuple -->> 30Tuple -->> 40>>> test(10, 20, 30, 40, foo=50)arg1 -->> 10arg2 -->> 20Tuple -->> 30Tuple -->> 40foo -->> 50>>> test(10, 20, 30, 40, foo=50, bar=60)arg1 -->> 10arg2 -->> 20Tuple -->> 30Tuple -->> 40foo -->> 50bar -->> 60>>> test(10, 20, *(30, 40), **('foo':50, 'bar':60))     #字典使用{}花括号,元组使用()圆括号  File "
", line 1 test(10, 20, *(30, 40), **('foo':50, 'bar':60)) ^SyntaxError: invalid syntax>>> test(10, 20, *(30, 40), **{
'foo':50, 'bar':60})arg1 -->> 10arg2 -->> 20Tuple -->> 30Tuple -->> 40foo -->> 50bar -->> 60

此外,我们还可以在函数调用之外创建元组和字典:

>>> t = (30, 40)>>> d = {
'foo':50, 'bar':60}>>> test(10, 20, *t, **d)arg1 -->> 10arg2 -->> 20Tuple -->> 30Tuple -->> 40foo -->> 50bar -->> 60

8、函数式编程

  • 匿名函数和lambda
    lamdba 表达式运行起来就像一个函数,当被调用时,创建一个框架对象。
    语法格式:
lambda [arg1[, arg2, arg3,....argN]] : expression

示例:

>>> lambda x, y : x + y
at 0x6ffffe276e0>

lambda 表达式可以用来赋值给一个如列表和元组的数据结构。

>>> n = lambda *z : z>>> n('a', 'b')('a', 'b')>>> m = lambda **y : y.keys()>>> m(a=123)['a']>>> m(a=123, b=456)['a', 'b']>>> p=lambda x : x + x>>> p(1)2>>> p('a')'aa'
  • 内建函数filter()、map()、reduce()

1、filter()

filter()是一个过滤函数。

filter(func, seq) #func判断的布尔函数, seq需要过滤的序列

调用一个布尔函数func来迭代遍历每个seq中的元素,返回一个使func返回值为true的元素的序列。

eg:

>>> def tell(x):...     return x % 2...>>> filter(tell, range(10))[1, 3, 5, 7, 9]#   可以与lambda表达式结合>>> filter(lambda x:x%2, range(10))     [1, 3, 5, 7, 9]# 更简单的过滤方法>>> [x for x in range(10) if x % 2][1, 3, 5, 7, 9]

2、map()

实际上就是一个针对所有的数据进行遍历的函数。

map(func, seq)

eg:

>>> map((lambda x: x+3), range(10))[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]>>> def foo(x, y):...     return x+y...>>> map(foo, range(10), range(10))      #这里的func是foo而不是foo(),这点要特别注意,在之前的笔记中有提到,foo是函数的引用,foo()是函数对象的调用,这里只能是引用,函数对象的调用需要有参数,如果你执行调用会报错[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]>>> map((foo(x, y)), range(10), range(10))Traceback (most recent call last):  File "
", line 1, in
NameError: name 'y' is not defined# 使用函数对象的调用会报错

3、reduce()

语法格式:

reduce(func, seq[, init])

将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续地将现有的结果和下一个之作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果返回值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。

reduce()实际上就是一个迭代器,对seq进行逐个迭代,其中前两个作为初始值。从seq[]中依此选择两个值传入func函数,得出新的结果,并将seq中被选择的两个数值替换为新的结果,然后重复上述过程,直至结束。典型的例子就是数列求和:

#求[0, 1, ..., 9]的和:>>> reduce((lambda x, y : x + y), range(10))45

9、偏函数

好吧,实际上我也不是很懂。。。。。。。。。。。。。。。

>>> from operator import add, mul>>> from functools import partial# 泛化偏函数(PFA)使用partial,可以简化代码>>> add1 = partial(add, 1)    # add1(x) == add(1, x)>>> mul100 = partial(mul, 100)    #mul100(x) == mul(100, x)>>>>>> add1(10)11>>> mul100(10)1000
  • 简单GUI
from functools import partialimport Tkinterroot = Tkinter.Tk()MyButton = partial(Tkinter.Button, root, fg='white', bg='blue')# MyButton(x) == TKinter.Button(root, fg='white', bg='blue', x)b1 = MyButton(text='Button1')b2 = MyButton(text='Button2')qb = MyButton(text='QUIT', bg='red', command=root.quit)b1.pack()b2.pack()qb.pack(fill=Tkinter.X, expand=True)root.title('PFAs!')root.mainloop()

运行截图:

10、变量作用域

  • 全局变量和局部变量

    定义在函数内的变量有局部作用域,在一个模块中的最高级的变量有全局作用域。
    全局变量的一个特征就是除非被剔除掉,否则它们会存活到脚本运行结束,且对于所有的函数,他们的值都是可以被访问的。而局部变量,仅仅是暂时存在的,只依赖于定义他们的函数现阶段是否处于活动。当一个函数调用出现时,其局部变量就进入声明他们的作用域。在那一刻,一个新的局部变量名为那个对象创建了,一旦函数完成,框架被释放,变量就会离开作用域。

  • global 语句

    如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉。

>>> is_this_global = 'xyz'>>> def  foo():...         this_is_local = 'abc'...         is_this_global = 'def'  #局部变量覆盖了全局变量...         print this_is_local + is_this_global...>>> foo()abcdef

为了明确地引用一个已经命名的全局变量,必须使用global语句。

global var1[, var2, ..., varN]
>>> is_this_global = 'xyz'>>> def  foo():...         global is_this_global...         this_is_local = 'abc'...         is_this_global = 'def'...         print this_is_local + is_this_global...>>> foo()abcdef
  • 闭包
    在一个内部函数内,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
    定义在外部函数内但由内部函数引用或者使用的变量称为自由变量。
    故闭包所满足的条件是:
1. 必须有一个内嵌函数2. 内嵌函数必须引用外部函数中的变量3. 外部函数的返回值必须是内嵌函数
>>> def counter(start_at=0):...     count = [start_at]...     def incr():...             count[0] += 1...             return count[0]...     return incr...>>> count = counter(5)>>> count()6>>> count()7>>> count2 = counter(25)>>> count2()26>>> count2()27>>> count3 = counter(5) # 每次调用counter()都会返回一个新的函数,即使传入相同的参数也是不同。>>> count == count3False

11、生成器

  • 1、yield 是一个关键字。带有yield的函数不再是一个函数,而是一个生成器,可用于迭代。其迭代的关键是next()方法,工作原理就是通过重复调用next()方法,直至捕捉一个异常。
  • 2、yield是一个类似return的关键字,迭代一次返回yield后面的值(yield后面也可以是一个函数的调用或者表达式),然后脚本就会在这里停止,当再次迭代后,从下一行开始。
  • 3、yield是类似return一样返回一个值,如果yield和它后面的值被赋值给其他变量,那么这个新的变量就是None,除非是用send()方法才能将yield后面的值赋给新的变量。
  • 4、第一次调用时必须先next()或者send(None),否则会报错。
>>> def g():...     print '1'...     x = yield 'hello'...     print '2', 'x = ', x...     y = 5 + (yield x)...     print '3', 'y = ', y...>>> f = g()>>> f.send(2)Traceback (most recent call last):  File "
", line 1, in
TypeError: can't send non-None value to a just-started generator>>> f.send(None)1'hello'

示例代码过程解读:

# next()方法>>> def g():...     print '1'...     x = yield 'hello'...     print '2', 'x = ', x...     y = 5 + (yield x)...     print '3', 'y = ', y...>>> f = g()>>> f.next()  #第一次迭代时[yield 'hello']返回['hello'],并赋值x为None,程序执行进程停止1'hello'>>> f.next()    #第二次迭代,从第一次停止的下一行开始,从输出可以看出x的值为None2 x =  None# send()方法>>> def g():...     print '1'...     x = yield 'hello'...     print '2', 'x = ', x...     y = 5 + (yield x)...     print '3', 'y = ', y...>>> f = g()>>> f.next()1'hello'>>> f.send(5)   #send()方法会重置第一次迭代的yield,并重新赋值为send传递的新值,而且此时x会被赋值为新的值,且程序将向下执行,直到遇见新的yield。2 x =  55>>> f.send(2)   # 上次使用send()方法后yield x返回5,并在此处停止,在send(2)后,重置(yield x)为新值2.3 y =  7Traceback (most recent call last):  File "
", line 1, in
StopIteration

转载地址:http://rgarb.baihongyu.com/

你可能感兴趣的文章
管理网&业务网的一些笔记
查看>>
openstack报错解决一
查看>>
openstack报错解决二
查看>>
linux source命令
查看>>
openstack报错解决三
查看>>
乙未年年终总结
查看>>
子网掩码
查看>>
第一天上班没精神
查看>>
启动eclipse报错:Failed to load the JNI shared library
查看>>
eclipse安装插件的两种方式在线和离线
查看>>
linux下源的相关笔记(suse)
查看>>
linux系统分区文件系统划分札记
查看>>
Linux(SUSE 12)安装Tomcat
查看>>
Linux(SUSE 12)安装jboss4并实现远程访问
查看>>
Neutron在给虚拟机分配网络时,底层是如何实现的?
查看>>
netfilter/iptables全攻略
查看>>
Overlay之VXLAN架构
查看>>
Eclipse : An error occurred while filtering resources(Maven错误提示)
查看>>
在eclipse上用tomcat部署项目404解决方案
查看>>
web.xml 配置中classpath: 与classpath*:的区别
查看>>