python实用派
第一章 python是什么?初始化
第二章 python基础内容(1)
第三章 python基础内容(2)
第四章 python进阶之numpy库
第五章 python进阶之pandas库
第六章 python进阶之求解器应用–gurobi求解器
第七章 python进阶之求解器应用–cplex求解器
第八章 python进阶之数据可视化篇
第九章 python进阶之爬虫篇
文章目录
五. 函数
函数是python中最重要的也是最主要的代码组织和复用手段
如果你要重复使⽤相同或⾮常类似的代码,就需要写⼀个函数。通过给函数起⼀个名字,还可以提⾼代码的可读性。
python通过保留字符 def来定义一个函数
,形式如下:
def 函数名(参数):
函数功能 # 注意冒号和缩进
通过参数来向函数传递信息,参数可以是数字,变量,列表,元组,字典 等等。
现在来写一个函数,并用return关键字返回值 (return关键字,其用法是在运行return时返回一个对象)
def my_fuction(x,y,z=1):
if z > 1:
return z * (x + y)
else:
return z / (x + y)
x, y = 1, 2
value1 = my_fuction(x,y)
value2 = my_fuction(x,y,z=2)
print('value1是',value1)
print('value2是',value2)
#输出结果:
value1是 0.3333333333333333
value2是 6
1. 实参和形参
形参是指在函数中用到的参数的名称,
实参是指参数所对应的实际的对象。
例如
def my_fuction(x,y,z=1):
if z > 1:
return z * (x + y)
else:
return z / (x + y)
x, y = 1, 2
value1 = my_fuction(x,y)
在函数my_fuction()中,x,y,z为形参,而x, y, z = 1, 2, 1 对应的对象为实参(即这几个数字)
2. 参数类型
1)必备参数
必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
def my_fuction(x,y):
if x > 1:
return x + y
else:
return x - y
value1 = my_fuction(1,2)
value2 = my_fuction(2,1)
print('value1是',value1)
print('value2是',value2)
#输出结果:
value1是 -1
value2是 3
2)关键字参数
如果想要避免传递参数的顺序问题,需要使用关键字参数传递,即指定参数的值。如
def my_fuction(x,y):
if x > 1:
return x + y
else:
return x - y
value1 = my_fuction(y=1,x=2)
value2 = my_fuction(y=2,x=1)
print('value1是',value1)
print('value2是',value2)
#输出结果:
value1是 3
value2是 -1
3)默认参数
在定义函数时,可以给参数设定默认值,如
def my_fuction(x,y,z=1):
if z > 1:
return z * (x + y)
else:
return z / (x + y)
形参z便给定了一个默认的值为1,当调用函数时,没有传递参数z的值,则z会使用默认值;当传递了z的值时,z会更新为传递值,如
def my_fuction(x,y,z=1):
if z > 1:
return z * (x + y)
else:
return z / (x + y)
x, y = 1, 2
value1 = my_fuction(x,y)
value2 = my_fuction(x,y,z=2)
print('value1是',value1)
print('value2是',value2)
#输出结果:
value1是 0.3333333333333333
value2是 6
4)不定长参数
当一个函数,可能要接收很多实参时,可以用一个带星号的形参来接受他们,而用带两个星号的形参可以创建一个空字典,接收键值对实参。
如
def sign_in(*names):
print(names,"sign in.")
sign_in('Chang', 'Gao', 'Zhou')
#输出结果:('Chang', 'Gao', 'Zhou') sign in.
def build_profile(first, last, **user_info):
profile = {}
profile['first_name'] = first
profile['last_name'] = last
for key, value in user_info.items():
profile[key] = value
return profile
user_profile = build_profile('Chang', 'Q', location='hefei', Gender='Male')
print(user_profile)
#输出结果:{'first_name': 'Chang', 'last_name': 'Q', 'location': 'hefei', 'Gender': 'Male'}
3. 全局变量与局部变量
变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
很简单就可以理解,如:
def my_fuction(x,y):
z=1 # 此处z在函数内部定义
if z > 1:
return z * (x + y)
else:
return z / (x + y)
x, y = 1, 2 # 此处x,y在函数外部定义
value1 = my_fuction(x,y)
print(value1)
print(x-y)
print(z)
#输出结果:
0.3333333333333333
-1
NameError: name 'z' is not defined
4. 匿名函数
使用 lambda 来创建匿名函数。
lambda只是一个表达式,函数体比def简单很多,但是lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去
比如说
a = lambda x, y : x+y
print(a(1,2))
#输出结果:3
关于字符串
5. 将函数存储在模块中
python之所以好用,很大的一部分原因是有丰富的第三方库,大量的已经写好的模块,可以直接导入进行使用,而不必再从头写起。(有大量的轮子可以搬过来用)
很简单的例子,比如单纯形法,很多求解器都可以实现,而且很多求解器都集成了大量的先进算法,运算效率更高,我们只需要掌握需要输入什么内容,以及能输出哪些内容,就可以很方便的进行调用求解。
1) 导入整个模块
首先创建一个.py文件,例如文件名为:functions.py,我们在这个文件中创建一个或几个函数,如:
def my_function_1(x, y):
return x+y
def my_function_2(x, y):
return x-y
接下来我们在另一个.py文件中导入模块,实现跨文件调用已有函数。如:
import functions
a = functions.my_function_1(3,2)
b = functions.my_function_2(3,2)
print(a)
print(b)
#输出结果:
5
1
2) 导入特定函数
有时候我们只想调用某一模块中的一个或几个函数,而不是所有函数,可以通过如下方式导入:
from functions import my_function_1
a = my_function_1(3,2)
print(a)
#输出结果:
5
或者导入几个函数
from functions import my_function_1, my_function_2
a = my_function_1(3,2)
b = functions.my_function_2(3,2)
print(a)
print(b)
#输出结果:
5
1
3) 使用as指定别名
当我们调用的函数名称过长时,可能会影响写代码的效率,我们可以通过as给该函数赋予一个简短的别名。如:
from functions import my_function_1 as f1
a = f1(3,2)
print(a)
#输出结果:
5
此外,还可以通过as给模块指定别名,如:
import functions as f
a = f.my_function_1(3,2)
print(a)
#输出结果:
5
4) 导入模块中所有函数
导入模块进行函数调用时,每次需要声明模块名再通过句点指明其中的函数名,过于繁琐,此时可以导入模块中的所有函数来避免这种情况,如
from functions import *
a = my_function_1(3,2)
b = functions.my_function_2(3,2)
print(a)
print(b)
#输出结果:
5
1
但是,需要注意的是,这种导入方法,会覆盖已有的相同名称的函数,在进行大型的模块编写时,应避免这种导入方式,可能会产生意想不到的结果。
一般只用在 导入自己写的函数中,即你有把握不会出现同名函数的情况下。
5) 使用已有的模块资源
我们可以通过本小节所述的导入模块的方法,导入别人写好的模块,大大的提升了效率,并降低编写代码的难度。 当然你需要先下载好模块文件(这个文件可能包含很多模块,一般称之为包)
模块文件的下载官方网站为:pypi官网 。较为麻烦,一般不用,可以自行百度
我们可以通过pip方式 方便快捷的进行包的安装。
打开cmd命令运行窗口,如安装pandas包
pip install pandas
也可以通过pycharm进行包管理,一键下载安装,非常简单快捷。可参考pycharm管理第三方包。
六. 类
类是用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
比如说,编写一个狗类,这个狗类包含了一些属性和方法,假如包括,狗的名字,狗的年龄,狗的品种。那么每一个实例狗,他都有上述提到的三条属性,你可以调用它。
类可以让你更方便的编写大型的项目。
1. 创建类
class Dog(): # 注意类名称的首字母大写,括号为空,并且有冒号,类内的内容进行缩进,表示下面的内容属于这个类
def __init__(self, name, age, breed):
self.name = name
self.age = age
self.breed = breed
def sit(self):
print(self.name, "坐下了!")
def roll(self):
print(self.name, "在滚动!")
在这个狗类中,我们设置了三条属性和两个方法,即狗的名字,年龄和品种三条属性,两个方法为坐和滚。
在狗类中,可以看到第一种方法是__init__()
方法,它是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。
- 来重点分析一下
__init__()
方法
(1)方法名称前后采用双下划线,这是一种约定,避免与普通方法冲突。
(2)其次,在这个方法中,第一个参数为self,这是一种表示习惯,用来自动传递实参self,指向实例本身,让实例能够访问类内的属性和方法。当创建实例时,self会自动传递,我们只需要给出后面三个参数即可。
(3)在定义类的属性时,采用self.XX = XX的这种形式时,即我们定义了这个类的某个属性值,可供类内的任何方法使用,“一次定义,全类畅用”。
(4)在定义类内其他方法时,第一个参数也必须是形参self。
比如我们在创建类实例时,需要传递name,age,breed三个实参,这时代码self.name = name
则 将类的属性name 设定为了传入的实参name,我们可以在这个类内的任何方法中使用,比如方法sit()
中。
当你创建了一个狗的实例后,便可以访问狗类中定义了的三条属性以及调用两个方法,如下
class Dog(): # 注意类名称的首字母大写,括号为空,并且有冒号,类内的内容进行缩进,表示下面的内容属于这个类
def __init__(self, name, age, breed):
self.name = name
self.age = age
self.breed = breed
def sit(self):
print(self.name, "坐下了!")
def roll(self):
print(self.name, "在滚动!")
dog1 = Dog('wang', 5, 'golden retriever') # 创建一个狗实例
dog2 = Dog('wen', 4, 'golden retriever') # 创建一个狗实例
print("狗1的名字是", dog1.name)
print("狗2的名字是", dog2.name)
print("狗1的品种是", dog1.breed)
dog1.sit()
dog2.roll()
#输出结果:
狗1的名字是 wang
狗2的名字是 wen
狗1的品种是 golden retriever
wang 坐下了!
wen 在滚动!
实例的属性值可以设定默认值,以及支持修改。如
class Dog(): # 注意类名称的首字母大写,括号为空,并且有冒号,类内的内容进行缩进,表示下面的内容属于这个类
def __init__(self, name, age):
self.name = name
self.age = age
self.breed = 'golden retriever'
def sit(self):
print(self.name, "坐下了!")
def roll(self):
print(self.name, "在滚动!")
dog1 = Dog('wang', 5) # 创建一个狗实例
print("狗1的名字是", dog1.name)
print("狗1的品种是", dog1.breed)
dog1.sit()
#输出结果:
狗1的名字是 wang
狗1的品种是 golden retriever # 默认值
wang 坐下了!
# 修改属性
dog1.name = 'haha'
dog1.sit()
#输出结果:
haha 坐下了!
2. 继承
如果需要编写的类是一个现有的类的特殊版本,那么可以用继承来自动获取原有类的所有属性和方法。省去了重写的麻烦。
通过继承创建的新类称为子类,被继承的类称为父类。
class Dog(): # 注意类名称的首字母大写,括号为空,并且有冒号,类内的内容进行缩进,表示下面的内容属于这个类
def __init__(self, name, age):
self.name = name
self.age = age
self.breed = 'golden retriever'
def sit(self):
print(self.name, "坐下了!")
def roll(self):
print(self.name, "在滚动!")
class Small_dog(Dog):
def __init__(self, name, age):
super().__init__(name, age)
上面的例子中,创建子类需要在子类名称后面的括号中声明父类名称。在子类的__init__()
方法中,可以通过super().__init__(xx, xx)
的方式来让子类继承父类的所有属性值。
另外我们可以继续编写属于子类特有的属性,方法。还可以对父类的方法进行重新定义。如
class Dog(): # 注意类名称的首字母大写,括号为空,并且有冒号,类内的内容进行缩进,表示下面的内容属于这个类
def __init__(self, name, age):
self.name = name
self.age = age
self.breed = 'golden retriever'
def sit(self):
print(self.name, "坐下了!")
def roll(self):
print(self.name, "在滚动!")
class Small_dog(Dog):
def __init__(self, name, age):
super().__init__(name, age) # 继承父类属性
self.lenth = '30cm' # 编写属于子类的特殊内容
def sit(self): # 重写父类方法
print(self.name,"我是子类,我没有坐下!")
dog1 = Small_dog('wang', 5)
print("我的身长为", dog1.lenth)
dog1.sit()
dog1.roll()
#输出结果
我的身长为 30cm
wang 我是子类,我没有坐下!
wang 在滚动!
3. 导入类
与之前导入函数的方法是相似的。
例如我们将之前写好的Dog类和Small_dog类存储在文件’my_dog.py’中。
则:
import my_dog
dog1 = my_dog.Dog('wang', 5)
dog2 = my_dog.Small_dog('hehe', 3)
print("Dog2的身长为", dog2.lenth)
dog1.roll()
dog2.sit()
# 输出结果
Dog2的身长为 30cm
wang 在滚动!
hehe 我是子类,我没有坐下!
或者其他的导入方式
from my_dog import Dog, Small_dog # 从my_dog中导入指定的类
# from my_dog import * # 导入my_dog中所有的类
dog1 = Dog('wang', 5)
dog2 = Small_dog('hehe', 3)
print("Dog2的身长为", dog2.lenth)
dog1.roll()
dog2.sit()
# 输出结果
Dog2的身长为 30cm
wang 在滚动!
hehe 我是子类,我没有坐下!
七. 文件读写和异常
1. 文件读取
假设当前在E\
目录下创建一个dog.txt文件
with open('E:/dog.txt') as f:
contents = f.read()
print(contents)
# 输出结果:
1357810
wangwang
保留字 with:一般open() 文件后 需要close()文件,with省去了close()的操作。
open包含的参数包括
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
open() 方法打开了文件,as 将文件名记为f,通过read()方法,读取f中的内容。
- 绝对路径与相对路径
文件的位置可以分为绝对文件路径和相对路径,
绝对路径即完整的文件路径位置,或者可以说是准确位置,如C:\Users\dog.txt
相对路径即相对于当前文件的位置,给出所要操作的文件的位置,假如当前代码文件在E:\
,由于dog.txt
在当前文件位置下,那么相对路径为dog.txt
。
此外注意使用反斜杠\
而不是斜杠/
2. 文件写入
with open('E:/dog.txt', 'w') as f:
f.write('wangwang')
通过write()方法即可将内容写入相应文件
注意:
(1) w表示写入模式,写入时文件中原有的内容会被覆盖掉
(2) r表示读取模式,这是默认模式。
(3) a表示附加模式,写入时原有内容不会被覆盖
(4) r+表示读写模式,可以读取也可以写入,写入时会覆盖原有内容
(5) a+表示附加读写模式,可以读取也可以写入,写入时不会覆盖原有内容
这里的模式还有很多种,如有需要可自行百度查看。
3. 处理异常
当我们编写代码进行运行时,经常会遇到报错的情况,我们可以根据python的traceback来判断错误原因,以便于修改。
此外,我们可以使用try-except-else
代码块来处理可能引发的异常.
如:
try:
a=5/0
except:
print('you can not divide by zero!')
else:
print(a)
# 输出结果:
you can not divide by zero!
try:
a=5/1
except:
print('you can not divide by zero!')
else:
print(a)
# 输出结果:
5.0
try-except-else
代码块,很直观的可以理解为我们将不确定是否报错的代码放在try代码块中,
如果运行出现问题,就执行except块的内容,
如果运行没有问题,则执行完try块的内容 并继续执行else中内容。
我们还可以打印错误信息,但是不是python的traceback报错
try:
a=5/0
except Exception as e:
print(e)
# 输出结果:
division by zero
try:
a=5 + 's'
except Exception as e:
print(e)
# 输出结果:
unsupported operand type(s) for +: 'int' and 'str'