Python入门学习(六)

发布时间:2019-09-25 08:14:31编辑:auto阅读(1573)

    在熟悉了Python中常用的一些内置函数, 那接下来我们定义一个自己的函数吧

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

    函数

    函数语法
    def functonname(parameters):
        ...
        return result
    定义空函数
    def nop():
        pass
    实际上 pass 是用来作为占位符的. 比如现在还没想好怎么写函数的代码, 就可以先放一个pass, 让其他代码可以运行起来.
    函数也是Object
    def pow(x, y):
        result = 1
        for i in range(0, y):
            result = result * x
        return result
    
    print(pow) #<function pow at 0x104147e18>

    函数也是内存中的一块区域, 函数名指向这块区域.

    fn = pow
    print(fn) #<function pow at 0x104147e18>
    print(fn(2, 10)) #1024

    参数

    • 必选参数
    • 默认参数
    • 可变参数
    • 关键字参数
    • 命名关键字参数

    必选参数

    def pow(x, y):
        result = 1
        for i in range(0, y):
            result = result * x
        return result
    
    t = pow(2, 3)
    print(t) # 8

    上面函数中, 需要两个参数分别是 x, y. 这两个参数都是必选参数, 缺一不可.
    pow函数中 x 为底数, y 为指数, 现在我想让指数默认为 2

    默认参数

    def pow(x, y = 2):
        result = 1
        for i in range(0, y):
            result = result * x
        return result
    
    t = pow(2)
    print(t) # 4

    设, 我要求多个数的和. 具体有多个参数, 我也不知道

    可变参数

    def sum_1(numbers):
        s = 0
        for x in numbers:
            s += x
        return s
    
    def sum_2(*numbers):
        s = 0
        for x in numbers:
            s += x
        return s
    
    arr = [1, 2, 4]
    print(sum_1(arr))
    print(sum_2(1, 2, 4))
    print(sum_2(*arr))

    关键字参数

    可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

    def person(name, age, **kw) :  # ** => dict
        print("kw tyep is", type(kw))
        if "city" in kw : 
            print("city :", kw["city"])
        if "job" in kw:
            print("job :", kw.get("job"))
        print("name:", name, ", age:", age, ", other:", kw)
    
    
    person("Jion", 18, city = "Beijing")
    person(name = "Tom", city = "Beijing", age = 17)
    extra = {'city': 'Beijing', 'job': 'Engineer'}
    person("Jion", 18, **extra)

    命名关键字参数

    如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数

    def person(name, age, *, city, job):
        print(name, age, city, job)

    命名关键字参数需要一个特殊分隔符 * ,* 后面的参数被视为命名关键字参数。

    >>> person('Jack', 24, city='Beijing', job='Engineer')
    Jack 24 Beijing Engineer

    如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符 * 了.

    def person(name, age, *, city = "Beijing", job):
        # 要限制关键字参数的名字, 就要用到 "命名关键字参数"
        # * 后的参数, 被视为"命名关键字参数"
        print(name, age, city, job)
    person("Jack", 24, job = "Engineer")
    x = {"city":"Shanghai", "job":"Engineer"}
    person("Jack", 23, **x)
    person("Jack", 23, city = "Beijing", job = "Engineer")
    
    def person(name, age, *args, city, job):
        print(name, age, args, city, job)
    x = {"A":1, "B":2, "C":3}
    # 当实参为 *x 时, 会将实参中的key以tuple(元组)的形式, 传递到方法内
    # person("Jack", 23, *x, city = "Beijing", job = "Engineer") # Jack 23 ('A', 'B', 'C') Beijing Engineer
    
    # 当实参为 x 时, 会将实参的整体内容做为tuple(元组)的一个元素, 传递到方法内
    person("Jack", 23, x, city = "Beijing", job = "Engineer") # Jack 23 ({'A': 1, 'B': 2, 'C': 3},) Beijing Engineer
    

    返回值

    返回常用类型

    def abs(x):
        if(x >= 0):
            return x
        else:
            retrun -x
    
    print(abs(-1)) #1
    return 类似出栈操作, return之后的语句则不被执行

    返回多个值

    def show(x, y, z):
        return x  * y * z, x + y + z
    
    x = show(2, 3, 4)
    print(x[0], x[1]) #24 9
    print(x) #(24, 9)
    当函数返回多个值时, 实际上是把多个需要返回的值, 封装成一个tuple

    返回函数

    刚刚说过, 函数也是一个Object, 所以也可以作为返回值进行返回

    递归
    def trim(s):
        if (s == ''):
            return ''
        if (ord(s[:1]) == 32):
            return trim(s[1:])
        elif (ord(s[-1:]) == 32):
            return trim(s[:-1])
        else:
            return s

    这是一个去除字符串前后空格的函数, 首先检测字符串的第一位是不是空格, 如果是去掉第一位, 再次检查新字符串的第一位 直至不是后, 检查字符串的最后一位, 如果是, 则去掉最后一位, 再次检测新字符串的最后一位.直到最后一位,不再是空格.

    闭包
    def make_adder(addend):
        def adder(augend):
            return augend + addend
        return adder
    
    p = make_adder(23)
    q = make_adder(44)
    
    print(p(100)) #123
    print(q(100)) #144

    闭包: 可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。
    在通过Python的语言介绍一下,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。

    def func(name):
        def inner_func(age):
            print 'name:', name, 'age:', age
        return inner_func
    
    bb = func('the5fire')
    bb(26)  # >>> name: the5fire age: 26

    这里面调用func的时候就产生了一个闭包——inner_func,并且该闭包持有自由变量——name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。

    def hellocounter (name):
        count = 0
        def counter():
            # 如果不加 nonlocal 会报错
            # UnboundLocalError: local variable 'count' referenced before assignment
            nonlocal count
            count += 1
            print ('Hello {0}, {1} access!'.format(name, count))
        return counter
    
    hello = hellocounter('ysisl')
    hello()
    hello()
    hello()

    在闭包函数内, 可以直接访问父函数作用域下的变量, 但不可以修改.
    python3里面,引入了一个关键字:nonlocal,这个关键字是干什么的? 就是告诉python程序, 我的这个count变量是再外部定义的, 你去外面找吧. 然后python就去外层函数找, 然后就找到了count = 0 这个定义和赋值, 程序就能正常执行了.

    装饰器

    装饰器: 是对闭包的一种实际运用的场景.

    def makebold(fn):
        def wrapped():
            return "<b>" + fn() + "</b>"
        return wrapped
    
    def makeitalic(fn):
        def wrapped():
            return "<i>" + fn() + "</i>"
        return wrapped
    
    @makebold
    @makeitalic
    def hello():
        return "hello world"
    
    print hello() # <b><i>hello world</i></b>

    相当于 makebold(makeitalic(hello()))

    import time
    
    def timecost(func):
        def wrapper(*args, **kw):
            def fn(*args, **kw):
                start = int(time.time())
                print("Call {0}() Before [{1}]".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))))
                func(*args, **kw)
                print("Call {0}() After [{1}]".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))))
                end = int(time.time())
                print("Run Cost Time {0}s".format(end - start))
    
            return fn(*args, **kw)
        return wrapper
    
    @timecost
    def now_datetime(format):
        now = int(time.time())
        print(time.strftime(format, time.localtime(now)))
    
    now_datetime("%H:%M:%S")
    
    # Call now_datetime() Before [2018-01-15 00:24:17]
    # 00:24:17
    # Call now_datetime() After [2018-01-15 00:24:17]
    # Run Cost Time 0s
    # 在方法前后加入自己想要的内容, 哈哈, 这就是传说中的AOP吗?

关键字