Fork me on GitHub

Python 函数

1.1 函数定义及作用

  • 函数,就是把具有独立功能的代码块组织为一个小模块,在需要的时候调用;
  • 函数的作用:
    • 减少代码重复;
    • 方便修改,更易扩展;
    • 保持代码一致性;
# 函数定义:
#    函数名称命名规则:
#           可以由字母,下划线和数字组成
#           不能以数字开头
def 函数名():
    函数封装的代码

# 函数注释:
#     在定义函数的下方,使用连续的三对引号
#     在函数调用的位置,使用"View -> Quick Documentation"可以查看函数的说明信息
#     由于函数体相对比较独立,函数定义的上方, 应该和其他代码(包括注释)保留两个空行

# 示例一: 日志记录
import time


def logger(n):
    time_format = '%Y-%m-%d %X'
    time_current = time.strftime(time_format)

    with open('日志记录','a') as f:
        f.write('%s end action %s\n' % (time_current, n))


def action1(n):
    print('starting action1...')
    logger(n)


def action2(n):
    print('starting action2...')
    logger(n)


def action3(n):
    print('starting action3...')
    logger(n)


action1(11)
action2(22)
action3(33)

1.2 函数的参数

  • 必需参数
    • 须以正确的顺序传入函数,调用时的数量必须和声明时的一样;
  • 关键字参数
  • 默认参数(缺省参数)
  • 不定长参数
# 示例一: 必需参数
def f(name, age):
    print('Name: %s' % name)
    print('Age: %d' %age)

f('小虎',25)
f('小米', 32)


# 示例二: 关键字参数
def f(name, age):
    print('Name: %s' % name)
    print('Age: %d' % age)

f(age=28, name='小虎')    # 注意,此处传入参数的顺序与函数定义时,不一致


# 示例三: 默认参数:
def f(name, age, gender='male'):
    print('Name: %s' % name)
    print('Age: %d' % age)
    print('Gender: %s' % gender)

f('小虎', 26)     # 其中,gender参数具有默认值,在调用函数时,可以不用赋值;


# 示例四: 不定长参数(*args)
# 计算传入参数的和
def add(*args):
    print(args)
    result = 0
    for i in args:
        result += i
    print(result)


add(1, 2, 3, 4)    # 输出: (1, 2, 3, 4), Python 将不定长参数封装成元组


# 示例五: 不定长参数(**kwargs)
def stu_info(name, age):
    print('Name: %s' % name)
    print('Age: %d' % age)


# 如果需要为 stu_info 增加参数,例如:
# stu_info(name, age, job)
# stu_info(name, age, job, hobby)

def stu_info(name, age, **kwargs):
    print('Name: %s' % name)
    print('Age: %d' % age)
    print(kwargs)
    # 此处,可以循环遍历字典
    for i in kwargs:
        print('%s : %s' %(i, kwargs[i]))


stu_info('小虎', 22, job='IT', hobby='football')  
# 输出:
#   Name: 小虎
#   Age: 22
#   {'job': 'IT', 'hobby': 'football'}
# Python 将 **kwargs 不定长参数封装成字典
# kwargs = keyword arguments


# 示例六: 不定长参数
def f(*args, **kwargs):
    pass

# 备注:
#   关于不定长参数的位置: *args 放在左边, **kwargs 放在右边

# 如果参数中存在默认值的情况:
def stu_info(gender='male', *args, **kwargs):
    print(args)

stu_info(2, 3, 4, 'female')
# 输出:
#   (3, 4, 'female')
#   其中, 2 被赋值给了 gender

1.3 函数的返回值

  • 如果未在函数中指定return, 那这个函数的返回值为None;
  • 如果 return 多个对象,那么,Python 会帮我们把多个对象封装成一个元组返回;
# 示例一: 利用元组返回多个值
# 需求: 测量温度和湿度
def measure():
    """测量温度和湿度"""

    print("测量开始...")
    temp = 39
    wetness = 35
    print("测量结束...")

    # 如果函数返回的类型是元组, 小括号可以省略
    # return (temp,wetness)
    return temp, wetness


result = measure()
print(result)

# 如果需要单独的处理温度或者湿度,可以使用多个变量, 一次接收函数的返回结果;
# 注意: 使用多个变量接收结果时, 变量的个数应该和元组中元素的个数保持一致;
gl_temp, gl_wetness = measure()

print(gl_temp)
print(gl_wetness)


# 示例二: 交换两个数字
#  要求: 1. 有两个整数变量 a = 6, b = 100
#       2. 不使用其他变量, 交换两个变量的值

# 方法一:
a = a + b
b = a - b
a = a - b

# 方法二: Python 专有, 利用元组
# a, b = (b, a)
a, b = b, a

1.4 作用域

  • Python中的作用域分四种情况:
    • L: local, 局部作用域, 即函数中定义的变量;
    • E: enclosing, 嵌套在父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
    • G: global, 全局变量,就是模块级别定义的变量;
    • B: built-in, 系统固定模块里面的变量,比如 int, bytearray等。
    • 搜索变量的优先即顺序依次是: 局部作用域 > 外层作用域 > 当前模块中的全局作用域 > Python 内置作用域
      即 LEGB
  • 在Python中,只有模块(module), 类(class)以及函数(def, lambda)才会引入新的作用域,其他的代码块(例如
    if, try, for等)是不会引入新的作用域的;
# 示例一:
x = int(2.9)    # int   built-in

g_count = 11    # global
def outer():
    name = '小虎'     # enclosing

    def inner():
        i = 4       # local
        print(name)

    # print(i)  # 找不到
    inner()


outer()


# 示例二:
count = 10

def outer():
    count = 5

outer()


# 示例三:
count = 10


def outer():
    print(count)    # 注意,此处会报错,在赋值之前,使用局部变量

    # count += 1    # 此处,也会报错

    count = 5   # 此处,count 属于重新创建

outer()

# 示例四:
count = 10


def outer():
    global count    # 此处,标识 count 为全局变量
    print(count)
    count = 5

outer()

# 示例五:
def outer():
    count = 10
    def inner():
        nonlocal count  # 此处, count 为嵌套函数内变量, 使用 nonlocal 声明
        count = 3
        print(count)
    inner()
    print(count)
outer()

1.5 高阶函数

  • 函数名可以作为参数输入;
  • 函数名可以作为返回值;
# 示例:
def f(n):
    return n * n


def foo(a, b, func):
    ret = func(a) + func(b)
    return ret

print(foo(1, 2, f))     # 注意,此处函数当作参数,传入另一函数内部的形式

# 备注:
#   1. 函数名可以进行赋值,函数名存储着函数对象在内存中的地址;
#   2. 函数名可以作为函数参数,还可以作为函数的返回值;

1.6 变量说明

  • Python 中,变量数据是分开存储的;
  • 数据保存在内存中的一个位置;
  • 变量中保存着数据在内存中的地址;
  • 变量中记录数据的地址,叫做引用;
  • 使用 id() 函数可以查看变量中保存数据所在的内存地址;
def test(num):

    print("在函数内部 %d 对应的内存地址是 %d" % (num, id(num)))

a = 10

print("a 变量保存数据的内存地址是 %d" % id(a))

# 调用函数,本质上传递的是实参保存数据的引用, 而不是实参保存的数据
# 函数的返回值,本质上返回的是数据的引用,而不是数据本身
test(a)

1.7 递归函数

  • 递归特性:
    • 必须有一个明确的结束条件;
    • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少;
    • 递归效率不高,递归层次过多会导致栈溢出;
# 示例一: 求 N 的阶乘
def fact(n):
    if n==1:
        return 1

    return n*fact(n-1)

# 示例二: 斐波那契数列
def fibo_new(n):
    if n <= 1:
        return n
    return fibo_new(n-1) + fibo_new(n-2)

print(fibo_new(10))

1.8 内置函数

  • filter(): 用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表;
  • map(): 会根据提供的函数对指定序列做映射;
  • reduce(): 会对参数序列中元素进行运算:
    • 用传给reduce中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
# 示例一: filter()
# 语法: filter(function, iterable)
# 其中,function 为判断函数, iterable 为可迭代对象
# 需求: 过滤出列表中的所有奇数
def is_odd(n):
    return n % 2 == 1


newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(newlist)


# 示例二: map()
# 语法: map(function, iterable, ...)
# python 2.x 返回列表,  python 3.x 返回迭代器
# 需求: 计算平方数
def square(x):
    return x ** 2

map(square, [1, 2, 3, 4, 5])

map(lambda x: x**2, [1, 2, 3, 4, 5])    # 使用 lambda 匿名函数
# 提供了两个列表, 对相同位置的列表数据进行相加
map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])


# 示例三: reduce()
# 语法: reduce(function, iterable[, initializer])
from functools import reduce    # python3.x 使用之前,需要先导入模块

def add(x, y):
    return x + y

reduce(add, [1, 2, 3, 4, 5])    # 计算列表的和: 1+2+3+4+5
reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])

1.9 匿名函数

  • 匿名函数的命名规则:用lambda关键字标识,冒号(:)左侧表示函数接收的参数,右侧表示函数的返回值;
# 示例:
# 普通函数
def add(x, y):
    return x + y

print add(2, 3)

# 匿名函数
add = lambda a, b : a + b
print add(2, 3)

参考资料:

posted @ 2018-03-05 23:02  小a的软件思考  阅读(118)  评论(0编辑  收藏  举报