• python——函数


    1.函数的创建

      函数是可以调用的(可能带有参数,也可能无参),它执行某种行动并且返回一个值。一般来说,内建的callable函数可以用来判断函数是否可调用。

    1 >>> import math
    2 >>> x = 1
    3 >>> y = math.sqrt
    4 >>> callable(x)
    5 False
    6 >>> callable(y)
    7 True

      注意:callable函数在python3.0中不可使用,需要使用表达式hasattr(func,_call_)代替。

      运用函数实现斐波那契数列

    1 # 实现斐波那契数列函数
    2 def fibs(num):
    3     result = [0,1]
    4     for i in range(num-2):
    5         result.append(result[-2]+result[-1])
    6     return result
    7 # 掉用斐波那契函数
    8 result = fibs(10)
    9 print(result)

      1.文档化函数

      为了让其他人使用该函数的时候理解,可以加注释。还有另外一种方法是直接写上字符串。实例如下:

      

     1 def fibs(num):
     2     '该函数用于实现斐波那契数列'
     3     result = [0,1]
     4     for i in range(num-2):
     5         result.append(result[-2]+result[-1])
     6     return result
     7 # 查看函数说明
     8 print(fibs.__doc__)
     9 
    10 -----
    11 输出结果:
    12 D:Python27python.exe D:/pythonwork/test01/function_1.py
    13 该函数用于实现斐波那契数列

      2.并非真正函数的函数

      数学意义上的函数,总是在计算其参数后返回点什么。Python的有些函数却并非返回任何东西。在其他语言中,这类函数有可能有其他名字,比如过程。但是python的函数就是函数,基本在数学意义上不是。

      没有return语句,或者虽有return语句但是return后面没有跟任何值的函数不返回值:

    1 >>> def test():
    2 ...     print('hello python')
    3 ...     # 这里的return语句只起到结束函数的作用
    4 ...     return
    5 ...     print('hi python')
    6 ...
    7 >>> test()
    8 hello python
    9 >>> x = test()
      hello python
     >>> print(x)
      None

      test函数其实返回了一个值“None”

      注意:千万不要被默认行为所迷惑。如果if语句内返回值,那么要确保其他分支也有其他返回值,这样一来当调用者期待一个序列的时候,就不会意外地返回None。

    2.参数魔法

      1.简单区分形参和实参

      在python写在def语句中函数名后面的变量通常叫做函数的形参,而调用函数时提供的值是实参,或者称为参数。

      2.能改变参数吗?

      在函数内为参数赋值不会影响外部任何变量的值:

    1 >>> def try_to_change(n):
    2 ...     n = 'Mr.Gumby'
    3 ...
    4 >>> name = 'Mr.Entity'
    5 >>> try_to_change(name)
    6 >>> name
    7 'Mr.Entity'
    8 >>>

      为了方便理解,可以不用函数模拟一下

    1 >>> name = 'Mr.Entity'
    2 >>> n = name #这就话的作用基本上等于传参数
    3 >>> n = 'Mr.Gumby' #在函数内部完成的
    4 >>> name
    5 'Mr.Entity'

      注意:参数存储在局部作用域(local scope)内。

      如果将可变的数据结构如列表用作参数的时候会发生什么:

    1 >>> def change(n):
    2 ...     n[0] = 'Mr.Gumby'
    3 ...
    4 >>> names = ['Mr.G','Mr.Thing']
    5 >>> change(names)
    6 >>> names
    7 ['Mr.Gumby', 'Mr.Thing']
    8 >>>

      可以看到例子中参数发生了改变,解决这样的问题,可以先用切片的方法复制一个副本,然后对副本进行操作。这样就不影响原始数据了。

      3.为什么要修改参数

      使用函数改变数据结构(比如字典和列表)是一种将程序抽象化的好方法。

      假设需要编写一个存储名字并且能用名字、中间名或者姓查询联系人的程序,可以使用下面数据结构:

    1 storage = {}
    2 storage['frist'] = {}
    3 storage['middle'] = {}
    4 storage['last'] = {}

      storage这个数据结构是带有3个键'first'、'middle'、'last'的字典。每个键下面都又存储一个字典。字典中,可以使用名字(名字、中间名或姓)作为键,插入联系人列表作为值。比如要把一个英文名字加入这个数据,可以按如下操作:

     1 me = 'Magnus Lie Hetland'
     2 storage['first']['Magnus'] = [me]
     3 storage['first']['middle'] = [me]
     4 storage['first']['last'] = [me]
     5 print(storage['first']['Magnus'])
     6 print(storage['first']['middle'])
     7 print(storage['first']['last'])
     8 
     9 -------
    10 结果如下:
    11 D:Python27python.exe D:/pythonwork/test01/function_1.py
    12 ['Magnus Lie Hetland']
    13 ['Magnus Lie Hetland']
    14 ['Magnus Lie Hetland']

      将人名加到列表中的步骤有点枯燥无味,尤其是要加入很多人名的时候。代码如下:

     1 my_sister = 'Anne Lie Hetland'
     2 storage['first'].setdefault('Anne', []).append(my_sister)
     3 storage['middle'].setdefault('Lie', []).append(my_sister)
     4 storage['last'].setdefault('Hetland', []).append(my_sister)
     5 print(storage['middle']['Lie'])
     6 print(storage['first']['Anne'])
     7 
     8 ----------
     9 结果如下:
    10 D:Python27python.exe D:/pythonwork/test01/function_1.py
    11 ['Magnus Lie Hetland', 'Anne Lie Hetland']
    12 ['Anne Lie Hetland']

      如果写大程序来这样更新列表,那么很显然程序很快就会得臃肿不堪。

      怎么却解决呢,那么就要用到抽象了,抽象的要点就是隐藏更新时繁琐的细节,可以用函数来实现这个过程。

      实现一个添加查找用户名的程序,代码如下:

     1 # 创建初始化结构的函数
     2 def init(data):
     3     data['first'] = {}
     4     data['middle'] = {}
     5     data['last'] = {}
     6 
     7 # 创建查询函数
     8 def lookup(data, label, name):
     9     return data[label].get(name)
    10 
    11 # 编写增加用户名的函数
    12 def store(data, full_name):                # 使用参数data和full_name进入这个函数,这两个参数被设置为函数在外部获得的一些值。
    13     names = full_name.split()              # 通过拆分full_name,得到一个叫做names的列表
    14     if len(names) == 2:                    # 如果names的长度为2,那么插入一个字符串作为中间名
    15         names.insert(1, '')
    16     labels = ('first', 'middle', 'last')
    17     for label, name in zip(labels, names): # 使用zip函数联合表情和名字,对每一个(label,name)对,进行处理
    18         people = lookup(data, label, name) # 调用查询函数,如果存在列表则追加,不存在则创建
    19         if people:
    20             people.append(full_name)
    21         else:
    22             data[label][name] = [full_name]
    23 
    24 #####################################主函数#########################################
    25 MyNames = {}
    26 # 引用初始化结构函数
    27 init(MyNames)
    28 # 调用存储函数
    29 store(MyNames, 'Naguns Lie Hetland')
    30 store(MyNames, 'Anne Lie Hetland')
    31 store(MyNames, 'MyNames, Robin Hood')
    32 # 调用查询函数
    33 name = lookup(MyNames, 'middle', 'Lie')
    34 print(name)

      4.如果参数是不可变的呢

      在python中:函数只能修改参数对象本身。但是如果你的参数不可变(比如数字),又该怎么办呢?

      不好意思,没有办法。

     将变量的数值增1的函数可以按如下方式来写
    1
    >>> def inc(x): return x+1 2 ... 3 >>> inc(10) 4 11 5 >>> x 6 >>> foo = inc(10) 7 >>> foo 8 11
    如果真的像改变参数,那么可以使用一点小技巧,将值放置在列表中:
    9 >>> def inc_2(x): x[0] = x[0] + 1 10 ... 11 >>> foo = inc_2(10) 12 >>> foo = inc_2([10]) 13 >>> foo 14 >>> foo = [10] 15 >>> inc_2(foo) 16 >>> foo 17 [11] 18 >>>

      

      5.关键字参数和默认值

      目前为止我们所使用的参数都叫做位置参数,因为他们的位置很重要,事实上比他们的名字还重要。

      如以下例子:

     1 def hello_1(greeting, name):
     2     print('%s,%s!' % (greeting, name))
     3 
     4 
     5 def hello_2(name, greeting):
     6     print('%s,%s!' % (name, greeting))
     7 
     8 
     9 hello_1('hello', 'python')
    10 
    11 hello_2('hello', 'python')
    12 
    13 -----------------
    14 结果:(两个代码显示的功能是一样的)
    15 D:Python27python.exe D:/pythonwork/test01/function_2.py
    16 hello,python!
    17 hello,python!

      参数的顺序很难记住,为了让事情简单些,可以提供参数的名字:

    def hello_1(greeting='hello', name='python'):
    print('%s,s%'%(greeting, name))

    # 这样一来顺序就完全没有影响了
    # 但参数值一定要对应

      这类使用参数名提供的参数叫做关键字参数。他的主要作用在于可以明确每个参数的作用。避免调用错参数。

      关键字参数最厉害的地方在于可以在函数中给参数提供默认值:

    1 >>> def hello_3(greeting='Hello', name='python'):
    2 ...     print('%s,%s!'%(greeting, name))
    3 ...
    4 >>> hello_3()
    5 Hello,python!

      

      6.收集参数

      以下写法可以给函数提供多个参数

      def print_params(*params):

        print(params)

      “*”的意义就是“收集其余的位置参数”。如果不提供任何供收集的元素,params就是个空元祖

      那么能不能处理关键字参数呢?见如下代码:

    1 >>> print_params_2('Hmm...', something=42)
    2 Traceback (most recent call last):
    3   File "<stdin>", line 1, in <module>
    4 NameError: name 'print_params_2' is not defined
    5 >>>

      很明显是不行的,所以我们需要采用另外一种方法来处理关键字参数的“收集”。这是就需要用到“**”

      事例如下:

    1 >>> def print_params_3(**params):
    2 ...     print(params)
    3 ...
    4 >>> print_params_3(x=1,y=2,z=3)
    5 {'x': 1, 'z': 3, 'y': 2}
    6 >>>

      测试证明是可行的。反悔的是字典,而不是元组。

      那么放在一起是否可行呢?

    >>> def print_params_4(x,y,z=3,*pospar, **keypar):
    ...     print(x,y,z)
    ...     print(pospar)
    ...     print(keypar)
    ...
    >>> print_params_4(1,2,3,4,5,foo=1,bar=2)
    1 2 3
    (4, 5)
    {'foo': 1, 'bar': 2}
    

       回到之前怎么实现多个名字同时存储的问题上。解决方案如下:

     1 # 编写增加用户名的函数
     2 def store(data, *full_names):                  # 使用“*full_names”收集参数,实现多个名字同时存储。
     3     for full_name in full_names:               # 使用参数data和full_name进入这个函数,这两个参数被设置为函数在外部获得的一些值。
     4         names = full_name.split()              # 通过拆分full_name,得到一个叫做names的列表
     5         if len(names) == 2:                    # 如果names的长度为2,那么插入一个字符串作为中间名
     6             names.insert(1, '')
     7         labels = ('first', 'middle', 'last')
     8         for label, name in zip(labels, names):  # 使用zip函数联合表情和名字,对每一个(label,name)对,进行处理
     9             people = lookup(data, label, name)  # 调用查询函数,如果存在列表则追加,不存在则创建
    10             if people:
    11                 people.append(full_name)
    12             else:
    13                 data[label][name] = [full_name]

      

      7.参数收集的逆过程

    1 >>> params = {'name':'Sir Robin','greeting':'Well met'}
    2 >>> hello_3(**params)
    3 Well met,Sir Robin!
    4 >>>

      在定义或者调用函数时使用星号(或者双星号)仅传递元组或字典。

      星号只用在定义函数(允许使用不定数目的参数)或者调用(“分割”字典或者序列)时才有用。

      提示:

      使用拼接(splicing)操作符“传递”参数很有用,因为这样一来就不用关心参数的个数之类的问题了,例如:

    1 def foo(x, y, z, m=0, n=0):
    2     print(x, y, z, m, n)
    3 
    4 
    5 def call_foo(*args, **kwds):
    6     print('Calling foo!')
    7     foo(*args, **kwds)

      

      8.使用参数例子:

     1 def story(**kwds):
     2     return 'Once upon a time, there was a %(job)s called %(name)s.' % kwds
     3 
     4 
     5 def power(x, y, *others):
     6     # 如果为类型
     7     if others:
     8         print('Received redundant parameters:', others)
     9     return pow(x, y)
    10 
    11 
    12 def interval(start, stop=None, step=1):  # start开始值, stop结束值, step步长
    13     'Imitates range() for step >0 '      # 函数的用途
    14     if stop is None:                     # 如果没有为stop提供直...
    15         start, stop = 0, start           # 指定参数
    16     result = []                          # 定义列表
    17     i = start                            # 计算索引
    18     while i < stop:                      # 直到检索到stop的索引
    19         result.append(i)                 # 将索引添加到result内
    20         i += step                        # 用step增加索引i
    21     return result                        # 以列表的形式返回结果

    小结:

    • 抽象:抽象是隐藏多余细节的艺术。定义处理细节的函数可以让程序更加抽象。
    • 函数定义:函数使用def语句定义。他们是由语句组成的块,可以从“外部世界”获取值(参数),也可以返回一个或者多个值作为运算结果。
    • 参数:函数从参数中得到需要的信息,也就是函数调用时设定的变量。Python中有两类参数:位置参数和关键字参数。参数在给定默认值时是可选的。

      

      

      

      

      

      

      

  • 相关阅读:
    利用avicap32.dll实现的实时视频传输
    异常错误:在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式
    很不错的python 机器学习资源
    基于C#的机器学习--目录
    C#WinForm无边框窗体移动----模仿鼠标单击标题栏移动窗体位置
    C# WinForm窗体控件GroupBox修改边框颜色控件
    wireshark抓包新手使用教程
    Winform开发框架之权限管理系统功能介绍
    自定义控件开发的调试及DesignMode的状态处理
    Winform开发框架之权限管理系统改进的经验总结(4)--用户分级管理
  • 原文地址:https://www.cnblogs.com/rsdqc/p/5174255.html
Copyright © 2020-2023  润新知