函数

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

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

简而言之,如果没有显式的返回于元素或者若果返回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() called
sar() called
>>> sar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'sar' is not defined

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

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

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

执行inner.py结果:

foo() called
sar() called
Traceback (most recent call last):
File ".\inner.py", line 18, in <module>
bar()
NameError: name 'sar' is not defined

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

5、内嵌函数体补充

  • func1():
>>> def func1():
... def fo():
... print 'fo() called'
... return fo
...
>>> func1()
<function fo at 0x7fa699baab90>
>>> result = fun1c()
>>> type(result)
<type 'function'>

这里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、默认参数

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

>>> 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 "<stdin>", line 1
SyntaxError: 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 ———>> abc
arg1 2— — default
>>> test('abc', '123')
arg1 ———>> abc
arg1 2— — 123
>>> test('abc', '123', 'def', 456)
arg1 ———>> abc
arg1 2— — 123
another arg ——>> def
another 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 -->> 123
arg2 -->> 456
a -->> 789
>>> test(123, 456, a=789, b=101112)
arg1 -->> 123
arg2 -->> 456
a -->> 789
b -->> 101112
>>> test(123, 456, a=789, b=101112, c='abcdefg')
arg1 -->> 123
arg2 -->> 456
a -->> 789
c -->> abcdefg
b -->> 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 -->> 123
arg2 -->> 456
Tuple -->> 789
dict -->> abc
>>> test(123, 456, 789, 'abc', dict1='abc', dict2=135)
arg1 -->> 123
arg2 -->> 456
Tuple -->> 789
Tuple -->> abc
dict1 -->> abc
dict2 -->> 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 -->> 10
arg2 -->> 20
Tuple -->> 30
>>> test(10, 20, 30, 40)
arg1 -->> 10
arg2 -->> 20
Tuple -->> 30
Tuple -->> 40
>>> test(10, 20, 30, 40, foo=50)
arg1 -->> 10
arg2 -->> 20
Tuple -->> 30
Tuple -->> 40
foo -->> 50
>>> test(10, 20, 30, 40, foo=50, bar=60)
arg1 -->> 10
arg2 -->> 20
Tuple -->> 30
Tuple -->> 40
foo -->> 50
bar -->> 60
>>> test(10, 20, *(30, 40), **('foo':50, 'bar':60)) #字典使用{}花括号,元组使用()圆括号
File "<stdin>", line 1
test(10, 20, *(30, 40), **('foo':50, 'bar':60))
^
SyntaxError: invalid syntax
>>> test(10, 20, *(30, 40), **{'foo':50, 'bar':60})
arg1 -->> 10
arg2 -->> 20
Tuple -->> 30
Tuple -->> 40
foo -->> 50
bar -->> 60

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

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

8、函数式编程

  • 匿名函数和lambda

    lamdba 表达式运行起来就像一个函数,当被调用时,创建一个框架对象。

    语法格式:
lambda [arg1[, arg2, arg3,....argN]] : expression

示例:

>>> lambda x, y : x + y
<function <lambda> 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 "<stdin>", line 1, in <module>
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 partial
import Tkinter root = 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 == count3
False

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 "<stdin>", line 1, in <module>
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的值为None
2 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 = 5
5
>>> f.send(2) # 上次使用send()方法后yield x返回5,并在此处停止,在send(2)后,重置(yield x)为新值2.
3 y = 7
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

Python——追加学习笔记(四)的更多相关文章

  1. Python——追加学习笔记(一)

    映射.字典 ## 映射类型内建函数 * dict Error: Python核心编程(第二版)p170 >>> dict([['x', 1], ['y', 2]]) {'y': 2, ...

  2. 【Python】学习笔记四:数学运算

    python中的加减乘除比其他的语言简单,不需要对其赋值变量 加减乘除 ) #加法 ) #减法 ) #乘法 ) #除法 5.0 ) #乘方 判断 判断返回的是True或者False ) #等于 Tru ...

  3. Python——追加学习笔记(三)

    错误与异常 AttributeError:尝试访问未知的对象属性 eg. >>> class myClass(object): ... pass ... >>> m ...

  4. 【原】Learning Spark (Python版) 学习笔记(四)----Spark Sreaming与MLlib机器学习

    本来这篇是准备5.15更的,但是上周一直在忙签证和工作的事,没时间就推迟了,现在终于有时间来写写Learning Spark最后一部分内容了. 第10-11 章主要讲的是Spark Streaming ...

  5. Python——追加学习笔记(二)

    文件处理 # 文件内移动 seek()方法可以在文件中移动文件指针到不同的位置,offset字节代表相对于某个位置偏移量,默认为0,代表从文件开头算起,1代表从当前位置算起,2代表从文件末尾算起. s ...

  6. Python爬虫学习笔记(四)

    Request: Test1(基本属性:POST): 代码1: import requests # 发送POST请求 data = { } response = requests.post(url, ...

  7. 0003.5-20180422-自动化第四章-python基础学习笔记--脚本

    0003.5-20180422-自动化第四章-python基础学习笔记--脚本 1-shopping """ v = [ {"name": " ...

  8. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

  9. python3.4学习笔记(四) 3.x和2.x的区别,持续更新

    python3.4学习笔记(四) 3.x和2.x的区别 在2.x中:print html,3.x中必须改成:print(html) import urllib2ImportError: No modu ...

随机推荐

  1. 怎样把ppt格式文件放到网页上?

    方法一:把ppt文件的扩展名直接修改为pps,嵌入到网页中嵌入代码:缺点:这种方式浏览器会提示是打开,还是下载,选择打开的话会直接在浏览器中打开,并且客户端一定要安装Office PowerPoint ...

  2. mysql 显示树结构表的节点全路径

    SELECT TYPEID AS TYPEID, pTYPEID AS 父TYPEID, levels AS 父到子之间级数, concat(paths, ',', TYPEID) AS 父到子路径, ...

  3. 抽象工厂方法模式(Abstract Factory Pattern)

    Provide an interface for creating families of related or dependent objects without specifying their ...

  4. 如何在ThinkPHP中开启调试模式

    1.为什么使用调试模式? 因为调试会在我们的模板页的最后增加一些trace信息. 2.什么是trace信息? 是ThinkPHP为我们提供好的一些包含了系统运行时间.占用内存.加载时间.请求的协议.. ...

  5. AI从入门到放弃:CNN的导火索,用MLP做图像分类识别?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:郑善友 腾讯MIG后台开发工程师 导语:在没有CNN以及更先进的神经网络的时代,朴素的想法是用多层感知机(MLP)做图片分类的识别:但 ...

  6. Springboot - 自定义错误页面

    Springboot 没找到页面或内部错误时,会访问默认错误页面.这节我们来自定义错误页面. 自定义错误页面 1.在resources 目录下面再建一个 resources 文件夹,里面建一个 err ...

  7. [转]解读ASP.NET 5 & MVC6系列(8):Session与Caching

    本文转自:http://www.cnblogs.com/TomXu/p/4496445.html 在之前的版本中,Session存在于System.Web中,新版ASP.NET 5中由于不在依赖于Sy ...

  8. Windows Composition API 指南 - 认识 Composition API

    微软在 Windows 10中 面向通用 Windows 应用 (Universal Windows Apps, UWA) 新引入了一套用于用户界面合成的 API:Composition API.Co ...

  9. mvc中RedirectToAction()如何传参?

    今天在做一个功能的时,使用RedirectToAction()需要从这里传几个参数,从网上查了一下,这样解决.真好. Return RedirectToAction("Index" ...

  10. linq(查询)

    1.改变数据库某一字段的属性 db.tableName.ToList().ForEach(x => x.State = false); 2.排序 db.tableName..toList().O ...