函数

内建函数

要使用内建的函数, 首先要导入相应的模块

import math

上述的import 语句导入了一个名为math的模块, 可以理解为该语句创建了一个名为math的模块对象
之后就可以通过点号 '.' 调用该对象的方法了

In [14]:
import math

print(math)
print('sin(2) = ', math.sin(2))
print('sqrt(2) =' , math.sqrt(2))
print('log(math.e) = ', math.log(math.e))  # 以e为底e的对数
print('log2(4) = ', math.log2(4))          # 以2为低的对数
print('log10(10) = ', math.log10(10))      # 以10为低的对数
print('log(4) = ', math.log(4))            
print('pi = ', math.pi)
<module 'math' (built-in)>
sin(2) =  0.9092974268256817
sqrt(2) = 1.4142135623730951
log(math.e) =  1.0
log(4) =  1.3862943611198906
log2(4) =  2.0
log10(10) =  1.0
pi =  3.141592653589793

自定义函数

1.位置参数

In [6]:
# 返回a,b中较小的一个, 这里 a, b 称为位置参数
def my_min(a , b):
    return a if a < b else b 

print(my_min(2, 3))

#如果函数中没有reture语句, 则返回的是None
def say_hello():
    print('hello, this function has no return statement')

print( say_hello() )
2
hello, this function has no return statement
None

位置参数带默认值

  • 在定义函数的时候, 可以给位置参数提供默认值,和c++,java语言一样, 带有默认值的位置参数必须出现在所有位置参数的最右边
  • 给位置参数传参时, 如果以关键字的方式传入参数, 则可以不按顺序提供
  • 需要注意的是, 默认参数最好使用不可变对象, 否则如果函数内部对可变参数对象进行了修改,则该修改会体现在后面的调用中, 因此很容易导致错误发生
In [29]:
# 带有默认值参数的函数
def testDefaultArg(name, age, tel='110',  city='bj'):
    print('name = ', name )
    print('age =', age)
    print('tel = ', tel)
    print('city = ', city)
    print('-' * 15)

testDefaultArg('jack', 20, '120') 
#给位置参数传参时, 如果以关键字的方式传入参数, 则可以不按顺序提供
testDefaultArg( age=20, name='jack', city = 'hk', tel='110' )
name =  jack
age = 20
tel =  120
city =  bj
---------------
name =  jack
age = 20
tel =  110
city =  hk
---------------

2.可变参数

  • 使用星号 * 将一定范围内的位置参数收集成一个tuple(所谓的gather操作)
  • 收集的位置是从星号开始, 到后面所有的非关键字参数
In [3]:
def testVarLenArg(*args):
    print(args)

testVarLenArg(1,2, 'hello', 3.4)
testVarLenArg(1,2, 'hello', [2,3,5], ('a','b','c'))

def testVarLenArg2(name, age, *other):
    print('name = ', name, end=', ')
    print('age = ', age, end = ', ')
    print('ohter = ', other)

testVarLenArg2('jack', 20, 'boy', 'like basketball')
(1, 2, 'hello', 3.4)
(1, 2, 'hello', [2, 3, 5], ('a', 'b', 'c'))
name =  jack, age =  20, ohter =  ('boy', 'like basketball')

3.关键字参数

使用两个连续的星号 ** 将从该位置开始后面的所有参数收集成一个dict传入函数

In [5]:
def testKeywordArg(name, age, **kw):
    print('name = ', name, end=', ')
    print('age = ', age, end = ', ')
    print( 'kw = ', kw)
    
testKeywordArg('jack', 20, sex='male', hobby='basketball', city = 'earth')

# 下面这个例子中, arg收集了从第三个参数开始的所有非关键字参数
# kw则收集了所有的关键字参数
def testKeywordArg2(name, *arg , **kw):
    print('name = ', name, end = ', ')
    print('arg = ', arg, end = ', ')
    print('kw = ', kw )
    
testKeywordArg2('jack', 20, 'male', height = 180, hobby='basketball')
name =  jack, age =  20, kw =  {'sex': 'male', 'hobby': 'basketball', 'city': 'earth'}
name =  jack, arg =  (20, 'male'), kw =  {'height': 180, 'hobby': 'basketball'}

4.命名关键字参数

在上面一个例子中, 我们并不知道函数接收了那些关键字参数, 这些关键字的名字是有调用者提供的.
那么如果我们想要特定名称的关键字参数,该怎么写呢

In [10]:
def testKeywordArg3(name, *arg, height, hobby, **kw):
    print('name = ', name, end=', ')       #位置参数, 必须传入
    print('arg = ', arg, end=', ')         #可变参数
    print('height = ', height, end=', ')   #命名关键字参数, 必须传入
    print('hobby = ', hobby, end=', ')     #命名关键字参数, 必须传入
    print('kw = ', kw)                     # 关键字参数
    
testKeywordArg3('jack', 20, sex='boy', height=180, hobby='movie') #关键字参数可以任意顺序出现
testKeywordArg3('jack', height=180, hobby='movie')

# 其中, 命名关键字参数前面必须要有一个可变参数, 否则这里的 height,hobby 都会被识别成位置参数
name =  jack, arg =  (20,), height =  180, hobby =  movie, kw =  {'sex': 'boy'}
name =  jack, arg =  (), height =  180, hobby =  movie, kw =  {}


如果不需要可变参数, 但又需要命名关键字参数,则可以在命名关键字参数前面添加一个 *

In [1]:
def testKeywordArg4(name, * , height, hobby, **kw):
    print('name = ', name, end=', ')       #位置参数, 必须传入
    print('height = ', height, end=', ')   #命名关键字参数, 必须传入
    print('hobby = ', hobby, end=', ')     #命名关键字参数, 必须传入
    print('kw = ', kw)                     #关键字参数

testKeywordArg4('jack', age=20, height=180, hobby='movie', sex='boy')
# 此时不能再传入多余的位置参数, 否则会报错
try:
    testKeywordArg4('jack', 20, height=180, hobby='movie', sex='boy')
except Exception as e:
    print(e)
name =  jack, height =  180, hobby =  movie, kw =  {'age': 20, 'sex': 'boy'}
testKeywordArg4() takes 1 positional argument but 2 positional arguments (and 2 keyword-only arguments) were given

组合

这里组合 位置参数, 可变参数, 命名关键字参数, 关键字参数, 写一个综合的例子
如果上述这些参数同时出现, 其顺序必须同上

In [26]:
def testArgs(name, age=20, *arg, height=180, hobby='movie', **kw):
    print('name = ', name)       # 位置参数
    print('age = ', age)         # 位置参数, 其默认值被'test1'覆盖了
    print('arg = ', arg)         # 可变参数
    print('height = ', height)   # 命名关键字参数
    print('hobby = ', hobby)     # 命名关键字参数
    print('kw = ', kw)           # 关键字参数
testArgs('jack', 'test1', 'test2', key1='value1', key2='value2')

# 可以看到, age的默认值被 'test1' 覆盖了, 说明可变参数不会收集其前面的位置参数,即使他们有默认值
name =  jack
age =  test1
arg =  ('test2',)
height =  180
hobby =  movie
kw =  {'key1': 'value1', 'key2': 'value2'}