zoukankan      html  css  js  c++  java
  • Python——追加学习笔记(四)

    函数

    1、python里的函数可以返回一个值或者对象,知识在返回一个容器对象的时候有点不同,看起来像是能返回多个对象。

    >>> def bar():
    ...     return 'abc', '123'
    ...
    >>> bar()
    ('abc', '123')
    >>> type(bar())   #返回的其实是元组
    <type 'tuple'>
    

    简而言之,如果没有显式的返回于元素或者若果返回None时,python会返回一个None。如果函数返回多个对象,python把他们聚集起来并以一个元组返回。

    调用函数

    1、以一对圆括号调用函数.

    >>> bar()
    ('abc', '123')
    

    创建函数

    1、def 语句

    语法:

    def function_name(arguments):
        "function_documentation_string"  #函数注释
        function_body_suite
    

    示例:

    >>> def bar():
    ...     "return a tuple"    #函数注释
    ...     return 'abc', '123'
    ...
    >>> bar()       #函数调用
    ('abc', '123')
    

    2、前向引用

    语言已经无法表达了。

    >>> def foo():
    ...     print 'In foo()'
    ...     bar()
    ...
    >>> def bar():
    ...     print 'In bar()'
    ...
    >>> foo()
    In foo()
    In bar()
    

    3、函数属性

    >>> def foo():
    ...     print 'In foo()'
    ... 
    >>> foo.__doc__     #函数注释
    >>> foo.__name__    #函数名字
    'foo'
    >>> foo.version = 0.1   #函数版本
    >>> foo.__doc__ = 'Make a test function'
    >>> help(foo)   #可以输出函数的注释文本
    

    4、内部/内嵌函数

    eg.
    python解释器输出:

    >>> def foo():
    ...     def sar():
    ...             print 'sar() called'
    ...     print 'foo() called'
    ...     sar()
    ...
    >>> foo()
    foo() called
    sar() called
    >>> sar()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'sar' is not defined
    
    

    将上述函数整合为一个模块:#inner.py

    #!/usr/bin/env python 
    # -*- coding:utf-8 -*- 
    # Script_Name: inner.py
    def foo():
        def sar():
            print 'sar() called'
        print 'foo() called'
        sar()
        
    if __name__ == '__main__':
        foo()
        sar()
    

    带有内嵌函数的外部函数,其执行顺序依然是顺序执行。
    执行inner.py结果:

    foo() called
    sar() called
    Traceback (most recent call last):
      File ".inner.py", line 18, in <module>
        bar()
    NameError: name 'sar' is not defined
    

    内嵌函数整个函数体都是在外部函数的作用域之内的,如果没有对内部函数的外部引用,那么除了函数体内,任何地方都不会对其起作用。

    5、内嵌函数体补充

    • func1():
    >>> def func1():
    ...     def fo():
    ...         print 'fo() called'
    ...     return fo
    ...
    >>> func1()
    <function fo at 0x7fa699baab90>
    >>> result = fun1c()
    >>> type(result)
    <type 'function'>
    

    这里return fo返回的是一个函数对象的引用。

    • func2():
    >>> def func2():
    ...     def fo():
    ...         print 'fo() called'
    ...     return fo()
    ...
    >>> func2()
    fo() called
    

    这里的返回[return fo()]的是一个函数(对象)的调用。

    6、传递函数(函数对象的引用和函数对象的调用)

    当对一个对象赋值时,世纪时将相同对象的引用复制给这个变量,如果这个对象是一个函数时,这个对象所有的别名都是可调用的。
    eg:

    >>> def foo():
    ...     print 'in foo()'
    ...
    >>> bar = foo #实际上是bar和foo引用了同一个函数对象,foo是函数对象的引用
    >>> foo()   #foo()是函数对象的调用
    in foo()
    >>> bar()
    in foo()
    >>>
    >>> def bar(argfunc):   #传入的参数:argfunc就是函数对象foo
    ...     argfunc()   #()双圆括号是函数调用的操作符,函数调用
    ...
    >>> bar(foo)
    in foo()
    

    7、默认参数

    实际上就是定义函数时允许设定默认的参数,如下例中的rate=0.0825.

    >>> def taxMe(cost, rate=0.0825):
    ...     return cost + (cost * rate)
    ...
    >>> taxMe(100)
    108.25
    >>> taxMe(100, 0.05)
    105.0
    

    切记:所有必须的参数都要在默认参数之前,也就是说默认参数在最后。这是强制规定。

    >>> def taxMe(cost = 100, rate):
    ...     return cost + (cost * rate)
    ...
      File "<stdin>", line 1
    SyntaxError: non-default argument follows default argument
    

    8、可变长度的参数

    • 非关键字可变长参数参数(元组)
      函数调用时可以接受一个非固定数目的参数,其使用元组的方式。
      可变长参数元组必须在位置和默认参数之后,且使用星号操作符,*(星号操作符)之后的形参座位元组传递给函数,元组保存了所有的传递给函数的额外的参数,如果没有给出额外的参数,那么元组为空。
    >>> def test(arg1, arg2 = 'default', *args):
    ...     print 'arg1 ——>> ', arg1
    ...     print 'arg2 ——>> ', arg2
    ...     for each in args:
    ...             print 'another arg ——>> ', each
    ...
    >>> test('abc')
    arg1 ———>>  abc
    arg1 2— —  default
    >>> test('abc', '123')
    arg1 ———>>  abc
    arg1 2— —  123
    >>> test('abc', '123', 'def', 456)
    arg1 ———>>  abc
    arg1 2— —  123
    another arg ——>>  def
    another arg ——>>  456
    
    • 关键字变量参数(字典)
      与非关键字可变长参数参数(元组)类似,只不过换成了**表示了。依然放在最后面,在存在元组的情况下依然在最后。
    >>> def test(arg1, arg2 = 'default', **args):
    ...     print 'arg1 -->> %s' % arg1
    ...     print 'arg2 -->> %s' % arg2
    ...     for each in args:
    ...             print '%s -->> %s' % (each, args[each])
    ...
    >>> test(123, 456, a=789)
    arg1 -->> 123
    arg2 -->> 456
    a -->> 789
    >>> test(123, 456, a=789, b=101112)
    arg1 -->> 123
    arg2 -->> 456
    a -->> 789
    b -->> 101112
    >>> test(123, 456, a=789, b=101112, c='abcdefg')
    arg1 -->> 123
    arg2 -->> 456
    a -->> 789
    c -->> abcdefg
    b -->> 101112
    

    元组和字典参数共同存在的情况下:

    >>> def test(arg1, arg2 = 'default', *argt, **args):
    ...     print 'arg1 -->> %s' % arg1
    ...     print 'arg2 -->> %s' % arg2
    ...     for each in argt:
    ...             print 'Tuple -->> %s' % each
    ...     for each in args:
    ...             print '%s -->> %s' % (each, args[each])
    ...
    >>> test(123, 456, 789, dict='abc')
    arg1 -->> 123
    arg2 -->> 456
    Tuple -->> 789
    dict -->> abc
    >>> test(123, 456, 789, 'abc', dict1='abc', dict2=135)
    arg1 -->> 123
    arg2 -->> 456
    Tuple -->> 789
    Tuple -->> abc
    dict1 -->> abc
    dict2 -->> 135
    
    • 调用带有可变长参数对象函数
      我们将非关键字参数放在元组中,将关键字参数放在字典中。
    >>> def test(arg1, arg2 = 'default', *argt, **args):
    ...     print 'arg1 -->> %s' % arg1
    ...     print 'arg2 -->> %s' % arg2
    ...     for each in argt:
    ...             print 'Tuple -->> %s' % each
    ...     for each in args:
    ...             print '%s -->> %s' % (each, args[each])
    ...
    >>>
    >>>
    >>> test(10, 20, 30)
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    >>> test(10, 20, 30, 40)
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    Tuple -->> 40
    >>> test(10, 20, 30, 40, foo=50)
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    Tuple -->> 40
    foo -->> 50
    >>> test(10, 20, 30, 40, foo=50, bar=60)
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    Tuple -->> 40
    foo -->> 50
    bar -->> 60
    >>> test(10, 20, *(30, 40), **('foo':50, 'bar':60))     #字典使用{}花括号,元组使用()圆括号
      File "<stdin>", line 1
        test(10, 20, *(30, 40), **('foo':50, 'bar':60))
                                        ^
    SyntaxError: invalid syntax
    >>> test(10, 20, *(30, 40), **{'foo':50, 'bar':60})
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    Tuple -->> 40
    foo -->> 50
    bar -->> 60
    

    此外,我们还可以在函数调用之外创建元组和字典:

    >>> t = (30, 40)
    >>> d = {'foo':50, 'bar':60}
    >>> test(10, 20, *t, **d)
    arg1 -->> 10
    arg2 -->> 20
    Tuple -->> 30
    Tuple -->> 40
    foo -->> 50
    bar -->> 60
    

    8、函数式编程

    • 匿名函数和lambda
      lamdba 表达式运行起来就像一个函数,当被调用时,创建一个框架对象。
      语法格式:
    lambda [arg1[, arg2, arg3,....argN]] : expression
    

    示例:

    >>> lambda x, y : x + y
    <function <lambda> at 0x6ffffe276e0>
    

    lambda 表达式可以用来赋值给一个如列表和元组的数据结构。

    >>> n = lambda *z : z
    >>> n('a', 'b')
    ('a', 'b')
    >>> m = lambda **y : y.keys()
    >>> m(a=123)
    ['a']
    >>> m(a=123, b=456)
    ['a', 'b']
    >>> p=lambda x : x + x
    >>> p(1)
    2
    >>> p('a')
    'aa'
    
    • 内建函数filter()、map()、reduce()

    1、filter()

    filter()是一个过滤函数。

    filter(func, seq) #func判断的布尔函数, seq需要过滤的序列

    调用一个布尔函数func来迭代遍历每个seq中的元素,返回一个使func返回值为true的元素的序列。
    eg:

    >>> def tell(x):
    ...     return x % 2
    ...
    >>> filter(tell, range(10))
    [1, 3, 5, 7, 9]
    #   可以与lambda表达式结合
    >>> filter(lambda x:x%2, range(10))     
    [1, 3, 5, 7, 9]
    # 更简单的过滤方法
    >>> [x for x in range(10) if x % 2]
    [1, 3, 5, 7, 9]
    

    2、map()

    实际上就是一个针对所有的数据进行遍历的函数。

    map(func, seq)  
    

    eg:

    >>> map((lambda x: x+3), range(10))
    [3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
    >>> def foo(x, y):
    ...     return x+y
    ...
    >>> map(foo, range(10), range(10))      #这里的func是foo而不是foo(),这点要特别注意,在之前的笔记中有提到,foo是函数的引用,foo()是函数对象的调用,这里只能是引用,函数对象的调用需要有参数,如果你执行调用会报错
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
    >>> map((foo(x, y)), range(10), range(10))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'y' is not defined
    # 使用函数对象的调用会报错
    

    3、reduce()

    语法格式:

    reduce(func, seq[, init])
    

    将二元函数作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素),连续地将现有的结果和下一个之作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值;如果返回值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。

    reduce()实际上就是一个迭代器,对seq进行逐个迭代,其中前两个作为初始值。从seq[]中依此选择两个值传入func函数,得出新的结果,并将seq中被选择的两个数值替换为新的结果,然后重复上述过程,直至结束。典型的例子就是数列求和:

    #求[0, 1, ..., 9]的和:
    >>> reduce((lambda x, y : x + y), range(10))
    45
    

    9、偏函数

    好吧,实际上我也不是很懂。。。。。。。。。。。。。。。

    >>> from operator import add, mul
    >>> from functools import partial
    # 泛化偏函数(PFA)使用partial,可以简化代码
    >>> add1 = partial(add, 1)    # add1(x) == add(1, x)
    >>> mul100 = partial(mul, 100)    #mul100(x) == mul(100, x)
    >>>
    >>> add1(10)
    11
    >>> mul100(10)
    1000
    
    • 简单GUI
    from functools import partial
    import Tkinter
    
    root = Tkinter.Tk()
    MyButton = partial(Tkinter.Button, root, fg='white', bg='blue')
    # MyButton(x) == TKinter.Button(root, fg='white', bg='blue', x)
    b1 = MyButton(text='Button1')
    b2 = MyButton(text='Button2')
    qb = MyButton(text='QUIT', bg='red', command=root.quit)
    
    b1.pack()
    b2.pack()
    qb.pack(fill=Tkinter.X, expand=True)
    root.title('PFAs!')
    root.mainloop()
    

    运行截图:

    10、变量作用域

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

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

    >>> is_this_global = 'xyz'
    >>> def  foo():
    ...         this_is_local = 'abc'
    ...         is_this_global = 'def'  #局部变量覆盖了全局变量
    ...         print this_is_local + is_this_global
    ...
    >>> foo()
    abcdef
    

    为了明确地引用一个已经命名的全局变量,必须使用global语句。

    global var1[, var2, ..., varN]
    
    >>> is_this_global = 'xyz'
    >>> def  foo():
    ...         global is_this_global
    ...         this_is_local = 'abc'
    ...         is_this_global = 'def'
    ...         print this_is_local + is_this_global
    ...
    >>> foo()
    abcdef
    
    • 闭包
      在一个内部函数内,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
      定义在外部函数内但由内部函数引用或者使用的变量称为自由变量。
      故闭包所满足的条件是:
    1. 必须有一个内嵌函数
    2. 内嵌函数必须引用外部函数中的变量
    3. 外部函数的返回值必须是内嵌函数
    
    >>> def counter(start_at=0):
    ...     count = [start_at]
    ...     def incr():
    ...             count[0] += 1
    ...             return count[0]
    ...     return incr
    ...
    >>> count = counter(5)
    >>> count()
    6
    >>> count()
    7
    >>> count2 = counter(25)
    >>> count2()
    26
    >>> count2()
    27
    >>> count3 = counter(5) # 每次调用counter()都会返回一个新的函数,即使传入相同的参数也是不同。
    >>> count == count3
    False
    

    11、生成器

    • 1、yield 是一个关键字。带有yield的函数不再是一个函数,而是一个生成器,可用于迭代。其迭代的关键是next()方法,工作原理就是通过重复调用next()方法,直至捕捉一个异常。
    • 2、yield是一个类似return的关键字,迭代一次返回yield后面的值(yield后面也可以是一个函数的调用或者表达式),然后脚本就会在这里停止,当再次迭代后,从下一行开始。
    • 3、yield是类似return一样返回一个值,如果yield和它后面的值被赋值给其他变量,那么这个新的变量就是None,除非是用send()方法才能将yield后面的值赋给新的变量。
    • 4、第一次调用时必须先next()或者send(None),否则会报错。
    >>> def g():
    ...     print '1'
    ...     x = yield 'hello'
    ...     print '2', 'x = ', x
    ...     y = 5 + (yield x)
    ...     print '3', 'y = ', y
    ...
    >>> f = g()
    >>> f.send(2)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can't send non-None value to a just-started generator
    >>> f.send(None)
    1
    'hello'
    

    示例代码过程解读:

    # next()方法
    >>> def g():
    ...     print '1'
    ...     x = yield 'hello'
    ...     print '2', 'x = ', x
    ...     y = 5 + (yield x)
    ...     print '3', 'y = ', y
    ...
    >>> f = g()
    >>> f.next()  #第一次迭代时[yield 'hello']返回['hello'],并赋值x为None,程序执行进程停止
    1
    'hello'
    >>> f.next()    #第二次迭代,从第一次停止的下一行开始,从输出可以看出x的值为None
    2 x =  None
    
    # send()方法
    >>> def g():
    ...     print '1'
    ...     x = yield 'hello'
    ...     print '2', 'x = ', x
    ...     y = 5 + (yield x)
    ...     print '3', 'y = ', y
    ...
    >>> f = g()
    >>> f.next()
    1
    'hello'
    >>> f.send(5)   #send()方法会重置第一次迭代的yield,并重新赋值为send传递的新值,而且此时x会被赋值为新的值,且程序将向下执行,直到遇见新的yield。
    2 x =  5
    5
    >>> f.send(2)   # 上次使用send()方法后yield x返回5,并在此处停止,在send(2)后,重置(yield x)为新值2.
    3 y =  7
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration
    
  • 相关阅读:
    分布式事务--AT+TCC
    Java基础面试题
    JVM问题
    集合问题
    线程问题
    微服务面试题
    【入职准备】安装STS以及整合maven
    事务----四大特性
    html小知识--创建表单
    通过css润色html表格
  • 原文地址:https://www.cnblogs.com/iskylite/p/8086421.html
Copyright © 2011-2022 走看看