11.Python编程:函数

当同一个功能、同一套算法等在多个地方重复使用,就要考虑把其抽成一个函数,在需要的地方调用即可。这样可以提高代码的复用性,也可便于维护代码。其实前面在学习循环等知识点时,已经接触到了函数。本文将详细学习Python3中的函数这一块内容,具体包括:函数的定义、调用、参数的分类、作用域等。

函数的定义规格及格式及调用

python3中定义一个函数需要遵循以下规则:

  1. 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
  2. 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  3. 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  4. 函数内容以冒号起始,并且缩进。
  5. return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。

Python 定义函数使用 def 关键字,一般格式如下:

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

实例:输入一个一元二次方程的系数,如:ax^2 + bx + c中的a,b,c,画出一个一元二次的方程的图像

# 输入一个一元二次方程的系数,如:ax^2 + bx + c中的a,b,c,画出一个一元二次的方程的图像

import math
import matplotlib.pyplot as plt
import numpy as np

# 定义函数1,用来接收一个一元二次方程的系数
def the_power_function(a1=1, b=0.0, c=0.0):

    # 调整系数符号
    b0 = fix_symbol(b)
    c0 = fix_symbol(c)

    # 调整bx
    bx = ''
    if b0 != '':
        bx = b0 + 'x'
    # 组装表达式
    funcExpress = str(a1) + 'x' + r"^2" + bx + c0
    print("一元二次函数是:" + funcExpress)
    startPoint = -( b/2/a1 + 5)
    endPoint = 5 - b/2/a1
    u = np.arange(startPoint, endPoint, 0.01)
    y1 = [[math.pow((a + b/2/a1), 2) + (c - b*b/4/a1)] for a in u]
    plt.plot(u, y1, linewidth = 1, color="#FF0000", label= funcExpress)
    plt.legend(loc = "lower right")
    plt.grid(True)
    plt.show()


# 定义函数2:一个修正系数符号的函数
def fix_symbol(c):
    if c < 0:
        return str(c)
    elif c > 0:
        return "+" + str(c)
    else:
        return ""
    
    
# 调用函数
the_power_function(1, 4, -3.8)

运行结果:

一元二次函数是:1x^2+4x-3.8

绘制的函数图像是:


一元二次函数:1x^2+4x-3.8

解析:

  1. 上面实例中定义了2个函数:
    函数1.接收一个一元二次方程的系数并绘制函数图像的函数,形参列表是方程的系数,并提供了默认参数。当用户什么也不传,或者某一参数不传时,就会使用提供的默认参数。
    函数2:用来修正方程系数的函数

2.函数的调用:在需要调用函数地方,直接写上已定义好的函数名,并按照函数签名(函数的名、形参列表)传入需要的参数即可。
3.对于函数1调用时,如果参数不传,就会使用默认参数了。关于函数参数,接下来会有详细的介绍。
4.关于画图,后面会有专门章节学习。

参数的分类

定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。

Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。

1.普通参数

普通参数是在调用函数时,要严格按照参数的类型、个数传入的,否则会报TypeError异常。

2.默认参数

当某个参数没有传入实参时,会使用函数定义时的参数的值,即默认参数。上面一元二次函数例子中,如果二次项系数a1、一次项系数b、常数项c都不传入,则按照def the_power_function(a1=1, b=0.0, c=0.0):函数定义时的a1=1, b = 0.0, c = 0.0。得到一元二次函数: 1x^2。

# 上接
# 不传入参数
the_power_function()

运行结果:一元二次函数是:1x^2

一元二次函数:1x^2的图像

从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意:

一是普通参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在普通参数前面);

二是如何设置默认参数。

当函数有多个参数时,把调用函数时必须传入的参数放前面,其他参数可以使用默认值的写在后面。这种可以使用默认值的参数就可以作为默认参数。

使用默认参数有什么好处?最大的好处是能降低调用函数的难度。

也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用the_power_function(b=4, a1=3, c=9.9),意思是,b、a1、c参数用传进去的值,其他默认参数继续使用默认值

the_power_function(b=4,  a1=3, c=9.9)

运行结果:

一元二次函数是:3x^2+4x+9.9
一元二次函数是:3x^2+4x+9.9

注意:

默认参数很有用,但使用不当,也会掉坑里。默认参数有个最大的坑,演示如下:

先定义一个函数,传入一个list,添加一个END再返回:

# 默认参数的坑
# 自定义一个list的拼接函数,参数是一个可变的、默认长度为0的list
def the_end(my_list=[]):
    my_list.append("The End")
    return my_list

list1 = ["a", "b", "c"]

# 传入实参list1
the_end(list1)
print(list1)

运行结果:

['a', 'b', 'c', 'The End']

一切正常,正如所期望的结果一样。接着传入实参list2,并打印list2:

list2 = ["1", "2", "3"]

# 传入实参list2
the_end(list2)
print(list2)

运行结果:

['1', '2', '3', 'The End']

此时,运行结果仍与预期一样。再次尝试:不传参数,使用默认的参数[]:

# 不传参数,使用默认的参数[]
print(the_end())

运行结果:

['The End']

到目前为止,无论传入新的list,还是使用默认的参数值,运行结果都如预期。但是,倘若对同一个list调用两次,具体操作如下:

# 自定义一个list的拼接函数,参数是一个可变的、默认长度为0的list
def the_end(my_list=[]):
    my_list.append("The End")
    return my_list

# 测试连续调用两次结尾函数:
print(the_end())
print(the_end())

运行结果:

[ 'The End']
['The End', 'The End']

思考:这是为什么呢?

原因解释如下:
Python函数在定义的时候,默认参数my_list的值就被计算出来了,即[],因为默认参数my_list也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

定义默认参数要牢记一点:默认参数必须指向不变对象!
优化如下:

# 默认参数的坑
# 自定义一个list的拼接函数,参数是一个可变的、默认长度为0的list
def the_end(my_list = None):
    if my_list is None:
        my_list = []
    my_list.append("The End")
    return my_list

# 测试连续调用两次结尾函数:
print(the_end())
print(the_end())

运行结果:

['The End']
['The End']

这样修改后,多次调用也没关系了。

为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。

补充:可更改(mutable)与不可更改(immutable)对象

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:

不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

3.可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,当然还可以是0个。在其它高级编程语言,如Java,C等都支持该语法,这在一定程度上大大提高了函数的灵活性。

我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:

# 定义一个求平方的和的函数
def get_sum(nums):
    total = 0
    for i in nums:
        total = total + i * i
    print(total)
    return total

但是调用的时候,需要先组装出一个list或tuple:

# 但是调用的时候,需要先组装出一个list或tuple:
nums1 = [1, 2, 3, 4]
# 调用求平方的和的函数
get_sum(nums1)

运行结果:
30

如果利用可变参数,调用函数的方式可以简化成这样:
get_sum(1, 2, 3, 4)
为了支持这种方便快捷的调用函数,我们把函数的参数改为可变参数:

# 定义一个求平方和的函数(可变参数形式)
def get_sum_mutable_params(*nums):
    total = 0
    for i in nums:
        total = total + i * i
    print(total)
    return total

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:

# 调用函数
get_sum_mutable_params(1, 2, 3, 4)
get_sum_mutable_params(1, 2, 3, 4, 5, 6, 7)

运行结果:

30
140

如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:

nums1 = [1, 2, 3, 4]
# 调用函数
get_sum_mutable_params(nums1[0], nums1[1], nums1[2], nums1[3])

运行结果:30
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

nums1 = [1, 2, 3, 4]

# 使用*将一个list或tuple中的元素,传入给可变参数
get_sum_mutable_params(*nums1)

运行结果:30

*nums1 表示把nums1这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。
提示:可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。

4.关键字参数

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

比如,大家在某网站注册账号时,除了必填信息(如:注册账号、登录密码)外,还有一些是可选填项(如:爱好,地区等)。

# 关键字参数
def enrollment(account, pwd, **kws):
    print('account:', account, ' pwd:', pwd, ' other:', kws)

enrollment("15639067890@163.com", r'******')
enrollment("15639067890@163.com", r'******', city="北京")

运行结果:

account: 15639067890@163.com  pwd: ******  other: {}
account: 15639067890@163.com  pwd: ******  other: {'city': '北京'}

说明:函数enrollment()除了必选参数account和pwd外,还接受关键字参数kws。在调用该函数时,可以只传入必选参数。也可以传入任意个数的关键字参数:

# 关键字参数
def enrollment(account, pwd, **kws):
    print('account:', account, ' pwd:', pwd, ' other:', kws)

enrollment("15639067890@163.com", r'******')
enrollment("15639067890@163.com", r'******', city="北京")
enrollment("15639067891@163.com", r'***', city="广州", sex='male')
enrollment("15639067892@163.com", r'*****', city="上海", name='Wang DaChui')

运行结果:

# 只传入必传参数
account: 15639067890@163.com  pwd: ******  other: {}

# 既有必传参数,又有关键词参数
account: 15639067890@163.com  pwd: ******  other: {'city': '北京'}
account: 15639067891@163.com  pwd: ***  other: {'city': '广州', 'sex': 'male'}
account: 15639067892@163.com  pwd: *****  other: {'city': '上海', 'name': 'Wang DaChui'}

关键字参数有什么用?它可以扩展函数的功能。比如,在enrollment()函数里,我们保证能接收到account和pwd这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了账号和密码是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

# 关键字参数
def enrollment(account, pwd, **kws):
    print('account:', account, ' pwd:', pwd, ' other:', kws)
# 一个字段
other = {'city' : '深圳', 'job' : '程序员'}
enrollment("15639067890@163.com", r'******', city=other['city'], job=other['job'])

运行结果:

account: 15639067890@163.com  pwd: ******  other: {'city': '深圳', 'job': '程序员'}

当然,上面复杂的调用可以用简化的写法:

# 关键字参数
def enrollment(account, pwd, **kws):
    print('account:', account, ' pwd:', pwd, ' other:', kws)

other = {'city' : '深圳', 'job' : '程序员'}
# 常规调用形式:
enrollment("15639067890@163.com", r'******', city=other['city'], job=other['job'])

# 简化调用形式
enrollment("15639067893@163.com", r'******', **other)

运行结果:

account: 15639067890@163.com  pwd: ******  other: {'job': '程序员', 'city': '深圳'}
account: 15639067893@163.com  pwd: ******  other: {'job': '程序员', 'city': '深圳'}

说明:
**other表示把other这个dict的所有key-value用关键字参数传入到函数的**kws参数,kws将获得一个dict,注意kws获得的dict是other的一份拷贝,对kws的改动不会影响到函数外的other。

命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。但是调用者仍可以传入不受限制的关键字参数。

# 关键字参数
def enrollment(account, pwd, **kws):
    if 'sex' in kws:
        # 有sex
        pass
    
    if 'city' in kws:
        # 有city
        pass
    print('account:', account, ' pwd:', pwd, ' other:', kws)

但是调用者仍可以传入不受限制的关键字参数:

enrollment("15639067891@163.com", r'***', city="广州", sex='male')
enrollment("15639067892@163.com", r'*****', city="上海", name='Wang DaChui')

运行结果:

account: 15639067891@163.com  pwd: ***  other: {'city': '广州', 'sex': 'male'}
account: 15639067892@163.com  pwd: *****  other: {'city': '上海', 'name': 'Wang DaChui'}

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和sex作为关键字参数。这种方式定义的函数如下。

# 命名关键字参数
def enrollment(account, pwd, *, city, sex):
    print('account:', account, ' pwd:', pwd, ' city:', city, 'sex:', sex)

# 调用函数
enrollment("15639067891@163.com", r'***', city="广州", sex='male')

运行结果:

account: 15639067891@163.com  pwd: ***  city: 广州 sex: male

和关键字参数kw不同,命名关键字参数需要一个特殊分隔符后面的参数会被视为命名关键字参数。在调用函数时,关键词参数不能多不能少,要严格按照定义时的参数名。

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。由于调用时缺少参数名city和job,Python解释器把这4个参数均视为位置参数。


# 命名关键字参数
def enrollment(account, pwd, *, city, sex):
    print('account:', account, ' pwd:', pwd, ' city:', city, 'sex:', sex)

# 少传入命名关键词参数
enrollment("15639067891@163.com", r'***', "广州")

运行结果:

Traceback (most recent call last):
  File "F:/python_projects/09argument.py", line 103, in <module>
    enrollment("15639067891@163.com", r'***', "广州")
TypeError: enrollment() takes 2 positional arguments but 3 were given

意思是:enrollment()需要 2 个位置参数,但是有3个被传入了。


此时,如果少传入了命名关键词参数,则报错:TypeError: enrollment() missing 1 required keyword-only argument:xxx。例如:

# 命名关键字参数
def enrollment(account, pwd, *, city, sex):
    print('account:', account, ' pwd:', pwd, ' city:', city, 'sex:', sex)

# 少传入命名关键词参数
enrollment("15639067891@163.com", r'***', city="广州")

运行结果:

Traceback (most recent call last):
File "F:/python_projects/09argument.py", line 102, in <module>
    enrollment("15639067891@163.com", r'***', city="广州")
TypeError: enrollment() missing 1 required keyword-only argument: 'sex'

意思是:缺少了必须的关键词参数:sex


如果多传入了命名关键词参数,则报错:TypeError: enrollment() got an unexpected keyword argument :xxx。例如:

# 命名关键字参数
def enrollment(account, pwd, *, city, sex):
    print('account:', account, ' pwd:', pwd, ' city:', city, 'sex:', sex)

# 多传入关键词参数
enrollment("15639067892@163.com", r'*****', city="上海", sex='male', name='Wang DaChui')

运行结果:

Traceback (most recent call last):
  File "F:/python_projects/09argument.py", line 105, in <module>
    enrollment("15639067892@163.com", r'*****', city="上海", sex='male', name='Wang DaChui')
TypeError: enrollment() got an unexpected keyword argument 'name'

意思是:调用enrollment()时,不期望有的(多余的)关键词参数:name


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

# 命名关键字参数
def enrollment(account, pwd, *other, city, sex):
    print('account:', account, ' pwd:', pwd,  'other :', other, 'city:', city, 'sex:', sex)

other = [2, 4, 5]
# 调用形式
enrollment("15639067893@163.com", r'******', *other, city='北京', sex='male')

运行结果:

account: 15639067893@163.com  pwd: ****** other : (2, 4, 5) city: 北京 sex: male

这里的*other,已经是一个可变参数了,所以后面跟着的命名关键字参数就不再需要一个特殊分隔符了。使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数:


命名关键字参数可以有缺省值,从而简化调用:

# 命名关键字参数
def enrollment(account, pwd, *other, city='北京', sex):
    print('account:', account, ' pwd:', pwd,  'other :', other, 'city:', city, 'sex:', sex)

other = [2, 4, 5]
# 调用形式
enrollment("15639067893@163.com", r'******', *other, city='北京', sex='male')

# 使用默认关键词参数的值
enrollment("15639067894@163.com", r'****', *other)

运行结果:

account: 15639067893@163.com  pwd: ****** other : (2, 4, 5) city: 北京 sex: male
account: 15639067894@163.com  pwd: **** other : (2, 4, 5) city: 北京 sex: male

如果,命名关键词没有给初始值,则调用时必须传入。否则,会报错缺少必须的关键词参数。

# 命名关键字参数
def enrollment(account, pwd, *other, city='北京', sex):
    print('account:', account, ' pwd:', pwd,  'other :', other, 'city:', city, 'sex:', sex)

other = [2, 4, 5]
# 调用形式
enrollment("15639067893@163.com", r'******', *other, city='北京', sex='male')

# 使用默认关键词参数的值
enrollment("15639067894@163.com", r'****', *other)

运行结果:

Traceback (most recent call last):
account: 15639067893@163.com  pwd: ****** other : (2, 4, 5) city: 北京 sex: male
  File "F:/python_projects/09argument.py", line 125, in <module>
    enrollment("15639067894@163.com", r'****', *other)
TypeError: enrollment() missing 1 required keyword-only argument: 'sex'
参数组合

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

小结

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。
1.默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误!
2.要注意定义可变参数和关键字参数的语法:
*args是可变参数,args接收的是一个tuple
**kw是关键字参数,kw接收的是一个dict
3.以及调用函数时如何传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2, 3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3))
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})
使用*args**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
4.命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
5.定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • 第5章 函数和函数式编程 5.1 引言函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数...
    VIVAFT阅读 943评论 0 5
  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,916评论 17 410
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 看是谁的事,谁更相关,听谁的 分开走也行 不激化矛盾
    高登安立奎阅读 261评论 0 0
  • 对不起,是我让你们失望了。
    Stars星星阅读 219评论 0 0