第八章 函数
函数的定义
def print_name(username):
print(username+"太强了,我是伞兵")
print_name("卢姥爷")
在函数定义中有多个形参时,调用函数时的输入实参顺序显然是和形参一一对应的,但是可以用以下方法规定哪一个实参传递给哪一个形参。如下所示:
def print_name(username,friend):
print(username+"是"+friend+"最好的朋友")
print_name("卢姥爷","凯亚")
print_name(friend="卢老爷",username="凯亚")
可见,可以使用关键字实参,规定实参传递给哪一个形参,而与输入顺序无关。
默认形参参数:
def print_name(username,friend="凯亚"):
print(username+"是"+friend+"最好的朋友")
print_name("卢姥爷")
这样是没啥问题的,此处应该是要求和C++保持一致,无默认值的形参要写在前面,有默认值的要写在后面。
def print_name(friend="凯亚",username):
print(username+"是"+friend+"最好的朋友")
print_name("卢姥爷")
这样的代码将会编译报错,报错信息如下,证明了我们的结论:
函数返回值的使用
def add_function(a, b):
return a + b
def name_produce(firstname, secondname):
return (firstname.title() + " " + secondname)
c = add_function(1, 2)
print(c)
wangxiaoming = name_produce("wang", "xiaoming")
print(wangxiaoming)
禁止函数修改列表:
def delete_List(list_p):
while list_p:
number=list_p.pop(0)
print(number)
list_p=["123","234","3124","314125"]
delete_List(list_p[:])#如果这里用的是list_p本身,则由于是引用传递。
#list_p本身的数据会被修改。
print(list_p)
传递任意数量的实参:
有些时候,传递的参数数量是不确定的,可以采用接下来的办法:
def delete_List(*list_p):
for number in list_p:
print(number,end=" ")
delete_List(1,2,3,4,5,6,7,8,9,10)
如果我们使用print(list_p)
可以看到 list_p是一个元组类型的数据
使用type函数也可以看出,类型是tuple
这里针对于元组tuple有一个问题,虽然大家都说元组元素不可以改变,但实际上我们可以查看下列代码:
def delete_List(*list_p):
print(type(list_p))
list_p[2].insert(0,12)
print(list_p)
delete_List(('lee', 21), ('gong', 20),[1,2,3])
实际上元组的元素发生了改变,我们可以认为是元组中元组地址和对应的数据的映射是不可改变的,但是对应的数据本身可以改变。
位置形参与任意数量实参相结合比较简单,只需要确保接受不确定数量的实参的形参在后面就可以了。
接下来我们看一下使用任意数量的关键字实参。
(意思就是,实参数量不确定,并且指定了关键字)
如下:
from functools import cmp_to_key
def key_judge(x,y):
if x[0]>y[0]:
return -1
else:
return 1
def produce_List(name, **list_p):
list_p["name"] = name
return list_p
newstudent = produce_List("Yin", school="HIT", graduate_year="2020")
print(sorted(newstudent.items(), key=cmp_to_key(key_judge)))
比较复杂,并且使用了key参数,规定了排序的比较参数和比较规则,也算学了点新东西吧。
函数模块:
我们在make.py文件中写入:
def make_pizza(size, *toppings):
print("这个pizza的尺寸是:"+str(size))
for topping in toppings:
print(topping)
然后我们在main.py中调用:
import make
make.make_pizza(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给")
注意必须使用 make.make_pizza()
的方式,否则无法识别。
如果想要直接调用make_pizza(),那么就需要加载时使用
from make import make_pizza
当然也可以使用别名,使用别名后,就不可以再使用原来的名称,别名用于防止引用的函数名和该模块内本身的函数名冲突,如下:
from make import make_pizza as oldeight
oldeight(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给")
from make import make_pizza as oldeight
import make
make.make_pizza(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给") #合法
oldeight(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给") # 合法
make_pizza(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给") #不合法 编译报错
同样可以指定模块名,例如:
import make as m
m.make_pizza(10,"臭豆腐","腐乳","鲱鱼罐头","奥里给") #合法
如果想要使用from xxx import xxx
的格式导入所有函数,可以使用这样的格式来实现。
from make import *
第九章 类
类的基本定义:
class Example:
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print(self.name)
def print_age(self):
print(self.age)
xiaoming=Example("xiaoming",18)
xiaoming.print_name()
xiaoming.print_age()
务必注意,类定义时,必须定义__init__()
函数,并且其必须有self形参,作为创建该类对象时必须执行的函数,同时如果自定义其他函数,定义时也应当填入self形参。
简单的类编写示范:
class Example:
def __init__(self, name, university,age=18):
self.__name = name
self.__age = age
self.__university=university
def print_name(self):
print(self.__name)
def print_age(self):
print(self.__age)
def print_university(self):
print(self.__university)
def updata_allinformation(self,newname,newage,newuniversity):
self.__name=newname
self.__updata_age(newage) #调用自己的方法还是要写上self
self.__updata_university(newuniversity) #调用自己的方法要用self
def __updata_age(self, newage):
self.__age = newage
self.age=newage
def __updata_university(self, new_university):
self.__university = new_university
student1=Example("Wang XiaoLang","HIT")
student1.print_age()
student1.print_university()
student1.print_name()
#print(student1.age) 由于我将age设置为了私有变量,从类外是不可以访问的
student1.updata_allinformation("Wang XiaoLang",22,"UESTC")
student1.print_age()
student1.print_university()
student1.print_name()
print(student1.age) #这里又可以了,因为我在updata里面额外添加了这样一个变量
继承:
python中似乎没有 JAVA 和 C++ 中复杂的 public,private,protected继承,(大概,这个继承非常的混乱(我个人认为),因为即使是私有属性依然可以强制访问)
下面是示例代码:
class Example():
def __init__(self, name, university,age=18):
self.__name = name
self.__age = age
self.__university=university
self.ceshi=120
def print_name(self):
print(self.__name)
def print_age(self):
print(self.__age)
def print_university(self):
print(self.__university)
def print_ceshi(self):
print(self.ceshi)
def updata_allinformation(self,newname,newage,newuniversity):
self.__name=newname
self.__updata_age(newage) #调用自己的方法还是要写上self
self.__updata_university(newuniversity) #调用自己的方法要用self
def __updata_age(self, newage):
self.__age = newage
self.age=newage
def __updata_university(self, new_university):
self.__university = new_university
class P_student(Example):
def __init__(self,name,university,age=18):
super().__init__(name, university, age)
self.number=1
print(self.ceshi)
self.ceshi=120 #这里表明父类和子类的同名ceshi是一个变量 即使将这行
#挪到初始化之前也是如此
super()._Example__updata_age(19) #强制调用私有函数
super().print_ceshi()
super().print_age()
self._Example__age=20 #强制调用私用变量
super().print_age()
student1=P_student("王刚","清华大学",12)
类继承的进一步测试:
class A:
def __init__(self):
self.A=1
self.B=2
def addP(self):
print(self.A+self.B)
def printAB(self):
print(self.A)
print(self.B)
class B(A):
def __init__(self):
super().__init__()
self.A=10
A.printAB(self) #此处输出表明 上述A和父类中A是同一个对象
b=B()
类中嵌套使用其他类的对象,这里就不展开了。
类函数的重载也很简单,重载之后的方法将覆盖父类方法,也就是只会执行重载的函数内代码,忽略原父类函数内容,
此处为测试:
class A:
def __init__(self):
self.A=1
self.B=2
def addP(self):
print(self.A+self.B)
def printAB(self):
print(self.A)
print(self.B)
class B(A):
def __init__(self):
super().__init__()
self.A=10
A.printAB(self) #此处输出表明 上述A和父类中A是同一个对象
def printAB(self):
print(self.A,end="???")
print(self.B,end=">>>")
b=B()
b.printAB() #简单的函数重载
但如果参数数量不一致呢,是否可以做到函数重载?
class A:
def __init__(self):
self.A=1
self.B=2
def addP(self):
print(self.A+self.B)
def printAB(self):
print(self.A)
print(self.B)
def printAB(self,C):
print(self.A)
print(self.B)
print(C)
b=A()
b.printAB(9)
b.printAB() #无法执行,后定义的printAB完全覆盖了前者,也就是python中不存在参数的差别产生的重载
然后是子函数重载父函数,但是参数个数不一样的实验:
class A:
def __init__(self):
self.A=1
self.B=2
def addP(self):
print(self.A+self.B)
def printAB(self):
print(self.A)
print(self.B)
class B(A):
def __init__(self):
super().__init__()
self.A=10
A.printAB(self) #此处输出表明 上述A和父类中A是同一个对象
def printAB(self,C):
print(self.A,end="???")
print(self.B,end=">>>")
print(C)
b=B()
b.printAB(9)
b.printAB() #同样无法执行,可见python重载只要函数名相同,
#直接覆盖父类函数。
#与参数个数完全无关
最后是 类的导入:
显然导入单个类和导入函数本质上没有区别。
直接测试嵌套导入:
第一种 Aclass.py文件:
class A:
def __init__(self):
self.a=1
def printA(self):
print(self.a)
Bclass.py文件
from Aclass import A
class B(A):
def __init__(self):
A.__init__(self)
self.b=2
A.printA(self)
main.py文件
from Bclass import B
b=B() #正确执行,可以看到的是 即使只是显示的导入了B,
#其依然可以使用B类中继承A类的函数
第二种测试:
将Aclass文件删除,Bclass文件修改为如下:
class A:
def __init__(self):
self.a=1
def printA(self):
print(self.a)
class B(A):
def __init__(self):
A.__init__(self)
self.b=2
A.printA(self)
在main文件不做出修改的情况下,依然可以正确执行,可见导入模块时,如果只导入子类,父类中的公有函数还是可以正常使用。
标准库代码:
随机数生成器
from random import randint
i=0
while i<99:
i+=1
print(randint(1,100)) #包括1和100
列表 元素随机选择一项:
from random import randint
from random import choice
i=0
example=[]
for i in range(0,10):
example.append(i)
while i<99:
i+=1
print(choice(example)) #包括1和100
第十章
文件与异常:
文件访问是一个任何语言里都很常见的东西了,从C++的read/write 到java的buffer(我都记不清是啥了),反正多多少少都要用到这些东西,我们来看看Python是如何实现这些内容的吧。
首先新建一个文件夹叫 Txt 然后放入文本文件 example.txt
写入文本:
如果大海能够
带走我的哀愁
就像带走每条河流
所有受过的伤
所有流过的泪
我的爱
请全部带走
main.py内容如下:
with open("Txt\example.txt",encoding="utf-8") as file1:
content=file1.read()
print(content)
如果不加上encoding="utf-8"
会出现乱码错误。(别人只是乱码,python直接报错无法读取)
读取文件的每一行数据:
with open("Txt\\example.txt",encoding="utf-8") as file1:
for line in file1:
print(line.strip())
将每一行数据 分别读取存成一个数组:
with open("Txt\\example.txt",encoding="utf-8") as file1:
lines=file1.readlines()
for line in lines:
print(line)
文件的写入:
file_name = "Txt\\example1.txt"
with open(file_name,'w',encoding="utf-8") as file1:
file1.write("你好,再见")
但是 write函数并不会在输入数据的末端自动添加 换行符,也就是如果连续使用write函数(不手动使用换行符),所有的数据将保留在同一行。
同样,如果不使用“w”方式打开文件,而是使用“a”类型时,使用write函数时,数据将添加到文件的末尾,而不会清除源文件的内容。
文件指针位置调整:
seek函数和tell函数,tell函数不需要额外参数,其返回当前文件指针位置,而seek函数需要两个参数,分别是offset和whence,offset表示偏移量,当offset不为0时,要求文件必须以二进制格式打开,否则报错,whence共有三种参数选择,为0时表示文件头,1表示当前位置,2表示文件尾。
异常处理:
try:
a=input("请输入被除数:\n")
b=input("请输入除数:\n")
answer=int(a)/int(b)
except ZeroDivisionError as ex1 :
print("sorry 出错了")
print(type(ex1),"::",ex1)
else:
print(answer)
python可以通过pass来 表示什么都不做,从而跳过一部分需要执行代码的区域。
使用json文件实现 信息的存储和读取:
import json
file_name="example2.txt"
stringx=[]
stringx=input().split()
with open(file_name,'w',encoding="utf-8") as file1:
json.dump(stringx,file1)
with open(file_name,'r',encoding="utf-8") as file2:
stringx2=json.load(file2)
print(stringx2)
实例使用
import json
file_name="example2.txt"
try:
with open(file_name) as file1:
numbers=json.load(file1)
except:
print("您好,新用户,请输入您的名字")
numbers=input()
with open(file_name,'w') as file2:
json.dump(numbers,file2)
else:
print("欢迎回来"+numbers+"!")