函数

  • 函数的作用
  • 函数的使用原则
  • 函数的三种形式
  • 函数的返回值
  • 函数的参数
  • 固定参数
  • 非固定参数
  • 高阶函数
  • 匿名函数
  • 作用域
  • 递归
  • 全局变量与局部变量

为什么要用函数?

#1、代码的组织结构不清晰,可读性差
#2、遇到重复的功能只能重复编写实现代码,代码冗余
#3、功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大 

函数的使用原则:先定义,后调用。

函数即“变量”,“变量”必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名

#测试一
def foo():
    print('from foo')
    bar()
foo() #报错

#测试二
def bar():
    print('from bar')
def foo():
    print('from foo')
    bar()
foo() #正常

#测试三
def foo():
    print('from foo')
    bar()
    
def bar():
    print('from bar')
foo() #会报错吗?不会


#结论:函数的使用,必须遵循原则:先定义,后调用
#我们在使用函数时,一定要明确地区分定义阶段和调用阶段

#定义阶段,只检测语法,不执行代码
def foo():
    print('from foo')
    bar()
def bar():
    print('from bar')
#调用阶段
foo()

定义函数的三种形式

#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
#3、空函数:设计代码结构
def func1(name):  # 有参数
    print(name)
    
def func2():  # 无参数
    print("hello word")
    
    
def func3():  # 空函数
    """void funcation"""
    pass
    

函数返回值(return)

python返回值三种形式


返回值数=0;返回none

返回值数=1;返回object

返回值数>1;返回tuple

示例代码


name = "jack"


def func1():
    print(name)
    # 返回None


def func2():
    x = [1, 2, 3]
    y = {"name": "alex", "age": 56}
    return x, y, 1
    # 返回 ([1, 2, 3], {'name': 'alex', 'age': 56}, 1)

def func3():
    print(name)
    return 666
    # 返回 666

a = func1()
b = func2()
c = func3()
print(a, b, c)

函数参数

函数参数传递概念:对象作为输入发送给函数的方式

1、参数的传递是通过自动将对象赋值给本地变量名来实现的

2、在函数内部的参数名赋值不会影响调用者。因为函数头部的参数名是在函数本地的作用域的。

3、改变函数的可变对象参数的值也许对调用者有影响

不可变参数“通过值”进行传递。像整数和字符串这样的对象是通过对象引用而不是拷贝进行传递的。因为对象不可变,实际效果像拷贝一样

可变对象是通过“指针”进行传递的。列表和字典等可变对象能够在函数内部进行原处的改变,所以在函数退出后仍然有效。

def change(a, b):
    a = 2
    b[0] = "spam"
  
    
x = 1
y = [1,2]

change(x, y)

print(x, y) # 1 ['spam', 2]

形参变量

只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变

实参

可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

def calc(x, y):  # x, y 是形参
    print(x,y)
    
a, b = 1, 2
c = (a, b)  # a,b 是实参

关键参数&默认参数

关键字参数通过变量名进行匹配,使用name=value这种语法。

默认参数,在调用中没有传递,函数头部name=value就是默认参数

默认参数必须放在位置参数之后
小结:在调用时代表关键字参数,在函数头部代表默认参数

def func(a, b=2, c=3):  # b=2,c=3为 默认参数
    print(a, b, c)  # 1 4 3
    
    
func(1, b=4)  # b=4是关键字参数

非固定参数

*args

对于调用者来说,以name传递的所有对象,并作为独立的基于位置的参数

def foo(x, y, *args):
    print(x, y)  # 1 2
    print(args)  # (3, 4, 5)
    
    
foo(1, 2, 3, 4, 5) 


def foo(x, y, *args):
    print(x, y)  # 1, 2
    print(args)  # (3, 4, 5)


foo(1, 2, *[3, 4, 5])


def foo(x, y, z):
    print(x, y, z)  # 1 2 3


foo(*[1, 2, 3])

**kwargs

以name成对的传递所有的关键字,并作为独立关键字参数

def foo(x, y, **kwargs):
    print(x, y)
    print(kwargs)  # {'a': 1, 'b': 2, 'c': 3}


foo(1, y=2, a=1, b=2, c=3)


def foo(x, y, **kwargs):
    print(x, y)
    print(kwargs)  # {'a': 1, 'b': 2, 'c': 3}


foo(1, y=2, **{'a': 1, 'b': 2, 'c': 3})


def foo(x, y, z):
    print(x, y, z)  # 2 3 1


foo(**{'z': 1, 'x': 2, 'y': 3})

*args+**kwargs

def foo(x,y):
            print(x,y)

def wrapper(*args,**kwargs):
    print('====>')
    foo(*args,**kwargs)

命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递

 def foo(x,y,*args,a=1,b,**kwargs):
            print(x,y)  # 1,2
            print(args) # (3, 4, 5)
            print(a)  # 1
            print(b)  # 3
            print(kwargs)  # {'c': 4, 'd': 5}

foo(1,2,3,4,5,b=3,c=4,d=5)

参数总结:

语法 位置 解释
func(value) 调用者 常规参数:通过位置匹配
func(name=value) 调用者 关键字参数:通过变量名匹配
func(*sequence) 调用者 以name传递所有的对象,并作为其独立的给予位置的参数。
func(**dict) 调用者 以name成对的传递所有的关键字/值,并作为独立的关键字参数
def func(name) 函数 常规参数:通过位置或者变量名进行匹配
def func(name=value) 函数 默认参数值,如果没有在调用中传递的话
def func(*name) 函数 匹配并收集(在元组中)所有包含位置的参数
def func(**name) 函数 匹配并收集(在字典中)所有包含位置的参数
def func(*args, name) 函数 参数必须在调用中按照关键字传递
def func(*, name=value) 函数 python3.0+中,跟在 * name或一个单独的 * 之后的任何正式的默认的参数都是keyword-only参数,必须按照关键字传递

全局变量与局部变量

1、在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

2、全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。

3、当全局变量和局部变量同名时;在局部变量的子程序内,局部变量起作用;在其他地方全局变量起作用。

name = "Alex Li"

def change_name(name):
    print("before change:",name)
    name = "金角大王,一个有Tesla的男人"
    print("after change", name)


change_name(name)

print("在外面看看name改了么?",name)

输出

before change: Alex Li
after change 金角大王,一个有Tesla的男人
在外面看看name改了么? Alex Li

作用域

作用域的定义:在代码中变量名被赋值的位置决定了变量能否被访问的范围,这个范围就是作用域。函数定义了本地作用域,模块定义了全局作用域。

LEGB原则

L:Local
E:Enclosing function locals
G:Gobal(module)
B:Built-in(python)

首先是本地然后是函数内,之后是全局,最后是pyonth内置函数。

作用域法则

1、内嵌模块是全局作用域

2、每次对函数的调用都创建一个新的作用域

3、赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量

4、所有其他的变量名都可以归纳为本地
全局或者内置的。

作用域实例

age = 18
def func1()
    age = 73
    def func2():
        print(age)
    return 666
    
val = func1()
print(val)  # 73

思考?下面代码会输出什么?

def extend_list(val, list=[]):
	# print("in func", list)
	list.append(val)
	return list


list1 = extend_list(10)
list2 = extend_list(13, [])
list3 = extend_list('a')

print("list1",list1)
print("list2",list2)
print("list3",list3)

输出>>>

list1 [10, 'a']
list2 [13]
list3 [10, 'a']

list1和list3共享一个内空间, list2传入参数'[]',会开辟新的内存空间。

递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就叫递归函数

1.必须有一个明确的结束条件

2.每次进入更深一层递归时,问题的规模相比上次递归都应有所减少

3.递归效率不高,递归层次过多会导致栈溢出

def calc(n, count):
    print(n, count)
    if count < 5:
        return calc(n/2, count+1)
    else:
        return n

    
res = calc(188, 1)
print("res", res)

高阶函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数.

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


res = add(3,-6,abs)
print(res)

只需满足以下任意一个条件,即是高阶函数

1、接受一个或多个函数作为输入
2、return 返回另外一个函数

匿名函数

匿名函数就是不需要显式的指定函数名

calc = lambda x,y:x**y
print(calc(2,5)

匿名函数往往搭配其他函数使用

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
    print(i)

内置方法

http://www.cnblogs.com/Jason-lin/p/8186513.html

posted @ 2018-01-04 00:14  Jason_lincoln  阅读(236)  评论(0编辑  收藏  举报