【Python基础】day8——函数、作用域LEGB原则

函数(subroutine 子程序,procedures 过程)

定义:

  • 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

作用:

 

  • 便于一部分代码的重用,减少重复代码
  • 方便修改代码,更易于扩展
  • 保持代码的一致性,防止重复代码段遗漏修改
import datetime

def func_first(input_text):
    f = open('test.txt','a')
    f.write("%s-%s\n" % (datetime.datetime.now(),input_text))
    f.close()
    print(datetime.datetime.now(),"-%s" % input_text)

func_first("exec func_1")
func_first("exec func_2")
func_first("exec func_3")
func_first("exec func_4")
func_first("exec func_5")

import datetime

def func_first(input_text):                              #这里的input_text相当于位置参数
    f = open('test.txt','a')
    f.write("%s-%s\n" % (datetime.datetime.now(),input_text))  #实现的结果就是每行前面可以出现当前时间,需要注意的是上一行代码插入当前时间的时候,需要转换成str字符串格式
    f.close()
    print(datetime.datetime.now(),"-%s" % input_text)

func_first("exec func_1")                                #调用函数传入可变参数,直接在函数的括号内写即可
func_first("exec func_2")
func_first("exec func_3")
func_first("exec func_4")
func_first("exec func_5")

执行结果:

2020-06-19 10:08:26.375084 -exec func_1
2020-06-19 10:08:26.376080 -exec func_2
2020-06-19 10:08:26.377078 -exec func_3
2020-06-19 10:08:26.378076 -exec func_4
2020-06-19 10:08:26.379073 -exec func_5

Process finished with exit code 0

写入文件的内容:

2020-06-19 10:08:26.374126-exec func_1
2020-06-19 10:08:26.375084-exec func_2
2020-06-19 10:08:26.376080-exec func_3
2020-06-19 10:08:26.377078-exec func_4
2020-06-19 10:08:26.378076-exec func_5

函数名的命名规则:

  • 函数名必须以下划线或者字母开头,可以包含任意字母、数字或者下划线的组合,不能使用任何的标点符号
  • 函数名是区分大小写的
  • 函数名不能使用保留字


形参和实参:

  • 形参:形式参数,不是实际存在,是虚拟变量,在定义函数和函数体的时候,使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
  • 实参:实际参数,调用函数时传给函数的参数,可以是常亮,变量,表达式,函数,传给形参


利用函数制作加法器:

def add(a,b):
    print(a+b)

add(5,7)

执行结果:

12

Process finished with exit code 0


函数的参数

必需参数

必需参数以正确的顺序传入函数,调用时的数量必须和声明时的一样

def print_info(name,age):
    print("Name: %s"%name)
    print("Age: %s"%age)

print_info('yuyang',18)

执行结果:

Name: yuyang
Age: 18

Process finished with exit code 0

关键字参数

 

def print_info(name,age):
    print("Name: %s"%name)
    print("Age: %s"%age)

print_info(age=18,name='yuyang')

执行结果:

Name: yuyang
Age: 18

Process finished with exit code 0

默认参数

def print_info(name,age=18):
    print("Name: %s"%name)
    print("Age: %s"%age)

print_info('yuyang')
print_info('jiayanping',20)

执行结果:

Name: yuyang
Age: 18
Name: jiayanping
Age: 20

Process finished with exit code 0

不定长参数

示例一:

def add(*args):
    print(args)

add(1,2,3,4)

执行结果:

(1, 2, 3, 4)

Process finished with exit code 0


示例二:

def print_info(*xargs,**kwargs):                 #如果传入键值对,就在不定长变量前面加两个*
    print(xargs)
    print(kwargs)
    print('---')
    for i in kwargs:
        print("%s:%s" % (i,kwargs[i]))

print_info('yuyang',18,name='jiayanping',age=20)

执行结果:

('yuyang', 18)                                      #元组
{'name': 'jiayanping', 'age': 20}                   #字典(因为是键值对)
---
name:jiayanping
age:20

Process finished with exit code 0


示例二中不能按下面行代码打印结果,会报错:

print_info(name='jiayanping','yuyang',18,age=20)

ERROR:

  File "H:/python_scripts/study_scripts/daily/day14/kwargs.py", line 10
    print_info(name='jiayanping','yuyang',18,age=20)
                                ^
SyntaxError: positional argument follows keyword argument

Process finished with exit code 1


加法器:

def add(*args):
    print(args)
    sum = 0
    for i in args:
        sum += i
    print("Sum: %s" % sum)
    print('---')

add(1,2,3,4)
add(1,2,3,4,5,6,7,8)

执行结果:

(1, 2, 3, 4)
Sum: 10
---
(1, 2, 3, 4, 5, 6, 7, 8)
Sum: 36
---

Process finished with exit code 0

使用下面行的代码基本上就可以让函数接收所有的参数了,不论是字符串、列表、键值对

def print_info(*xargs,**kwargs):     

 

  • 关于不定长参数,*args无命名的参数放左边,**kwargs有命名的参数放右边

  • 如果有默认参数,放左边

 

 

函数的返回值return

要想获取函数的执行结果,就可以用return语句把结果返回

注意:

  1. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,所以也可以理解为return语句代表着函数的结束
  2. 如果未在函数中指定return,那这个函数的返回值为None
  3. return多个对象,解释器会把福讴歌对象组装成一个元组作为一个一个整体结果输出

 

return
 

功能:

  1. 结束函数
  2. 返回某个对象


示例:

def f():
    print("ok")
    return 'success'

rst=f()
print(rst)

执行结果:

ok
success

Process finished with exit code 0

 

  • 函数的默认返回值是None

  • 如果return多个对象,那么python会将多个对象封装成一个元组返回

 

def f():
    print("ok")
    return 'success',1,[5,6,7]

rst=f()
print(rst)

结果:

ok
('success', 1, [5, 6, 7])

Process finished with exit code 0


从上面的结果可以看到,return可以返回多个值,只是将返回的多个值封装成一个对象返回了

 

函数的作用域


python中,作用于分为4种情况:

  • L:local,局部作用域,即函数中定义的变量
  • E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
  • G:global,全局变量,就是模块级别定义的变量
  • B:built-in,系统固定模块里面的变量,比如int、bytearray等。
  • LEGB:搜索变量的优先级顺序依次是:作用域局部 > 外层作用域 > 当前模块中的全局python内置作用域


LEGB变量示例:

x = int(3.6)   #int----built-in

y = 'yuyang'      #global

def outer():
    a = 1            #enclosing
    def inner():
        b = 2            #local
        print(x,y,a,b)
    inner()                  #注意在嵌套函数中,子函数编写完,一定要在父函数中执行子函数

outer()

执行结果:

3 yuyang 1 2

Process finished with exit code 0

注意在嵌套函数中,子函数编写完,一定要在父函数中执行子函数


ERROR案例

count = 10
def f():
    print(count)
    count = 5

f()

执行结果:

Traceback (most recent call last):
  File "H:/python_scripts/study_scripts/daily/day14/le.py", line 6, in <module>
    f()
  File "H:/python_scripts/study_scripts/daily/day14/le.py", line 3, in f
    print(count)
UnboundLocalError: local variable 'count' referenced before assignment


出现报错的原因就是:

  • 全局的变量不允许在局部修改,如果在局部修改这个变量的话,就相当于是同名了两个变量,只是作用域不同而已。
  • 如果要在局部修改全局变量可以用下面global方法
count = 10
def f():
    global count
    print(count)
    count = 5
    print(count)
f()

结果:

10
5

Process finished with exit code 0


nonlocal方法

 

def outer():
    a = 1
    def inner():
        nonlocal a            #如果变量的上一级不是全局变量的话,需要使用nonlocal,就可以修改啊变量了 
        a = 2
        print(a)
    inner()
    print(a)

outer()

执行结果:

2
2

Process finished with exit code 0


如果我们需要向函数中传入一个字典:

def f(**kwargs):
    print(kwargs)

f({'name':'yuyang'})

结果:

Traceback (most recent call last):
  File "H:/python_scripts/study_scripts/daily/day14/dict_func.py", line 4, in <module>
    f({'name':'yuyang'})
TypeError: f() takes 0 positional arguments but 1 was given

Process finished with exit code 1


正确的方式是:

def f(**kwargs):
    print(kwargs)

f(**{'name':'yuyang'})

执行结果

{'name': 'yuyang'}

Process finished with exit code 0


小结:

  1. 变量查找顺序:LEGB,作用域局部 > 外层作用域 > 当前模块中的全局 > python内置作用域
  2. 只有模块、类、及函数才能引用新的作用域
  3. 对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量
  4. 内部作用域要修改外部作用域变量的值时,全局变量要是用global关键字,嵌套作用域变量要使用nonlocal关键字,nonlocal是python3新增的关键字,有了这个关键字就能完美的实现闭包了。
  5. 函数名可以进行赋值
  6. 函数名可以作为函数参数,还可以作为函数的返回值

 


高阶函数

满足以下条件之一就是高阶函数

  • 函数名可以作为参数输入
  • 函数名可以作为返回值

示例:

def f(n):
    return n*n

def foo(a,b,func):
    print(func(a)+func(b))

foo(1,2,f)

执行结果:

5

Process finished with exit code 0


对于f()这个函数,f只是函数名,也是一个变量,只有在运行到f()的时候,才会执行函数中的代码块

 

结论:

  • 函数名字就是一个变量,所以函数名可以赋值
  • 函数名可以作为函数参数,还可以作为函数的返回值


函数名可以作为函数返回值的示例:

def foo():
    x=5
    return x

print(foo())

执行结果:

5

Process finished with exit code 0

示例二:

def foo():
    def inner():
        return 8
    return inner()

print(foo())

执行结果:

8

Process finished with exit code 0


作用域的产生

  • 只有模块(module)、类(class)以及函数(def、lambda)才会引入新的作用域,其他代码块是不会引入新的作用域的


递归函数


阶乘器

def jc(a):
    number=1
    while True:
        number = a * number
        a -= 1
        if a == 1:
            break
    print(number)

jc(7)

或者:

def jc(a):
    number=1
    for i in range(a):
        i += 1
        number = i * number
    print(number)

jc(7)

执行结果:

5040

Process finished with exit code 0


从上面的阶乘器,演变出来的递归函数,也就是上面的程序,使用递归函数编写的内容:

def fact(n):
    if n == 1:                            #对于递归函数,我们需要设定最大值使递归函数有执行上限,防止无限执行下去
        return 1                          #return可以结束函数,return后面的程序将不再执行
    return n*fact(n-1)

print(fact(5))


执行结果:

120

Process finished with exit code 0

关于递归函数的特点

  • 调用自身函数
  • 有一个结束条件
  • 但凡是递归可以写的程序,循环都可以解决
  • 递归的效率在很多时候很低,不推荐使用
  1. 必须有一个明确的结束条件
  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,由于栈大小不是无限的,所以递归调用的次数过多,会导致栈溢出)


斐波那契数列:(后一个数是前两个数的和)

0 1 1 2 3 5 8 13 21 34 55 89


斐波那契实现程序:

 

def fibo(n):
    if n<2:
        return n
    return fibo(n-1)+fibo(n-2)

print(fibo(9))

执行结果:

34

Process finished with exit code 0


内置函数

打印python中所有的内置函数

for item in dir(__builtins__):
    print(item)

结果:

ArithmeticError
AssertionError
AttributeError
BaseException
BlockingIOError
BrokenPipeError
BufferError
BytesWarning
ChildProcessError
ConnectionAbortedError
ConnectionError
ConnectionRefusedError
ConnectionResetError
DeprecationWarning
EOFError
Ellipsis
EnvironmentError
Exception
False
FileExistsError
FileNotFoundError
FloatingPointError
FutureWarning
GeneratorExit
IOError
ImportError
ImportWarning
IndentationError
IndexError
InterruptedError
IsADirectoryError
KeyError
KeyboardInterrupt
LookupError
MemoryError
ModuleNotFoundError
NameError
None
NotADirectoryError
NotImplemented
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
PermissionError
ProcessLookupError
RecursionError
ReferenceError
ResourceWarning
RuntimeError
RuntimeWarning
StopAsyncIteration
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TimeoutError
True
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
WindowsError
ZeroDivisionError
__build_class__
__debug__
__doc__
__import__
__loader__
__name__
__package__
__spec__
abs
all
any
ascii
bin
bool
bytearray
bytes
callable
chr
classmethod
compile
complex
copyright
credits
delattr
dict
dir
divmod
enumerate
eval
exec
exit
filter
float
format
frozenset
getattr
globals
hasattr
hash
help
hex
id
input
int
isinstance
issubclass
iter
len
license
list
locals
map
max
memoryview
min
next
object
oct
open
ord
pow
print
property
quit
range
repr
reversed
round
set
setattr
slice
sorted
staticmethod
str
sum
super
tuple
type
vars
zip

Process finished with exit code 0

几个重要的内置函数

filter函数

str=['a','b','c','y','n']

def f(s):
    if s != 'y':
        return s

rst = filter(f,str)
print(rst)
print(list(rst))

执行结果:

<filter object at 0x0000025F760A39B0>
['a', 'b', 'c', 'n']

Process finished with exit code 0


map函数

 

str=['a','b','c']

def f(s):
    return s + 'yuyang'

rst = map(f,str)
print(rst)
print(list(rst))

执行结果:

<map object at 0x000001E9FF4039B0>
['ayuyang', 'byuyang', 'cyuyang']

Process finished with exit code 0

 

 

reduce函数

 

from functools import reduce

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

print(reduce(add,range(1,101)))

执行结果:

5050

Process finished with exit code 0


reduce的结果就是一个值


lambda函数

a= lambda a,b: a+b

print(a(1,2))

执行结果:

3

Process finished with exit code 0

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值