-
实例
def sale_car(price, color='red', brand='carmy', is_second_hand=True):
print('price', price,
'color', color,
'brand', brand,
'is_second_hand', is_second_hand,)
这里定义了一个函数, 该函数的参数表示车的属性, 不过在除了价格之外, 像颜色以及品牌和是否新车这些都设置了默认值的内容, 假如我们调用此函数并仅传入(1000)这个数值的话, 那么就相当于传入了(1000, 'red', 'carmy', True)这种情况的效果罢了, 另外需要注意的是当然也有可能在调用函数的过程里面传递特定的参数以实现对默认参数的修改操作。
我们调用函数的这个行为, 其复杂程度是可以通过给函数设置上一些默认的参数值来进行一个减轻的。
注意:默认值放在非默认值之后
- 进阶
当人们打算在运行脚本的阶段把一些程序代码放进来搞事情, 比如去跑一下单元测试的时候, 一个常见的办法就是在整个脚本文件的末尾把那部分测试程序的代码给加上, 可是这样一来, 要是这个脚本被当作是一个用来向外头提供实际功能的模块对待的话, 那么那段用于测试的代码就会跟着一起被执行到头上, 而这通常并不是我们内心所期望发生的情景, 针对这种不太理想的状态, 大家一般会采取把一个特定的东西丢到文件最后面的做法。
if __name__ == '__main__':
#code_here
如果我们在执行这个脚本的时候, 那个if判断语句的状态会是True, 那么它里面的那一份代码就会被执行下去。可是当我们从外面去调用这个脚本的时候, 条件上的if判断语句的结果会表现为False, 这样的话, 内部的那些代码就完全不会被执行了。
单元测试举例
①首先定义了一个测试函数:.py
def get_formmed_name(first, last):
"""该函数根据姓和名生成一个完整的姓名"""
full_name = first + ' ' + last
return full_name.title()
②然后编写了一个测试该函数的模块:names.py
from name_function import get_formmed_name
"""该文件用来测试姓名生成函数"""
print "Enter 'q' to quit any time."
while True:
first = raw_input("\nEnter first name:")
if first == 'q':
break
last = raw_input("Enter last name:")
if last == 'q':
break
formatted_name = get_formmed_name(first,last)
print "Formmated name:",formatted_name
通过进行测试这一行为之后, 可以知道那个在中间的函数是可以把它的功能给实现出来的。
③最后是单元测试和测试用例的编写。 .py
import unittest
from name_function import get_formmed_name
class NamesTestCase(unittest.TestCase):
"""测试name_function.py"""
def test_first_last_name(self):
"""能够正确处理像Janis Joplin这样的姓名吗?
"""
formatted_name = get_formmed_name('janis','joplin')
self.assertEqual(formatted_name,'Janis Joplin')
#注意这个地方,我在Python 2.7的版本中直接调用书上的主函数
#unittest.main()时程序无法通过,而改用以下调用方式即可
if __name__ == '__main__':
unittest
通过对前面提到的那些单元测试的部分进行分析。
先导入单元测试的类, 再导入要测试的那个函数, 在本例子当中呢, 就是那个模块里面的()函数, 然后创建一个类, 这个类是继承于那个东西的类的,在类的里面去定义好多方法, 用这些不同的方法来分别测试函数行为的不同方面, 需要特别注意的就是一个测试的用例它只能去测试一个方面, 测试的目的还有测试的内容都要变得非常明确才可以, 主要是去调用那些像断言一类的这种方法来判定一下程序的执行出来的结果和预期的结果是不是相符。

打个比方来说, 函数的所谓可变参数, 意思就是传进去的参数个数可以是变动的, 可以是一两个, 也可以是无数个。尽管把多个参数都打包到一个叫作 list 或 tuple 的容器里一起传进去, 也是可以做到的, 但这样的做法并不够好。
使用可变参数的方法就可以非常完美地处理好这个状况。需要引起重视的一点是, 可变参数在函数被定义的时候, 绝对不能放在那些指定参数和带有默认值的参数的前面。导致这样的原因是因为可变参数会把前面的参数全都给吞掉从而忽略这些参数。
def report(name, *grades):
total_grade = 0
for grade in grades:
total_grade += grade
print(name, 'total grade is ', total_grade)
这里定义了一个函数, 它接收一个名为name的参数作为输入条件, 随后出现的参数前面加上了*修饰符号, 这一操作是用来标识该参数属于可变参数类型的, 意思就是这个特定的变量内部会包含多个数据项并且是以可迭代对象形式存在的整体结构。
在该函数被执行的过程中, 需要提供具体的姓名信息以及对应科目的相关分数情况, 而最终的结果输出部分将会展示出个人的名字连同所有科目累计的总分数值组合在一起的内容情况。
所以, 可以按照这种方式来调用一下函数, 也就是输入 ('Mike', 8, 9) 这几个参数进去, 输出的结果会是 Mike total grade is 17, 另外, 也可以采用另一种方式来调用, 即输入 ('Mike', 8, 9, 10), 此时得到的结果是 Mike total grade is 27。
关键字参数这个玩意儿, 它允许你传进去0个或者任意多个的、带着自己名字参数的参数, 这些带名字的参数, 在咱们给函数写定义的时候根本就没有出现过, 可是, 这些个参数在函数干活的那个内部, 会自动地被打包进一个叫做字典的东西里面去, 这个字典用英文来说是dict。
def portrait(name, **kw):
print('name is', name)
for k,v in kw.items():
print(k, v)
定义了一个函数, 该函数接收一个名为 name 的参数以及使用两个星号进行修饰的关键字参数 kw。这个双星号的设置意在表明其所修饰的内容属于关键字参数的范畴。在通用的规范里面而言, 关键字参数应当被放置于函数参数列表的末端位置。
当执行调用操作并提供具体的参数内容, 这些参数具体为字符串 'Mike , 后续紧接着是 age 等于数字24、第三个参数键值缺失导致赋值语句存在语法错误提示 =' 而后面跟着字符串 'China, 第四个参数同样是 '=' 且后跟空字符串 '')时, 系统或者程序将输出相应的结果:
name is Mike
age 24
country China
education bachelor
借助可变参数, 再配合上关键字参数的这种方式, 任何的一个函数都存在能够以 (*args, kw) 这样的形式来得到表达的结果。
全局变量、局部变量
在 def 里面, 我们可以去定义一个局部变量, 这个叫做 a 的变量, 它只能在 fun 这个功能范围之内是有效的, 一旦离开了这个功能的范围之后, 那个 a 变量就不再是原来那个局部的 a 了。
def fun():
a = 10
print(a)
return a+100
print(fun())
"""
10
110
"""
下面的例子就验证了, 如果在fun函数的外部调用变量a的话, 会报错, 这表明位于外部的print(a)代码是不能找到那个属于局部变量的a的, 只有全局变量才能够在外部被调用, 比如APPLE这个变量。
APPLY = 100 # 全局变量
def fun():
a = 10 # 局部变量
return a+100
print(APPLE) # 100
print(a) # 报错, 不能拿到一个局部变量的值
首先在外部来定义一个全局变量, 这个变量的名字是a, 它的初始值是None, 然后在函数fun的内部去声明说这个a它是来自于外面的那个a, 具体的声明方式呢就是直接写个a。
APPLY = 100 # 全局变量
a = None
def fun():
global a # 使用之前在全局里定义的 a
a = 20 # 现在的 a 是全局变量了
return a+100
print(APPLE) # 100
print('a past:', a) # None
fun()
print('a now:', a) # 20