函数
Martin Fowler先生曾经说过:“代码有很多种坏味道,重复是最坏的一种!”。
定义函数
通常情况下函数是下面的这种结构,其中def
是关键字,函数名可以自己定义,与变量的命名一样。括号里面放传过来来的参数(自变量),return
后面接函数的返回值。
注意: 任何一个函数都有返回值,如果函数没有return,返回值就是None
,返回值可以是任意的数据类型
def 函数名(参数):
return
函数的参数
默认参数
def 函数名(a,b=3):
return
这里的b=3就是默认参数,如果不传b过来,b默认就是3,如果重新传b,b的值就被覆盖掉
注意:带默认值的参数必须放在不带默认值的参数之后,否则将产生SyntaxError
错误,错误消息是:non-default argument follows default argument
,翻译成中文的意思是“没有默认值的参数放在了带默认值的参数后面
可变参数
可变参数指的是在调用函数时,可以向函数传入0个或任意多个参数。这里使用*
号。一个*
号表示传入的是一个元组,两个**
号表示传入的是一个字典
def 函数名(*args,**kwargs):
return
关键字参数
在没有特殊处理的情况下,函数的参数都是位置参数,也就意味着传入参数的时候对号入座即可。也可以通过参数名=参数值
的方式传入函数所需的参数,因为指定了参数名,传入参数的顺序可以进行调整
调用函数时,如果希望函数的调用者必须以参数名=参数值
的方式传参,可以用命名关键字参数取代位置参数。所谓命名关键字参数,是在函数的参数列表中,写在*
之后的参数
def 函数名(*,a,b,c)
return
# 函数的调用
# 传参时必须使用“参数名=参数值”的方式,位置不重要
函数名(a = 1,b=2,c=3)
注意:上面的函数,参数列表中的*
是一个分隔符,*
前面的参数都是位置参数,而*
后面的参数就是命名关键字参数。
模块
Python中每个文件就代表了一个模块(module),我们在不同的模块中可以有同名的函数,在使用函数的时候我们通过import
关键字导入指定的模块再使用完全限定名的调用方式就可以区分到底要使用的是哪个模块中的函数
调用的两种方式
import 模块名
# 调用函数
模块名.函数名()
from 模块名 import 函数名 as 重命名 # as是对函数名称重命名
# 调用函数
函数名()
python标准库的一部分内置函数,可直接使用
函数 | 说明 |
---|---|
abs | 返回一个数的绝对值,例如:abs(-1.3) 会返回1.3 。 |
bin | 把一个整数转换成以'0b' 开头的二进制字符串,例如:bin(123) 会返回'0b1111011' 。 |
chr | 将Unicode编码转换成对应的字符,例如:chr(8364) 会返回'€' 。 |
hex | 将一个整数转换成以'0x' 开头的十六进制字符串,例如:hex(123) 会返回'0x7b' 。 |
input | 从输入中读取一行,返回读到的字符串。 |
len | 获取字符串、列表等的长度。 |
max | 返回多个参数或一个可迭代对象(后面会讲)中的最大值,例如:max(12, 95, 37) 会返回95 。 |
min | 返回多个参数或一个可迭代对象(后面会讲)中的最小值,例如:min(12, 95, 37) 会返回12 。 |
oct | 把一个整数转换成以'0o' 开头的八进制字符串,例如:oct(123) 会返回'0o173' 。 |
open | 打开一个文件并返回文件对象(后面会讲)。 |
ord | 将字符转换成对应的Unicode编码,例如:ord('€') 会返回8364 。 |
pow | 求幂运算,例如:pow(2, 3) 会返回8 ;pow(2, 0.5) 会返回1.4142135623730951 。 |
print | 打印输出。 |
range | 构造一个范围序列,例如:range(100) 会产生0 到99 的整数序列。 |
round | 按照指定的精度对数值进行四舍五入,例如:round(1.23456, 4) 会返回1.2346 。 |
sum | 对一个序列中的项从左到右进行求和运算,例如:sum(range(1, 101)) 会返回5050 。 |
type | 返回对象的类型,例如:type(10) 会返回int ;而type('hello') 会返回str 。 |
Lambda函数
Python中的Lambda函数是没有的名字函数,所以很多人也把它叫做匿名函数,匿名函数只能有一行代码,代码中的表达式产生的运算结果就是这个匿名函数的返回值
numbers1 = [35, 12, 8, 99, 60, 52]
numbers2 = list(filter(lambda x: x % 2 == 0, numbers1))
# 结果
[12,8,60,52]
面向对象编程
类与对象
类:众多具有相同属性的对象构成类
对象:类的实例化,具体的一个事物
定义类
在Python中,可以使用class
关键字加上类名来定义类。方法的第一个参数通常都是self
,它代表了接收这个消息的对象本身。
__init__
的方法:在我们调用Student
类的构造器创建对象时,首先会在内存中获得保存学生对象所需的内存空间,然后通过自动执行__init__
方法,完成对内存的初始化操作,也就是把数据放到内存空间中。所以我们可以通过给Student
类添加__init__
方法的方式为学生对象指定属性,同时完成对属性赋初始值的操作,正因如此,__init__
方法通常也被称为初始化方法。
class Student: # 学生类
def __init__(self, name, age): # 属性
"""初始化方法"""
self.name = name
self.age = age
def study(self, course_name): # 行为,学习
print(f'学生正在学习{course_name}.')
def play(self): # 行为:玩游戏
print(f'学生正在玩游戏.')
魔术方法
# 打印对象是,不会出现对象的地址,会出现对象的属性
class Student:
"""学生"""
def __init__(self, name, age):
"""初始化方法"""
self.name = name
self.age = age
def __repr__(self):
return f'{self.name}: {self.age}'
stu = Student('王大锤',40)
print(stu1) # 王大锤: 40 ,如果没有__repr__方法,这里打印的就是对象的地址
静态方法与类方法
传入三条边,判断是否能构成三角形。在创建三角形对象时,传入的三条边长未必能构造出三角形,为此我们可以先写一个方法来验证给定的三条边长是否可以构成三角形,这种方法很显然就不是对象方法,因为在调用这个方法时三角形对象还没有创建出来。我们可以把这类方法设计为静态方法或类方法,也就是说这类方法不是发送给三角形对象的消息,而是发送给三角形类的消息,代码如下所示。
class Triangle(object):
"""三角形类"""
def __init__(self, a, b, c):
"""初始化方法"""
self.a = a
self.b = b
self.c = c
@staticmethod
def is_valid(a, b, c):
"""判断三条边长能否构成三角形(静态方法)"""
return a + b > c and b + c > a and a + c > b
# @classmethod
# def is_valid(cls, a, b, c):
# """判断三条边长能否构成三角形(类方法)"""
# return a + b > c and b + c > a and a + c > b
def perimeter(self):
"""计算周长"""
return self.a + self.b + self.c
def area(self):
"""计算面积"""
p = self.perimeter() / 2
return (p * (p - self.a) * (p - self.b) * (p - self.c)) ** 0.5
上面的代码使用staticmethod
装饰器声明了is_valid
方法是Triangle
类的静态方法,如果要声明类方法,可以使用classmethod
装饰器。可以直接使用类名.方法名
的方式来调用静态方法和类方法,二者的区别在于,类方法的第一个参数是类对象本身,而静态方法则没有这个参数。简单的总结一下,对象方法、类方法、静态方法都可以通过类名.方法名
的方式来调用,区别在于方法的第一个参数到底是普通对象还是类对象,还是没有接受消息的对象。静态方法通常也可以直接写成一个独立的函数,因为它并没有跟特定的对象绑定。
总结:本周学习如何定义函数,调用函数,以及函数传参过程中可能遇到的问题,位置参数、关键字传参、如何传多个参数(元组)、如何传多个关键字参数(字典)。面向对象编程:类-对象-属性和方法。如何创建一个类,创建一个对象,以及归纳它的属性,和创建方法。以及继承,多态,子类继承父类,子类重写父类方法。逻辑还是能够理解,只是写少了,不够熟练