Python之函数

152 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

语法

def 函数名(参数列表):
    函数体

实例

def max(a, b):
    if a > b:
        return a
    else:
        return b
        
if __name__ == '__main__':
    print(max(3, 4))

参数传递

这个其实和java一样,只是细节上不一样,都是分为两种:

  • 不可更改-strings、tuples和numbers。如fun(a),传递的只是a的值,没有影响a对象本身。如果在fun(a)内部修改a的值,则是新生成一个a的对象。

java的不可更改的有:基础类型及基础类型对应的封装类型、String。

  • 可更改-list、dict等

java的可更改的有:把不可更改的进行封装的广大类对象。

传不可变对象实例

通过id()函数来查看内存地址变化:

def change(a):
    # 通过id()函数来查看内存地址变化
    print(id(a))
    a = 10
    print(id(a))
    
if __name__ == '__main__':
    a = 1
    print(id(a))
    change(a)

输出:

4379320568
4379320568
4379320856

传可变对象实例

def listAdd(list):
   list.append(5)

if __name__ == '__main__':
   list = [1, 2, 3, 4]
   listAdd(list)
   print(list)

调用参数的类型

必须参数

必须以正确的顺序传入函数。调用时的数量必须和声明时的一样。

def printme(a1, a2):
    a1 = a1 + "ddd"
    a2 = a2 + 1
    print(a1, a2)


if __name__ == '__main__':
    a1 = "谢谢"
    a2 = 1
    printme(a2, a1)

输出:

Traceback (most recent call last):
  File "/Users/wanghaifeng/PycharmProjects/study/basic/flow/def.py", line 32, in <module>
    printme(a2, a1)
  File "/Users/wanghaifeng/PycharmProjects/study/basic/flow/def.py", line 24, in printme
    a1 = a1 + "ddd"
TypeError: unsupported operand type(s) for +: 'int' and 'str'

这个让我感受到了动态类型的缺点,可读性和出错。

关键字参数

def printme(a1, a2):
    a1 = a1 + "ddd"
    a2 = a2 + 1
    print(a1, a2)


if __name__ == '__main__':
    a1 = "谢谢"
    a2 = 1
    printme(a1=a1, a2=a2)

这样就很明确了,这就是py的聪明之处,很灵活

默认参数

def printinfo(name, age=35):
    print("名字:", name)
    print("年龄:", age)


if __name__ == '__main__':
    printinfo(age=50, name="hf")
    print("____________")
    printinfo(name="ff")

看到默认参数方法的调用可以省略掉默认参数,让我想到了java的重载,下面我们来看看py支不支持重载:

def printinfo(name, age=35):
    print("名字:", name)
    print("年龄:", age)


def printinfo(name):
    print("名字:", name)


if __name__ == '__main__':
    printinfo(age=50, name="hf")
    print("____________")
    printinfo(name="ff")

输出:

Traceback (most recent call last):
  File "/Users/wanghaifeng/PycharmProjects/study/function/def.py", line 39, in <module>
    printinfo(age=50, name="hf")
TypeError: printinfo() got an unexpected keyword argument 'age'

可以发现报错了,其实是被下面的覆盖了。至于不同类型,因为py是弱类型,所以不可能存在,但是函数对应的是一个“动作”,动作可能会因为类型不一样导致“动作”内容(方法体)不一样,所以这点笔者认为就算有默认参数也是没有java的重载来的灵活的。

不定长参数

加了*的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数:

笔者有点乱了,go中*表示指针参数。

def printinfo(arg1, *vartuple):
    print(arg1, vartuple)


if __name__ == '__main__':
    printinfo(10)
    printinfo(70, 60, 50)

输出:

10 ()
70 (60, 50)

**的参数会以字典的形式导入:

def printinfo(arg1, **vardict):
    print(arg1, vardict)


printinfo(1, a=2, b=3)

输出:

1 {'a': 2, 'b': 3}

还是一样的感觉:灵活

单独出现*,则*后面的参数必须用关键字传入:

def f(a, b, *, c):
    return a + b + c


f(1, 2, 3)

输出:

Traceback (most recent call last):
  File "/Users/wanghaifeng/PycharmProjects/study/function/def.py", line 52, in <module>
    f(1, 2, 3)
TypeError: f() takes 2 positional arguments but 3 were given

必须这样:

def f(a, b, *, c):
    return a + b + c


# f(1, 2, 3)
f(1, 2, c=4)

匿名函数

Python使用lambda来创建匿名函数:

sum = lambda arg1, arg2: arg1 + arg2

print("相加后的值为:", sum(10, 20))
print("相加后的值为:", sum(20, 20))

我们可以将匿名函数封装在一个函数内,这样可以使用同样的代码来创建多个匿名函数:

def myfunc(n):
    return lambda a: a * n


mydoubler = myfunc(2)
mytripler = myfunc(3)

print(mydoubler(11))
print(mytripler(11))