一、函数
1. 简介
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。
2. 组成
- 函数代码块以 def 关键词开头,后接函数名和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数主体部分:函数内容以冒号起始,并且缩进。
- 函数结束部分:return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
示例:
1 def functionname( parameters ):
2 "函数声明、注释等内容,一般为__doc__部分"
3 函数主体部分
4 return [expression]
3. 简单调用
以上边的示例为例,调用方法很简单执行如下代码。
functionname(参数)
注意,函数定义好之后,并不会运行。只有在调用的时候会运行。
二、函数各组成部分
2.1 函数的命名
函数名应该为小写,可以用下划线风格单词以增加可读性。如:myfunction,my_example_function。
Python之父Guido推荐的命名规范包括如下几点:模块名和包名采用小写字母并且以下划线分隔单词的形式;
类名采用以大写字母开头,并且以大写字母分隔单词的形式命名;
全局或者类常量,全部使用大写字母,并且以下划线分隔单词;其余变量命名则是采用全部小写字母,并且以下划线分隔单词的形式命名。
以上的内容如果是内部的,则使用下划线开头命名。
2.2 函数参数
函数的参数分为四类:普通参数、默认参数、指定参数、可变参数
2.2.1 普通参数
1 def functionname(name,age):
2 print("I'm %s, age %s" % (name, age))
3
4 functionname("yaoming",18)
5 out: I'm yaoming, age 18
2.2.2 默认参数
1 def functionname(name,age=18):
2 print("I'm %s, age %s" % (name, age))
3
4 functionname("yaoming")
5 out: I'm yaoming, age 18
2.2.3 指定参数
1 def functionname(name,age=18):
2 print("I'm %s, age %s" % (name, age))
3
4 functionname(age=32, name="yaoming") #上述默认age参数为18,如果这里不指定age的话,默认会使用18,但是如果我们指定参数的话,优先会执行我们指定的参数值。
5 out: I'm yaoming, age 32
2.2.4 可变参数
2.2.4.1 可变参数*
1 def function_name(*args):
2 print(args, type(args))
3
4 function_name(1,2,3)
5 out: (1, 2, 3) <class 'tuple'>
6
7 function_name((1,2,3))
8 out: ((1, 2, 3),) <class 'tuple'>
由上边的例子可以看出,默认将传入的参数,全部放在元组中,即args = (...),在执行()的时候,会进行tuple.__init__方法。
1 def function_name(*args):
2 print(args, type(args))
3 function_name(*(1,2,3))
4
5 out: (1, 2, 3) <class 'tuple'>
6
7 function_name(*'wzg')
8 function_name(*['jack','tony'])
9 out: ('w', 'z', 'g') <class 'tuple'>
10 out: ('jack', 'tony') <class 'tuple'>
从上边的例子,可以看出带*的参数,会循环变量中的每个元素加入至tuple中。字符串的话循环每个字母。如果传入的是个列表或者元组,返回的是列表,元组中的每个元素。class类型都是作为'tuple'返回。
def function_name(*args):
#print(args,type(args)) for name in args:
print(name,type(name)) function_name('liupeng','jack',11,22,['a','b','c'])
out:
liupeng <class 'str'>
jack <class 'str'>
11 <class 'int'>
22 <class 'int'>
['a', 'b', 'c'] <class 'list'>
还是基于*args案例的基础上添加了for循环语句,循环的是args中的每个元素并显示元素的类型。从上例可以看出*接收的不光可以是一个字符串,还可以是数字或者列表。
2.2.4.2 可变参数**
def function_name(**args):
print(args,type(args)) function_name(name = 'wzg',job = "IT")
out: {'name': 'wzg', 'job': 'IT'} <class 'dict'> -----------------------------------------------------------
dic = {'k1':'v1','k2':'v2'}
function_name(**dic)
out: {'k2': 'v2', 'k1': 'v1'} <class 'dict'>
-----------------------------------------------------------
function_name(di = dic)
out: {'di': {'k2': 'v2', 'k1': 'v1'}} <class 'dict'>
从上边的例子可以看出,可变参数** , 默认将参数的参数,全部放在字典中进行处理。
具体分析下上例:
1.函数本身不用多说,当我们在第一次调用函数时因为参数我们指定了(name跟job的)参数因此打印时候直接输出了字典keys为name跟job,values为wzg,IT即 {'name': 'wzg', 'job': 'IT'} <class 'dict'>。
2.在第二次调用函数时,会发现我们这次调用函数()中传的参数也是**的方式。这里提前创建了一个dic的字典并把它作为函数的参数使用。结合**的用法,使得字典中每个元素作为参数传到函数中被调用。
即{'k2': 'v2', 'k1': 'v1'} <class 'dict'>。
3.最后一次调用函数时,我们参数是这么指定的(di = dic),这里可以看出跟1的使用方法相同。对了,没错。这次只不过是我们把整个dic作为了字典中的values来传入函数了而di做为了字典中的key。即
{'di': {'k2': 'v2', 'k1': 'v1'}} <class 'dict'>
总结:上面1-3不管那一种的类型最终都是<class 'dict'>也就是说**args,或者**其他什么变量最终生成的结果都是以字典的方式呈现。而*args最终都是以元组的方式呈现。
2.3 函数注释
Python有一种独一无二的的注释方式: 使用文档字符串. 文档字符串是包, 模块, 类或函数里的第一个语句. 这些字符串可以通过对象的__doc__成员被自动提取, 并且被pydoc所用。参照下面的一个代码
def function_name(big_table, keys, other_silly_variable=None):
"""Fetches rows from a Bigtable. Retrieves rows pertaining to the given keys from the Table instance
represented by big_table. Silly things may happen if
other_silly_variable is not None. Args:
big_table: An open Bigtable Table instance.
keys: A sequence of strings representing the key of each table row
to fetch.
other_silly_variable: Another optional variable, that has a much
longer name than the other args, and which does nothing. Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings. For
example: {'Serak': ('Rigel VII', 'Preparer'),
'Zim': ('Irk', 'Invader'),
'Lrrr': ('Omicron Persei 8', 'Emperor')} If a key from the keys argument is missing from the dictionary,
then that row was not found in the table. Raises:
IOError: An error occurred accessing the bigtable.Table object.
"""
function_body
return [expression] 注释
注释:
从例子中,可以看出函数注释包含以下几个部分:
1.整体功能说明 2.输入参数说明 3.输出/返回值说明 4.异常说明 5.其他
2.4 函数主体
函数主体部分就是代码逻辑的实现/处理过程。
2.5 函数返回值
函数返回值是一个可选的选项,可以返回一个表达式、某种数据结构等。默认返回None
三、函数的分类
函数大概可以分为以下几类
- 內建函数
- 自定义函数
- 匿名函数
3.1 內建函数 __builtins__
从Python3.5官网拔下来一张最新的内置函数列表
与2.7Python相比:
新增:ascii() ,bytes() , exec(),
减少:basestring() ,cmp(), execfile(), file(),long(),raw_input(),reduce(), reload() , unichr(), unicode() ,xrange()
3.2 常用內建函数
3.2 常用內建函数
函数名 | 作用 |
all(iterable) | 1、集合中的元素都为真的时候为真 2、特别的,若为空串返回为True |
any(iterable) | 1、集合中的元素有一个为真的时候为真 2、特别的,若为空串返回为False |
bool([x]) | 将x转换为Boolean类型 |
ascii() | 只要执行这个方法,则会自动调用对象的__repr__。这个函数跟repr()函数一样,返回一个可打印的对象字符串方式表示。当遇到非ASCII码时,就会输出\x,\u或\U等字符来表示。与Python 2版本里的repr()是等效的函数。 |
abs(x) | 求绝对值 |
pow(x, y[, z]) | 返回x的y次幂 |
oct(x) | 将一个数字转化为8进制 |
hex(x) | 将整数x转换为16进制字符串 |
bin(x) | 将整数x转换为二进制字符串 |
bytes("要转化的字符串", encoding="编码") | 字符串转换为字节类型 |
具体详细使用方法请参照:https://docs.python.org/3/library/functions.html#reversed
or http://www.cnblogs.com/phennry/p/5544509.html (英文不好的同学推荐)
3.3 自定义函数
我们平时使用的大多数函数,以及开发中创建的函数,都属于自定义函数。这极大的提高了代码的重用性和可读性。
自定义函数的创建和使用,在上文中已经进行了说明和示例,参照上边文章即可。这里不作过多说明。
3.4 匿名函数
python 使用 lambda 来创建匿名函数。
- lambda只是一个表达式,函数体比def简单很多。
- lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
- lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
3.4.1 匿名函数创建语法
lambda [arg1 [,arg2,.....argn]]:expression
3.4.2 示例
>>> lambda x: x+1 #一个参数
>>> lambda x,y,z:x+y+z #多个参数
>>> lambda x,y=3: x*y #允许参数存在默认值,但是默认值的参数必须参数顺序最后
e = lambda x,y = 3: x*y
print(e(4)) out:
12 a = lambda x,y=2: x*y
print(a(4,5)) out:
20 b = lambda x,y,z: x*y*z
print(b(3,5,2)) out:
30
lambda表达式
lambda表达式函数表达
通过下例可以看出普通方式跟lambda表达式的方便之处直接通过lambda表达式就能返回值。
#定义函数 (普通方式) def name(arg):
return arg + 1 #执行函数 print(name(23)) out:
24 #定义函数 (lambda表达式) my_lambda= lambda arg: arg +1 #执行函数 result = my_lambda(23) print(result) out:
24
四、作用域
python中的作用域分4种情况:
L:local,局部作用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G:global,全局变量,就是模块级别定义的变量;
B:built-in,系统固定模块里面的变量,比如int, bytearray等。
搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
补充:
函数局部变量和全局变量:
在局部中调用全局变量(读取全局变量默认不用写。修改时需要),当全局变量为列表和字典,局部引用区域引用时不使用global时也是可以修改,不能重新赋值。全局变量与局部变量名称冲突时,在函数体内部优先使用局部变量
>>> li=[11,22,33]
>>> def name(li):
li=li.append(44) #全局变量在函数体内由于是引用,所以可以别修改,但是不能被赋值
>>> name(li)
>>> print(li)
[11, 22, 33, 44] >>> li=[11,22,33]
>>> def name(li):
li='hello' #函数体内对全局变量赋值,结果没有改变
>>> name(li)
>>> print(li)
[11, 22, 33, 44] >>> li=[11,22,33]
>>> def name(arg):
global li #使用global,可以对全局变量进行修改,不建议使用
li='hello world'
>>> name(li)
>>> print(li)
hello world
五、文件操作
操作文件,一般需要经过三大步骤
1. 打开文件
2. 操作文件
3. 关闭文件(非必须)
3.1 打开文件
打开文件时,需要指定文件路径和以何等方式打开文件,打开后,即可获取该文件句柄,日后通过此文件句柄对该文件操作。通常我们使用open()函数来打开文件,源码中说明了打开模式:
模式 | 描述 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。这种方法基本不用 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ |
以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
x |
如果文件存在则报错,如果不存在,则创建文件并写内容 |
3.2 操作文件
创建文件句柄之后,可以针对句柄对文件进行如下操纵
3.3 关闭文件
这步操作并不是必须的,如果使用open()函数打开文件,那么要记得最终close()文件
如果使用with 语句打开的文件,则不需要。在with 语句主体语句执行完之后,会自动调用close()来关闭文件句柄。语法如下:
1 with open('db1', 'r', encoding="utf-8") as f1:
2 for line in f1:
3 print(line)
同时打开2个文件,语法如下:
1 with open('file1', 'r', encoding="utf-8") as f1, open("file2", 'w',encoding="utf-8") as f2:
2 pass
本章总结至此结束!
此文转载于http://www.cnblogs.com/jishuweiwang/p/5528905.html
转载此文对于函数的总结个人感觉已经非常细致,因此没有自己撰写,直接转载并对其内容做了测试并添加了部分自己的案例。
“今天的努力都是明天别人对你的膜拜,今天的停滞就是明天别人对你的唾弃!“