作者:達聞西
链接:https://zhuanlan.zhihu.com/p/24162430
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

5.2.4 函数、生成器和类

还是从几个例子看起:

def say_hello():
print('Hello!') def greetings(x='Good morning!'):
print(x) say_hello() # Hello!
greetings() # Good morning!
greetings("What's up!") # What's up!
a = greetings() # 返回值是None def create_a_list(x, y=2, z=3): # 默认参数项必须放后面
return [x, y, z] b = create_a_list(1) # [1, 2, 3]
c = create_a_list(3, 3) # [3, 2, 3]
d = create_a_list(6, 7, 8) # [6, 7, 8] def traverse_args(*args):
for arg in args:
print(arg) traverse_args(1, 2, 3) # 依次打印1, 2, 3
traverse_args('A', 'B', 'C', 'D') # 依次打印A, B, C, D def traverse_kargs(**kwargs):
for k, v in kwargs.items():
print(k, v) traverse_kargs(x=3, y=4, z=5) # 依次打印('x', 3), ('y', 4), ('z', 5)
traverse_kargs(fighter1='Fedor', fighter2='Randleman') def foo(x, y, *args, **kwargs):
print(x, y)
print(args)
print(kwargs) # 第一个pring输出(1, 2)
# 第二个print输出(3, 4, 5)
# 第三个print输出{'a': 3, 'b': 'bar'}
foo(1, 2, 3, 4, 5, a=6, b='bar')

其实和很多语言差不多,括号里面定义参数,参数可以有默认值,且默认值不能在无默认值参数之前。Python中的返回值用return定义,如果没有定义返回值,默认返回值是None。参数的定义可以非常灵活,可以有定义好的固定参数,也可以有可变长的参数(args: arguments)和关键字参数(kargs: keyword arguments)。如果要把这些参数都混用,则固定参数在最前,关键字参数在最后。

Python中万物皆对象,所以一些情况下函数也可以当成一个变量似的使用。比如前面小节中提到的用字典代替switch-case的用法,有的时候我们要执行的不是通过条件判断得到对应的变量,而是执行某个动作,比如有个小机器人在坐标(0, 0)处,我们用不同的动作控制小机器人移动:

moves = ['up', 'left', 'down', 'right']

coord = [0, 0]

for move in moves:
if move == 'up': # 向上,纵坐标+1
coord[1] += 1
elif move == 'down': # 向下,纵坐标-1
coord[1] -= 1
elif move == 'left': # 向左,横坐标-1
coord[0] -= 1
elif move == 'right': # 向右,横坐标+1
coord[0] += 1
else:
pass
print(coord) # 打印当前位置坐标

不同条件下对应的是对坐标这个列表中的值的操作,单纯的从字典取值就办不到了,所以就把函数作为字典的值,然后用这个得到的值执行相应动作:

moves = ['up', 'left', 'down', 'right']

def move_up(x):         # 定义向上的操作
x[1] += 1 def move_down(x): # 定义向下的操作
x[1] -= 1 def move_left(x): # 定义向左的操作
x[0] -= 1 def move_right(x): # 定义向右的操作
x[0] += 1 # 动作和执行的函数关联起来,函数作为键对应的值
actions = {
'up': move_up,
'down': move_down,
'left': move_left,
'right': move_right
} coord = [0, 0] for move in moves:
actions[move](coord)
print(coord)

把函数作为值取到后,直接加一括号就能使了,这样做之后起码在循环部分看上去很简洁。有点C里边函数指针的意思,只不过更简单。其实这种用法在之前讲排序的时候我们已经见过了,就是operator中的itemgetter。itemgetter(1)得到的是一个可调用对象(callable object),和返回下标为1的元素的函数用起来是一样的:

def get_val_at_pos_1(x):
return x[1] heros = [
('Superman', 99),
('Batman', 100),
('Joker', 85)
] sorted_pairs0 = sorted(heros, key=get_val_at_pos_1)
sorted_pairs1 = sorted(heros, key=lambda x: x[1]) print(sorted_pairs0)
print(sorted_pairs1)

在这个例子中我们用到了一种特殊的函数:lambda表达式。Lambda表达式在Python中是一种匿名函数,lambda关键字后面跟输入参数,然后冒号后面是返回值(的表达式),比如上边例子中就是一个取下标1元素的函数。当然,还是那句话,万物皆对象,给lambda表达式取名字也是一点问题没有的:

some_ops = lambda x, y: x + y + x*y + x**y
some_ops(2, 3) # 2 + 3 + 2*3 + 2^3 = 19

生成器(Generator

生成器是迭代器的一种,形式上看和函数很像,只是把return换成了yield,在每次调用的时候,都会执行到yield并返回值,同时将当前状态保存,等待下次执行到yield再继续:

# 从10倒数到0
def countdown(x):
while x >= 0:
yield x
x -= 1 for i in countdown(10):
print(i) # 打印小于100的斐波那契数
def fibonacci(n):
a = 0
b = 1
while b < n:
yield b
a, b = b, a + b for x in fibonacci(100):
print(x)

生成器和所有可迭代结构一样,可以通过next()函数返回下一个值,如果迭代结束了则抛出StopIteration异常:

a = fibonacci(3)
print(next(a)) # 1
print(next(a)) # 1
print(next(a)) # 2
print(next(a)) # 抛出StopIteration异常

Python3.3以上可以允许yield和return同时使用,return的是异常的说明信息:

# Python3.3以上可以return返回异常的说明
def another_fibonacci(n):
a = 0
b = 1
while b < n:
yield b
a, b = b, a + b
return "No more ..." a = another_fibonacci(3)
print(next(a)) # 1
print(next(a)) # 1
print(next(a)) # 2
print(next(a)) # 抛出StopIteration异常并打印No more消息

类(Class

Python中的类的概念和其他语言相比没什么不同,比较特殊的是protected和private在Python中是没有明确限制的,一个惯例是用单下划线开头的表示protected,用双下划线开头的表示private:

class A:
"""Class A"""
def __init__(self, x, y, name):
self.x = x
self.y = y
self._name = name def introduce(self):
print(self._name) def greeting(self):
print("What's up!") def __l2norm(self):
return self.x**2 + self.y**2 def cal_l2norm(self):
return self.__l2norm() a = A(11, 11, 'Leonardo')
print(A.__doc__) # "Class A"
a.introduce() # "Leonardo"
a.greeting() # "What's up!"
print(a._name) # 可以正常访问
print(a.cal_l2norm()) # 输出11*11+11*11=242
print(a._A__l2norm()) # 仍然可以访问,只是名字不一样
print(a.__l2norm()) # 报错: 'A' object has no attribute '__l2norm'

类的初始化使用的是__init__(self,),所有成员变量都是self的,所以以self.开头。可以看到,单下划线开头的变量是可以直接访问的,而双下划线开头的变量则触发了Python中一种叫做name mangling的机制,其实就是名字变了下,仍然可以通过前边加上“_类名”的方式访问。也就是说Python中变量的访问权限都是靠自觉的。类定义中紧跟着类名字下一行的字符串叫做docstring,可以写一些用于描述类的介绍,如果有定义则通过“类名.__doc__”访问。这种前后都加双下划线访问的是特殊的变量/方法,除了__doc__和__init__还有很多,这里就不展开讲了。

Python中的继承也非常简单,最基本的继承方式就是定义类的时候把父类往括号里一放就行了:

class B(A):
"""Class B inheritenced from A"""
def greeting(self):
print("How's going!") b = B(12, 12, 'Flaubert')
b.introduce() # Flaubert
b.greeting() # How's going!
print(b._name()) # Flaubert
print(b._A__l2norm()) # “私有”方法,必须通过_A__l2norm访问

5.2.5 map, reduce和filter

map可以用于对可遍历结构的每个元素执行同样的操作,批量操作:

map(lambda x: x**2, [1, 2, 3, 4])                 # [1, 4, 9, 16]

map(lambda x, y: x + y, [1, 2, 3], [5, 6, 7])   # [6, 8, 10]

reduce则是对可遍历结构的元素按顺序进行两个输入参数的操作,并且每次的结果保存作为下次操作的第一个输入参数,还没有遍历的元素作为第二个输入参数。这样的结果就是把一串可遍历的值,减少(reduce)成一个对象:

reduce(lambda x, y: x + y, [1, 2, 3, 4])    # ((1+2)+3)+4=10

filter顾名思义,根据条件对可遍历结构进行筛选:

filter(lambda x: x % 2, [1, 2, 3, 4, 5])    # 筛选奇数,[1, 3, 5]

需要注意的是,对于filter和map,在Python2中返回结果是列表,Python3中是生成器。

5.2.6
列表生成(list comprehension)

列表生成是Python2.0中加入的一种语法,可以非常方便地用来生成列表和迭代器,比如上节中map的两个例子和filter的一个例子可以用列表生成重写为:

[x**2 for x in [1, 2, 3, 4]]                      # [1, 4, 9 16]

[sum(x) for x in zip([1, 2, 3], [5, 6, 7])] # [6, 8, 10]

[x for x in [1, 2, 3, 4, 5] if x % 2]       # [1, 3, 5]

zip()函数可以把多个列表关联起来,这个例子中,通过zip()可以按顺序同时输出两个列表对应位置的元素对。如果要生成迭代器只需要把方括号换成括号,生成字典也非常容易:

iter_odd = (x for x in [1, 2, 3, 4, 5] if x % 2)

print(type(iter_odd))                       # <type 'generator'>

square_dict = {x: x**2 for x in range(5)}   # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

至于列表生成和map/filter应该优先用哪种,这个问题很难回答,不过Python创始人Guido似乎不喜欢map/filter/reduce,他曾在表示过一些从函数式编程里拿来的特性是个错误。

python中定义函数和参数的传递问题的更多相关文章

  1. Python中定义函数时参数有默认值的小陷阱

    在定义函数的时候,如果函数的参数有默认值,有两种类型的参数,一种是整数,字符串这种不可变类型,另一种是列表这种可变类型,对于第一种情况没有什么特殊的地方,但是对于可变类型,有一个微妙的小陷阱. 可变类 ...

  2. python中的函数的参数和可变参数

    最近在搞python的过程中需要用到给函数传可变参数..所以去网上找前人的帖子学习了一下 为了尊重原作者,这里附上链接:http://www.cnblogs.com/tqsummer/archive/ ...

  3. python 中_init_函数以及参数self

    1)class类包含: 类的属性:类中所涉及的变量 类的方法:类中函数 2)_init_函数(方法) 1.首先说一下,带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问. 2. ...

  4. Python 中的函数

    学了 Python 中的数据类型,语句,接下来就来说一下 Python 中的函数,函数是结构化编程的核心.我们使用函数可以增加程序的可读性.自定义函数时使用关键字def 函数由多条语句组成.在定义函数 ...

  5. Python中的函数(2)

    一.实参和形参        def greet_user(username): """显示简单的问候语,且显示用户名""" print(& ...

  6. Python中针对函数处理的特殊方法

    Python中针对函数处理的特殊方法 很多语言都提供了对参数或变量进行处理的机制,作为灵活的Python,提供了一些针对函数处理的特殊方法 filter(function, sequence):对se ...

  7. [19/10/13-星期日] Python中的函数

    一.函数 # 第五章 函数 ## 函数简介(function) - 函数也是一个对象 - 对象是内存中专门用来存储数据的一块区域 - 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行 ...

  8. 14.在Python中lambda函数是什么

    在Python中lambda函数是什么? It is a single expression anoymous function often used as inline function. lamb ...

  9. 『无为则无心』Python函数 — 25、Python中的函数

    目录 1.函数的使用 (1)定义函数 (2)调用函数 (3)使用函数的注意事项 2.函数的参数 3.实参的类型 Python函数的说明: Python中函数的应用非常广泛,前面章节中我们已经接触过多个 ...

随机推荐

  1. SQL查询语句 常用示例

    SQL语言的应用 1.     找出姓李的读者姓名和所在单位. 2.     列出图书库中所有藏书的书名及出版单位. 3.     查找高等教育出版社的 所有图书及单价,结果按单价降序排序. 4.   ...

  2. Codeforces 2016 ACM Amman Collegiate Programming Contest B. The Little Match Girl(贪心)

    传送门 Description Using at most 7 matchsticks, you can draw any of the 10 digits as in the following p ...

  3. <<< 入侵网站思路

    思路: 以下是入侵网站常用方法: 1.上传漏洞 如果看到:选择你要上传的文件 [重新上传]或者出现“请登陆后使用”,80%就有漏洞了! 有时上传不一定会成功,这是因为Cookies不一样.我们就要用W ...

  4. 静态关键字static(2)

    static关键字主要有两种作用: 第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关. 第二,实现某个方法或属性与类而不是对象关联在一起 具体而言,在Java语言中,static ...

  5. Angular.js通过bootstrap实现经典的表单提交

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel= ...

  6. ARCGIS常用几种本地数据AE初始化

    1.Personal GDB 新建一个在E盘的名为test的mdb: IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryCl ...

  7. debian 缺少固件怎么解决

    一般是安装的时候会遇到这个问题.http://www.debian.org/releases/stable/amd64/ch02s02.html.en 解决办法是先下载对应debian版本的firmw ...

  8. Python 字符串操作及string模块使用

    python的字符串操作通过2部分的方法函数基本上就可以解决所有的字符串操作需求: python的字符串属性函数 python的string模块 1.字符串属性方法操作: 1.>字符串格式输出对 ...

  9. [NHibernate]O/R Mapping基础

    系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) 引言 对象和关系数据库 ...

  10. JavaScript事件处理程序

    JavaScript中的事件处理程序主要分为3种: HTML事件处理程序: <script type="text/javascript"> // HTML事件处理程序 ...