函数2

函数目录:
  1.声明与定义比较
  2.函数属性
  3.内部/内嵌函数
  4.函数的应用
  5.变量的作用域

 

 

 

1.声明与定义比较

  在某些编程语言里,函数声明和函数定义区分开的。一个函数声明包括提供 函数名,参数的名字(传统上还有参数的类型),但不必给出函数的任何代码,具体的代码通常属于函数定义范畴

  在声明和定义有区别的语言中,往往是因为函数的定义可能和其声明放在不同的文件中。python将这两者视为一体,函数的句子由声明的标题以及随后的定义组成的。

前者引用

和其他高级语言类似,python也不允许在函数未声明之前,对其进行引用或者调用。

我们下面给出几个例子来看一下:

def func():
    print("in func()")
    bar()
def bar():
    print("in bar()")

func()    # 调用函数
这段代码是正确的!因为即使(在 foo()中)对 bar()进行的调用,且出现在 bar()的定义之前,但 foo()本身不是在 bar()声明之前被调用的。换句话说,我们声明 foo(),然后再声明bar(),接着调用 foo(),但是到那时,bar()已经存在了,所以调用成功。
注意:foo()在没有错误的情况下成功输出了'in foo()'。名字错误是当访问没有初始化的标识符时才产生的异常

 

 

 

2.函数属性

 你可以获取每个python 模块、类和函数中任意的名字空间,你可以在模块foo和bar里都有名为x的一个变量

但是在将这两个模块导入你的程序后,可以使用这两个变量,所以,即使在两个模块中使用了相同的变量名字这也是安全的,因为句点属性标识对于这两个模块中使用了意味了不同的命名空间,比如说,在这段代码中没有名字冲突。

import foo, bar
print(foo.y+bar.y)

函数属性是python 另外一个使用了句点属性标识并拥有名字空间领域

def foo():
    'foo()-- properly created doc string'

def bar():
    pass

bar.__doc__='Oops,forgot the doc str above'  # 给bar()函数赋值文档信息
bar.version =0.1  # 版本
#按住shift在空白处打开 执行时在中间加-i
PS C:\Users\asus\Desktop\python作用域\> python -i test.py
>>> foo.__doc__
'foo()-- properly created doc string'
>>>

 

上面的foo()我们以常规地方式创建了我们的文档字串,比如,在函数声明后在函数声明后第一个没有赋值的字串。

当声明 bar()时, 我们什么都没做, 仅用了句点属性标识来增加文档字串以及其他属性。我们可以接着任意地访问属性。下面是一个使用了交互解释器的例子。(你可能已经发现,用内建函数 help()显示会比用doc属性更漂亮,但是你可以选择你喜欢的方式) 

>>> help(foo)
Help on function foo in module __main__:

foo()
    foo() -- properly created doc string

>>> bar.version 
0.1
>>> foo.__doc__
'foo() -- properly created doc string'
>>> bar.__doc__
'Oops, forgot the doc str above'
>>>

注意我们是如何在函数声明外定义一个文档字串。然而我们仍然可以就像平常一样,在运行时刻访问它。然而你不能在函数的声明中访问属性。换句话说,在函数声明中没有'self‘这样的东西让你可以进行诸如dict['version'] = 0.1 的赋值。这是因为函数体还没有被创建,但之后你有了函数对象,就可以按我们在上面描述的那样方法来访问它的字典。另外一个自由的名字空间!

 

 

 

 3.内部/内嵌函数

在函数体内创建另外一个函数(对象)是完全合法的,这种函数叫做内部/内嵌函数。 最明显的创造内部函数的方法是在外部函数的定义体内定义函数(用def关键字),如在:

def foo():
    def bar():
        print("bar() called.")
    print("foo() called")
    bar()
foo()
bar()

我们将以上代码置入一个模块中,如inner.py,然后运行,我们会得到如下输出:

bar() called.
foo() called
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
>>>
http://www.pythontutor.com/visualize.html#mode=edit

将简单的代码拷贝进去,可以查看执行的步骤过程
内部函数一个有趣的方面在于整个函数体都在外部函数的作用域(即是你可以访问一个对象的区域;稍后会有更多关于作用域的介绍)之内。如果没有任何对 bar()的外部引用,那么除了在函数体内,任何地方都不能对其进行调用,这就是在上述代码执行到最后你看到异常的原因

另外一个函数体内创建函数对象的方式是使用lambda 语句。 稍后讲述。如果内部函数的定义包含了在外部函数里定义的对象的引用(这个对象甚至可以是在外部函数之外),内部函数会变成被称为闭包(closure)的特别之物。

 

 

 

4.函数应用:打印图形和数学计算

函数的嵌套调用;

程序设计的思路,复杂问题分解为简单问题。

思考1:编程实现:

  • 写一个函数打印一条横线

  • 打印自定义行数的横线

举例子说明:

#打印一行方法一
# def foo():
#     for i in range(5):
#         dar()
# def dar():
#     print("-",end=" ")
# foo()

#打印一行方法二:
# def line():
#     print("-"*15)
# line()

#打印多条横线的方法一:
# def line():
#     print("-"*15)
# line()
# def lines(n):
#     for i in range(n):
#         line()
# lines(5)

#打印多条横线方法二:
def printOneline():
    print("-"*30)

def printNumline(num):
    a=0
#因为prinOneline函数已经完成了打印横线的功能
#只需要多次调用此函数即可
    while a<num:
        printOneline()
        a+=1
printNumline(3)
例子

 

思考2:编程实现

  • 写一个函数求三个数的和

  • 写一个函数求三个数的平均值

参考代码:

# 求3个数的和
def sum3Number(a,b,c):
    return a+b+c # return 的后面可以是数值,也可是一个表达式

# 完成对3个数求平均值
def average3Number(a,b,c):

 # 因为sum3Number函数已经完成了3个数的就和,所以只需调用即可
 # 即把接收到的3个数,当做实参传递即可
 sumResult = sum3Number(a,b,c)
 aveResult = sumResult/3.0
 return aveResult

 # 调用函数,完成对3个数求平均值
 result = average3Number(11,2,55)
 print("average is %d"%result)
例子

 

 

 

5.变量作用域

标识符的作用域是定义为其声明在程序的可应用范围,或者即是我们所说的变量可见性,换句话说,就好像在问你自己,你可以在程序里的哪些部分去访问一个制定的标识符,变量可以是局部域或者是全局域。

 

5-1.全局变量与局部变量

定义在函数内的变量有局部作用域,在一个模块中最高级别的变量有全局作用域。 "声明适用的程序的范围被称为了声明的作用域,在一个过程中,如果名字在过程的声明之内,它的出现即为过程的局部变量,否则的话,出现即为非局部的". 全局变量的一个特征是除非被删除掉,否则它们的存活到脚本运行结束,且对于所有的函数,他们的值都是可以被访问的,然而局部变量,就像它们存放的栈,暂时的存在,仅仅只依赖于定义它们的函数现阶段是否处于活动,当一个函数调用出现时,其局部变量就进入声明它们的作用域,在那一刻,一个新的局部变量名为那个对象创建了,一旦函数完成,框架被释放,变量将会离开作用域。

举例子说明:

global_str='foo'
def foo():
    local_str='bar'
    return global_str+local_str
print(foo())#结果为:foobar
print(global_str)#结果为:foo
print(local_str)#会报错,因为局部变量只能在函数方法内部使用才有用
题目:
   编写函数,实现求两个序列的交集。(为方便,序列类型可以直接统一采用列表)
def intersection(num1, num2):
    intersection = []
    for i in num1:
        if i in num2:
            intersection.append(i)
    return intersection


print(intersection((1, 2, 3), [2, 3, 4]))    # [2,3]
题目

 

5-2.局部变量

例子:

def foo():
    a=666
    print('foo(),修改前a:\t',a)
    a=999
    print('foo(),修改后a:\t',a)

def bar():
    a=8899
    print('bar(),a\t',a)

运行结果:

>>> foo()
foo(),修改前a:   666
foo(),修改后a:   999
>>> bar()
bar(),a  8899
>>>

可以看出:

  • 局部变量,就是在函数内部定义的变量

  • 不同的函数,可以定义相同的名字的局部变量,但是各用个的不会产生影响

  • 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储,这就是它的作用

 

5-2.全局变量

同样,先看一下例子:

a=6699
def foo():
    print('foo(),a:\t',a)

def bar():
    print('bar(),a:\t',a)
 
print(foo())
print(bar())

运行结果:

foo(),a:     6699
None
bar(),a:     6699
None

讨论1:如果全局变量和局部变量名字相同?

a=8899
def foo():
    a=666
    print('foo(),修改前a:\t',a)
    a=888
    print('foo(),修改后a:\t',a)

def bar():
    print('bar(),a:\t',a)

foo()
bar()

运行结果为:

foo(),修改前a:     666
foo(),修改后a:     888
bar(),a:     8899

讨论2:全局变量,是能够在所有的函数中进行使用的变量,那么局部变量可否进行修改编程全局变量?我们来看下面的学习内容

 

5-3.globa语句

如果将全局变量的名字声明在一个函数体内的时候,全局变量的名字能被局部变量给覆盖掉。

a=6699
def foo():
    global a 

    print('foo(),修改前,a:\t',a)
    a=666
    print('foo(),修改后,a:\t',a)

def bar():
    print('bar(),a:\t',a)
foo()
bar()

运行结果:

foo(),修改前,a:     6699
foo(),修改后,a:     666
bar(),a:     666

通过以上例子,我们可以观察出:

  • 在函数外边定义的变量叫做全局变量

  • 全局变量能够在所有的函数中进行访问

  • 如果在函数中修改全局变量,那么就需要使用global进行声明,否则出错

  • 如果全局变量的名字和局部变量的名字相同,那么使用的是局部变量的

 

5-4.可变类型的全局变量

先举2个例子:

例子1:

a=1
def foo():
    a+=1
    print(a)
foo()#内存地址改变了

运行后:

Traceback (most recent call last):
  File "C:\Users\asus\Desktop\pythondemo测试\小巷\test.py", line 108, in <module>
    foo()
  File "C:\Users\asus\Desktop\pythondemo测试\小巷\band.py", line 106, in foo
    a+=1
UnboundLocalError: local variable 'a' referenced before assignment

 

例子2:

li=['a','b']
def foo():
    li.append('c')    
    print(li)
print(foo())
print(li)

运行结果:

['a', 'b', 'c']
None    # 函数返回值
['a', 'b', 'c']

 

posted @ 2019-04-12 13:39  下一站守候丶  阅读(263)  评论(0)    收藏  举报