一、全局变量和局部变量

1、局部变量:

函数的形参也是局部变量)
     局部变量只能在函数内部使用
     局部变量在函数调用时才能被创建,在函数调用之后会自动销毁

2、全局变量

     定义在函数外部,模块内部的变量称为全局变量
     全局变量所有函数都可以直接访问(但函数内部不能将其赋值)

# 此示例示意全局变量和局部变量
a = 100  # 全局变量
b = 200  # 全局变量

def fx(c):  # c是局部变量
    d = 400  # d是局部变量
    print(a, b, c, d)

fx(300)
print(a, b)

global_local.py

  说明:
     1. 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个模块范围内访问
     2. 在函数内部赋值语句不会对全局变量造成影响

  示意:

L = []
     def input_number():
         L2 = []
         while True:
             n = int(input("请输入正整数"))  # 1 2 3 4
             if n < 0:
                 break
             L2.append(n)
         L = L2
     input_number()
     print(L)

二、globals() / locals() 函数

   globals()  返回当前全局作用域内变量的字典
   locals()  返回当前局部作用内变量的字典

1 # globals()/ locals()函数
 2 a = 1
 3 b = 2
 4 c = 3
 5 def fn(c, d):
 6     e = 300
 7     print("locals() 返回: ", locals())
 8     print("globals() 返回: ", globals())
 9     print(c)  # 100
10     print(globals()['c'])  # 3
11 
12 fn(100, 200)

globals_locals.py

三、函数变量:

   1、函数名是变量,它在创建函数时绑定一个函数

# 此示例示意函数名fn是变量.它绑定一个函数对象
def fn():
    print("hello world!")
f1 = fn
print(fn)  # <function fn at 0x7f0df513bf28>
print(f1)  # <function fn at 0x7f0df513bf28>
print(f1())  # None

def f1():
    print("函数f1被调用")

def f2():
    print('函数f2被调用')

f1, f2 = f2, f1

f1()  # f2被调用
f2()  # f1被调用

function_variable.py

  2、一个函数可以作为另一个函数的实参传递

1 # 此示例示意一个函数可以作为别一个函数的实参传入另一个函数中(1)
 2 def f1():
 3     print("hello f1")
 4 
 5 def f2():
 6     print('hello f2')
 7 
 8 def fx(fn):
 9     print(fn)  # < function f1 at 0xXXXXXXX>
10     fn()  # 调用fn绑定的函数
11 
12 fx(f1)  # 请问是如何执行的?
13 fx(f2)

function_give_function1.py

# 此示例示意一个函数可以作为别一个函数的实参传入另一个函数中
def goodbye(L):
    for x in L:
        print("再见", x)

def hello(L):
    for x in L:
        print("你好", x)

def do_things(fn, L):
    fn(L)

do_things(goodbye, ['Tom', 'Jerry', 'Spike'])

function_give_function2.py

    看懂下面的代码在干什么:

def myinput(fn):
           L = [1, 3, 5, 7, 9]
           return fn(L)       print(myinput(max))  # 9
       print(myinput(min))  # 1
       print(myinput(sum))  # 25

  3、函数可以返回另一个函数

1 # 函数可以返回另一个函数
 2 def get_function():
 3     s = input("请输入您要做的操作: ")
 4     if s == '求最大':
 5         return max
 6     elif s == '求最小':
 7         return min
 8     elif s == '求和':
 9         return sum
10 
11 L = [2, 4, 6, 8, 10]
12 f = get_function()  # 让get_function返回给我们一个函数
13 print(f(L))

return_function.py

练习:
   写一个计算公式的解释执行器
     已知有如下一些函数:

def myadd(x, y):
           return x + y
       def mysub(x, y):
           return x - y
       def mymul(x, y):
           return x * y
     
       def get_fun(op):
           .... # 此处自己实现    get_fun(op)函数传入字符串'加'或'+' 返回myadd
     get_fun(op)函数传入字符串'乘'或'*' 返回mymul

    在主函数中程序如下:

def main():
          while True:
             s = input("请输入计算公式:")  # 10 加 20
             L = s.split()  # L=['10', '加', '20']
             a = int(L[0])
             b = int(L[2])
             fn = get_fun(L[1])
             print("结果是:", fn(a, b))  # 结果是: 30
# 方法1
def myadd(x, y):
    return x + y

def mysub(x, y):
    return x - y

def mymul(x, y):
    return x * y

def get_fun(op):
    if op == '加' or op == '+':
        return myadd
    if op in ('乘', '*'):
        return mymul
    if op in ("减", '-'):
        return mysub

def main():
    while True:
        s = input("请输入计算公式:")  # 10 加 20
        L = s.split()  # L=['10', '加', '20']
        a = int(L[0])
        b = int(L[2])
        fn = get_fun(L[1])
        print("结果是:", fn(a, b))  # 结果是: 30
main()

方法1

# 方法2
def get_fun(op):
    if op == '加' or op == '+':
        def myadd(x, y):
            return x + y
        return myadd
    if op in ('乘', '*'):
        def mymul(x, y):
            return x * y
        return mymul
    if op in ("减", '-'):
        def mysub(x, y):
            return x - y
        return mysub

def main():
    while True:
        s = input("请输入计算公式:")  # 10 加 20
        L = s.split()  # L=['10', '加', '20']
        a = int(L[0])
        b = int(L[2])
        fn = get_fun(L[1])
        print("结果是:", fn(a, b))  # 结果是: 30
main()

方法2

四、函数嵌套定义

   函数嵌套定义是指一个函数里用def语句来创建另一个函数的情况

  示例:

def fn_outter():
         print("fn_outter() 被调用")        def fn_inner():
             print("fn_inner 被调用")        fn_inner()  #调用嵌套函数fn_nner
         fn_inner()  # 第二次调用
         print('fn_outter() 调用结束')    fn_outter() # 调用外层函数
1 # 此示例示意函数的嵌套定义
 2 def fn_outter():
 3     print("fn_outter() 被调用")
 4 
 5     def fn_inner():
 6         print("fn_inner 被调用")
 7 
 8     fn_inner()  #调用嵌套函数 fn_nner
 9     fn_inner()  # 第二次调用
10     print('fn_outter() 调用结束')
11     return fn_inner
12 
13 fn_outter()  # 调用外层函数
14 # fn_inner()  # 不可以调用
15 fx = fn_outter()
16 fx()

function_embed_def.py

五、python3的四个作用域

   作用域也叫名字空间,是访问变量时查找变量名的范围空间

1、python的四个作用域 LEGB

作用域             英文解释               英文简写
  局部作用域(函数内)  Local(function)             L
  外部嵌套函数作用域  Enclosing function locals   E
  函数定义所在模块作用域  Global(module)           G
  python内置模块的作用域 Builtin(Python)          B
1 # python3的四个作用域
 2 v = 100  # 函数定义所在模块作用域(全局)
 3 def fun1():   # 外部嵌套函数作用域
 4     v = 200
 5     print("fun1.v=", v)
 6 
 7     def fun2():
 8         v = 300   # 局部作用域
 9         print("fun2.v=", v)
10     fun2() # 调用fun2
11 
12 fun1()
13 print("全局变量v=", v)

namespace.py

2、变量名查找规则:

   在访问变量时,先查找本地变量,然后是包裹此函数外部的函数内的变量,之后是全局变量,最后是内建作用域内的变量
       即: L  --->   E   --->   G ----> B

在默认情况下,变量名赋值会在当前作用域内创建变量和修改变量

3、global 语句

   作用:
     告诉解释执行器,global语句声明的一个或多个变量,这些变量的作用域为模块级的作用域,也称作全局作用域
     全局声明 global 将赋值变量映射到模块文件内部的作用域
   语法:
     global 变量名1, 变量名2, ...

# global语句
v = 100


def fn():
    global v  # 告诉解释执行器python3, v是全局变量,不是局部变量
    v = 200


fn()
print('v=', v)  # 200

global1.py

# global语句
v = 100

def fn():
    v = 200  # 不建议在global之前来创建局部变量
    print(v)
    global v
    # v = 300
    # print(v)


fn()
print('v=', v)  # 200

global2.py

# global变量列表里的变量名不能出现在函数的形参列表里
v = 100

def fx(v):
    # global v  # 此处错误!!!
    v = 300


fx(200)
print(v)

global3.py

# global_list
L = []
print("id(L)=", id(L))
def input_number():
    L2 = []
    while True:
        n = int(input("请输入正整数: "))  # 1 2 3 4
        if n < 0:
            break
        L2.append(n)
    # L = L2       # 创建局部变量,未改变全局变量L的绑定关系
    # L.extend(L2)  # 根据变量找到列表,改变的是列表而不是变量
    # L += L2    # 出错  L = L + L2
    return L2

input_number()
print(L)  # 打印什么?
print('id(L)=', id(L))

global_list.py

   说明:
     1. 全局变量如果要在函数内部被赋值,则必须经过全局声明(否则会被认为是局部变量)
     2. 全局变量在函数内部不经过声明就可以直接访问
     3.不能先声明局部变量,再用global声明为全局变量,此做法不附合规则
     4. global变量列表里的变量名不能出现在函数的形参列表里

4、nonlocal语句

   作用:
       告诉解释执行器,nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
   语法:
     nonlocal 变量名1, 变量名2, ....

1 # nonlocal语句
 2 v = 100
 3 
 4 def f1():
 5     v = 200
 6     print("f1.v=", v)
 7 
 8     def f2():
 9         nonlocal v
10         v = 300
11         print("f2.v=", v)
12     f2()
13     print("调用f2()后的f1.v = ", v)
14 
15 
16 f1()
17 print("全局的v=", v)

nonlocal1.py

# 当有两层或两层以上函数嵌套时,
# 访问nonlocal变量只对最近一层变量进行操作
v = 100
def f1():
    v = 200
    def f2():
        v = 300
        def f3():
            nonlocal v
            v = 400
        f3()
        print("f2.v=", v)
    f2()
    print("f1.v = ", v)
f1()

nonlocal2.py

  说明:
1.
2.
3.
4.

六、def 语句

1、def语法:

      def 变量/函数名(形参):
          ....

2、lambda 表达式

   作用:
      创建一个匿名函数对象
      同 def 类似,但不提供函数名
   语法:
     lambda [形参名1, 形参名2, ...]: 表达式

# def myadd(x, y):
#     return x + y
# 以上等同于 myadd = lambda x, y: x + y

myadd = lambda x, y: x + y

print('20 + 30 =', myadd(20, 30))  # 50
print('40 + 50 =', myadd(40, 50))  # 90

lambda.py

    语法说明:
     1. lambda 只是一个表达式,它用来创建一个函数
     2.当lambda 表达式调用时,先执行冒号(:)后的表达式,并返回表达式的结果的引用
     3. lambda 表达式创建的函数只能包含一条表达式
     4. lambda比函数简单且可以随时创建和销毁,有利于减少程序的偶合度

练习:

   1. 写一个lambda表达式,创建一个函数,此函数判断参数n的平方加1能否被5整除.如果能整除返回True,否则返回False

fx = lambda n: ...
     print(fx(3))  # True
     print(fx(4))  # False
# 方法1
# fx = lambda n: (n ** 2 + 1) % 5 == 0

# 方法2
fx = lambda n: True if (n ** 2 + 1) % 5 == 0 else False

print(fx(3))  # True
print(fx(4))  # False

练习1.py

  2. 写一个lambda表达式,返两个形参的最大值

def mymax(x, y):
         ...
     mymax = lambda .....
     print(mymax(100, 200))  # 200

  看懂下面的程序在做什么?

def fx(f, x, y):
         print(f(x, y))    fx((lambda a, b: a + b), 100, 200)
     fx((lambda x, y: x ** y), 3, 4)
# 方法1
# def mymax(x, y):
#     return max(x, y)
#     if x > y:
#         return x
#     return y

# 方法2
# mymax = lambda x, y: x if x > y else y

# 方法3
mymax = lambda x, y: max(x, y)

print(mymax(100, 200))  # 200

练习2.py

七、eval, exec 函数

1、eval() 函数

   作用:
     把一个字符串当成一个表达式来执行,返回表达式执行后的结果
   格式:
     eval(source, globals=None, locals=None)

# eval函数
x = 100
y = 200
s = "x + y"
a = eval(s)  # 解释执行s字符串,把表达式的值返回回来
print(a)  # 300

b = eval(s, None, {'x': 1, 'y': 2})
print(b)

c = eval(s, {'x': 10, 'y': 20}, {'x': 1})
print(c)  # 21

eval1.py

# eval函数
n = int(eval(input("请输入一个表达式")))

eval2.py

2、exec() 函数

   作用:
     把一个字符串当成程序来执行
   格式:

exec(source, globals=None, locals=None)


   示例:

s = "x=100\ny=200\nprint('x+y=', x+y)\ndel x, y"
     exec(s)
# exec函数
s = "x=100\ny=200\nprint('x+y=',x+y)\ndel x, y"
exec(s)

exec.py

练习:

   1. 给出一个数n,写一个函数myfac(n)来计算n!(n的阶乘)
     n! = 1*2*3*4*....*n

      print(myfac(5))  # 120

def myfac(n):
    s = 1
    for x in range(1,n+1):
        s *= x 
    return s

print(myfac(5))

练习1

  2. 给出一个数n,写一个函数计算:
       1 + 2**2 + 3**3 + 4**4 + .... n**n的和

def f(n):
    # 方法2
    return sum(map(lambda x: x ** x, range(1, n + 1)))
    # 方法1
    # s = 0
    # for i in range(1, n + 1):
    #     s += i ** i
    # return s


print(f(3))

练习2

  3. 写程序打印杨辉三角 (只打印6层)

1
          1 1
         1 2 1
        1 3 3 1
       1 4 6 4 1
     1 5 10 10 5 1
#         [1]
#        [1,1]
#       [1,2,1]
#      [1,3,3,1]
#     [1,4,6,4,1]
#   [1,5,10,10,5,1]

def get_next_line(L):
    '''此函数将用一层的列表L 计算下一层然后返回
       L = [1,3,3,1], 则返回: [1,4,6,4,1]
    '''
    line = [1]  # 最左侧的1
    # 计算中间的数字
    for i in range(len(L) - 1):  # i绑定L的索引
        line.append(L[i] + L[i + 1])

    # 在最后放入一个1
    line.append(1)
    return line

def get_yh_list(n):  # n 代表行数:
    L = []
    line = [1]  # 当前是第一行
    for _ in range(n):
        L.append(line)  # 当前行放进行
        # 再算出下一行,准备放入
        line = get_next_line(line)

    return L


def list_to_string(L):
    '''此函数任意给定一个列表,将其转换为字符串
    如: L = [1, 3, 3, 1], 则返回 '1 3 3 1'
    '''
    L2 = [str(x) for x in L]  # L2 = ['1', '3', '3', '1']
    return ' '.join(L2)


# L = [
#     [1],
#     [1, 1],
#     [1, 2, 1],
#     [1, 3, 3, 1],
#     [1, 4, 6, 4, 1],
#     [1, 5, 10, 10, 5, 1]
# ]
L = get_yh_list(6)

# 得到最下面一行占几个字符的宽度:
max_char = len(list_to_string(L[-1]))

# 居中显示
for line_list in L:
    s = list_to_string(line_list)
    print(s.center(max_char))

练习3