面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的思想就好比是精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线就是用来解决一个问题,代码牵一发而动全身。
应用场景:
一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象OOP(Object Oriented Programming),是一种程序设计思想。OOP把对象作为程序的基本单元,并且一个对象包含数据和操作数据的方法。
面向对象的程序设计的核心是对象,要理解对象为何物,必须把自己当成上帝(上帝式思维)。上帝眼里世间存在的万物皆为对象。
形象化场景设计:
面向对象的优点:面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使他人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
应用场景:需求经常变化的软件,如互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
类,英文名字Class,有“类别”,“分类”,“聚类”的意思。
必须牢记类是抽象的模板,用来描述具有相同属性和方法的对象的集合,比如Animal类。
而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
Python使用class关键字来定义类,其基本结构如下:
class 类名(): #一般类名首字母是大写
pass
下面是一个学生类:
class Student():
#类变量
classroom = '101'
address = 'beijing'
#构造方法:用来初始化实例变量的
def __init__(self, name, age):
#实例变量
self.name = name
self.age = age
#操作
def print_age(self):
print('%s: %s' % (self.name, self.age))
对象的创建
可以通过调用类的实例化方法(有的语言中也叫初始化方法或构造函数)来创建一个类的实例(对象)。
Python提供了一个def __init__(self):
的实例化机制。任何一个类中,名字为__init__
的方法就是类的实例化方法,具有__init__
方法的类在实例化的时候,会自动调用该方法,并传递对应的参数。
zhangsan = Student('zhangsan',20)
lisi = Student('lisi',30)
实例变量
定义在__init__
内部的变量是实例变量
实例变量指的是实例(对象)本身拥有的变量。Student类中__init__
方法里的name和age就是两个实例变量。
通过实例名加圆点的方式调用实例变量(可以通过对象名打点的方式去调用
/访问属于对象的成员)。
class Student():
#init称为构造方法
def __init__(self,i_name,i_age):
#只要定义在init方法内部的变量就是【实例/对象变量】
self.name = i_name #self.name就是定义的实例变量,name是init方法的参数值
self.age = i_age #self.age就是定义的实例变量,age就是init方法的参数值
s1 = Student('zhangsan',20) #调用Student类中的init这个构造方法
s2 = Student('lisi',25)
#根据对象的引用访问对象的实例变量
print(s1.name,s1.age) #访问s1对象的name和age这两个实例变量
print(s2.name,s2.age) #访问s2对象的name和age这两个实例变量
类变量
定义在类中,方法之外的变量,称作类变量
。类变量是所有实例公有的变量,每一个实例都可以访问类变量。
在Student类中,classroom和address两个变量就是类变量
。可以通过类名或者实例名加圆点的方式访问类变量
,比如:
class Student():
#定义在方法外部的变量:类变量
address = 'Beijing'
classroom = 167
#init称为构造方法
def __init__(self,i_name,i_age):
#只要定义在init方法内部的变量就是【实例/对象变量】
self.name = i_name #self.name就是定义的实例变量,name是init方法的参数值
self.age = i_age #self.age就是定义的实例变量,age就是init方法的参数值
s1 = Student('zhangsan',20) #调用Student类中的init这个构造方法
s2 = Student('lisi',25)
#根据对象的引用访问对象的实例变量
print(s1.name,s1.age) #访问s1对象的name和age这两个实例变量
print(s2.name,s2.age) #访问s2对象的name和age这两个实例变量
类变量的特性:
所有的类变量是可以通过类名或者对象名打点的方式访问/调用的。
print(s1.address,s1.classroom) #通过对象名可以访问类变量(不推荐)
print(Student.address,Student.classroom)#通过类名可以访问类变量(推荐)
类变量是可以被所有的对象公用的
print(s1.address,s1.classroom) #通过s1对象访问类变量
print(s2.address,s2.classroom) #通过s2对象访问类变量
Python的类中包含实例方法
、静态方法
和类方法
三种方法。区别在于传入的参数和调用方式不同。
在类的内部,使用def
关键字来定义一个方法。
类的实例方法由实例调用,至少包含一个self参数,且为第一个参数
。执行实例方法时,会自动将调用该方法的实例赋值给self。
self
代表的是类的实例,而非类本身。self
不是关键字,而是Python约定成俗的命名,你完全可以取别的名字,但不建议这么做。
例如,我们前面Student类中的print_age()就是实例方法:
class Student():
classroot = 167 #类变量
#构造方法
def __init__(self,name,age):
#实例变量
self.name = name
self.age = age
#实例方法:self不是python的关键字,实例方法的第一个参数也可以叫其他的名字,但是约定俗成叫做self。
#注意:实例方法只可以通过对象调用。
def study(self,book):#self是不需要手动给其传值
print('正在学习的书籍是:',book)
s = Student('zhangsan',20) #调用构造方法
#只给除了self其他的参数传值
s.study('高等数学')
实例方法中的第一个参数self到底是什么鬼?
class Student():
classroot = 167 #类变量
#构造方法
def __init__(self,name,age):
#实例变量
self.name = name
self.age = age
#实例方法
def study(self,book): #self就是study方法的调用者(对象)
#注意:在study方法内部调用play方法,如何实现?
self.play('足球') #实例方法必须使用对象调用
#self表示的就是调用该方法的对象的引用
print('正在学习的书籍是:',book)
#实例方法
def play(self,b):
print('正在玩的项目是:',b)
s = Student('zhangsan',20) #调用构造方法
s.study('高等数学')
对象之间的交互:设计人狗大战游戏,让他们真正的打一架。
class Person():
def __init__(self,name):
self.name = name
self.blood = 100 #人的初始血量
self.gjl = 10 #人的攻击力
def hitDog(self,dog): #dog参数表示的是狗对象
#人打狗后,需要让狗的血量减去人的攻击力
dog.blood -= self.gjl
#展示剩余血量
def showBlood(self):
print('%s,剩下的血量为:%d'%(self.name,self.blood))
class Dog():
def __init__(self,name):
self.name = name
self.blood = 50 #狗的初始血量
self.gjl = 5 #狗的攻击力
def hitPerson(self,p): #参数p就是狗攻击的人那个对象
p.blood -= self.gjl
#展示剩余血量
def showBlood(self):
print('%s,剩下的血量为:%d'%(self.name,self.blood))
p1 = Person('zhangsan')
p2 = Person('lisi')
d1 = Dog('doudou')
d2 = Dog('huanghuang')
p2.hitDog(d1) #lisi去攻击doudou这条狗
d1.showBlood() #查看被攻击后的狗还剩下多少血量
d2.hitPerson(p1) #huanghuang去攻击zhangsan
p1.showBlood() #查看被攻击后的人还剩下多少血量
静态方法由类调用
,无默认参数
。
将实例方法参数中的self去掉
,然后在方法定义上方加上@staticmethod
,就成为静态方法。
静态方法属于类,和实例无关
。建议只使用类名.静态方法
的调用方式。(虽然也可以使用实例名.静态方法的方式调用)
class Obj():
def __init__(self):
pass
#定义一个静态方法
@staticmethod
def staticFunc(name):#静态方法不需要有任何的必要参数
print('我是静态方法!,我有一个普通参数:',name)
Obj.staticFunc('bobo') #通过类名调用(推荐)
o = Obj()
o.staticFunc('bobo') #通过对象名调用(不推荐)
#静态方法既不属于类也不属于对象,仅仅是写在类内部的一个普通函数而已
类方法由类调用
,采用@classmethod装饰
,至少传入一个cls
(代指类本身,类似self)参数。
执行类方法时,自动将调用该方法的类赋值给cls。建议只使用类名.类方法的调用方式。(虽然也可以使用实例名.类方法的方式调用)
class Obj():
f = 'classVar' #类变量
def __init__(self):
pass
@classmethod
def classFunc(cls): #类方法必须要有一个cls的参数,且作为第一个参数
#cls也不是python的关键字,cls也可以写作其他的形式,比如:name,self
print('我是类方法!必要参数cls的值为:',cls)
print('类变量的值为:',cls.f) #类名访问类变量
#cls表示的是当前类
o = Obj()
o.classFunc() #通过对象名访问(不推荐)
Obj.classFunc() #通过类名访问(推荐)
测试题:
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
思路设计:一个学生会有一步手机,学生使用手机看电影。
class Student():
def __init__(self):
#将创建好的手机对象赋值给了phone这个实例变量
self.phone = Phone('霸王别姬')
class Phone():
def __init__(self,movie_name):
self.movie_name = movie_name
def playMovie(self):
print('手机正在播放的电影是:',self.movie_name)
s1 = Student()
s1.phone.playMovie()
面向对象有三大特性:封装、继承和多态
封装是指将数据与具体操作的实现代码放在某个对象内部,使这些代码的实现细节不被外界发现且不能通过任何形式修改对象内部实现,正是由于封装机制。
作用:
class Student:
classroom = '101'
address = 'beijing'
def __init__(self, name, age):
self.name = name
self.age = age
def print_age(self):
print('%s: %s' % (self.name, self.age))
# 以下是错误的用法
# 类将它内部的变量和方法封装起来,阻止外部的直接访问
print(classroom)
print(adress)
print_age()
继承来源于现实世界:
在OOP程序设计中,当我们定义一个新类的时候,新的类称为子类(Subclass),而被继承的类称为基类、父类或超类(Base class、Super class)。
继承最大的好处是子类获得了父类的全部变量和方法的同时,又可以根据需要进行修改、拓展。其语法结构如下:
class Foo(superA, superB,superC....):
pass
Python支持多父类的继承机制。
继承示例代码:子类可以继承到父类中所有的成员
class Father():
address = 'Beijing' #类变量
#构造方法
def __init__(self,fistName,hobby):
#两个实例变量
self.firstName = fistName
self.hobby = hobby
def get_xxx(self):
print('我是Father的实例方法')
@classmethod
def classFunc(cls):
print('我是Father类的类方法')
@staticmethod
def staticFunc():
print('我是Father类的静态方法')
#Son继承了Father这个类
#Son子类,Father父类
class Son(Father):
pass
#1.子类可以继承到父类的构造方法
s = Son('zhang','smoke') #调用子类的构造方法,子类是可以继承到父类的构造方法
#2.子类可以继承到父类的类变量
print(Son.address)
#3.子类可以继承到父类的实例变量
print(s.firstName,s.hobby)
#4.子类可以继承到父类的实例方法
s.get_xxx()
#5.子类可以继承到父类的类方法
Son.classFunc()
#6.子类可以继承到父类的静态方法
Son.staticFunc()
class Father():
address = 'Beijing' #类变量
#构造方法
def __init__(self,fistName,hobby):
#两个实例变量
self.firstName = fistName
self.hobby = hobby
def get_xxx(self):
print('我是Father的实例方法')
@classmethod
def classFunc(cls):
print('我是Father类的类方法')
@staticmethod
def staticFunc():
print('我是Father类的静态方法')
class Son(Father):
#子类自己派生出来的独有的方法
def sing(self):
print('子类的实例方法sing')
s = Son('zhang','smoke')
s.sing()
重写:子类继承到父类的方法,如果满足不了子类的需求,则子类可以重写从父类中继承到的方法。重写父类方法有两种方式:1完全重写,2部分重写
1.完全重写:完全重新将父类的方法进行的全新的定义/实现(毫无保留父类方法原始的功能)
class Father():
def __init__(self,firstName):
self.firstName = firstName
def hobby(self):
print('我喜欢读书,运动和跳舞!')
class Son(Father):
#完全重写
def hobby(self):
print('我喜欢吃鸡,王者!')
s = Son('zhang')
s.hobby()
2.部分重写:在父类方法功能实现的基础上新增了其他操作/功能
class Father():
def __init__(self,firstName):
self.firstName = firstName
def hobby(self):
print('我喜欢读书,运动和跳舞!')
class Son(Father1):
#部分重写
def hobby(self):
#调用一下父类的hobby方法
super().hobby() #调用父类的方法
print('我喜欢吃鸡,王者!')
s = Son('zhang')
s.hobby()
super()只可以作用在类的内部,然后表示的是父类对象的引用。
super函数
如果你想强制调用父类的成员该如何实现呢?使用super()函数!这是一个非常重要的函数,最常见的就是通过super调用父类的实例化方法__init__
!
语法:super(子类名, self).方法名()
,需要传入的是子类名和self,调用的是父类里的方法,按父类的方法需要传入参数。
class Father():
def __init__(self,firstName):
self.firstName = firstName
def hobby(self):
print('我喜欢读书,运动和跳舞!')
class Son(Father):
#子类需要有属于自己的实例变量
def __init__(self,firstName,classroom,score):
super().__init__(firstName)
#子类自己派生出的独有的实例变量
self.classroom = classroom
self.score = score
#部分重写
def hobby(self):
#调用一下父类的hobby方法
super().hobby() #调用父类的方法
print('我喜欢吃鸡,王者!')
s = Son('zhang',102,100)
s.hobby()
继承的作用:
在多继承中,继承关系的优先级
class Father1():
def hobby(self):
print('我是Father1,我喜欢唱歌!')
class Father2():
def hobby(self):
print('我是Father2,我喜欢跳舞!')
#注意:越靠前的父类越优先被继承
class Son(Father1,Father2):
#方法的重写
def hobby(self):
#思考:现在Son有两个父类,super()表示的是哪一个父类对象?
#输出结果显示super表示的是Father1对象
super().hobby()
print('我是Son,我喜欢吃鸡!')
s = Son()
s.hobby()
type和isinstance
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
isinstance() 方法的语法:
isinstance(object, classinfo)
参数:
object -- 实例对象。
classinfo -- 可以是类名、基本类型或者有它们组成的元组。
返回值:
如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。
class Father():
pass
class Son(Father):
pass
s = Son() #子类对象
print(isinstance(s,Son)) #True
#s这个对象是属于Son这个数据类型的。
#python的数据类型:内置类型(8中),自定义类型(类)
class Father():
pass
class Son(Father):
pass
s = Son() #子类对象
print(isinstance(s,Father)) #True
#注意:子类对象可以被视为是一种父类类型
class Father():
pass
class Son(Father):
pass
s = Son() #子类对象
print(type(s)) #
type:返回对象的类型
isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。
实例方法中的self参数是一个相对的值?
class Father():
def get_xxx(self):
print(self)
class Son(Father):
pass
f = Father()
f.get_xxx()
#输出:<__main__.Father object at 0x103536580>
#说明self表示的是父类类型的对象
class Father():
def get_xxx(self):
print(self)
class Son(Father):
pass
s = Son()
#是子类对象从父类中继承过来,self原本是写在父类的实例方法中的
s.get_xxx()
#输出结果:<__main__.Son object at 0x100e2a880>
类方法中的cls参数是一个相对的值?
class Father():
#类变量
class_var = 'father var'
@classmethod
def getVar(cls):
print(Father.class_var)
class Son(Father):
#类变量:和父类的类变量同名,子类同名的类变量就会覆盖从父类中继承过来的类变量
class_var = 'son var'
Son.getVar() #输出:father var
class Father():
#类变量
class_var = 'father var'
@classmethod
def getVar(cls):
print(cls.class_var)
class Son(Father):
#类变量:和父类的类变量同名,子类同名的类变量就会覆盖从父类中继承过来的类变量
class_var = 'son var'
Son.getVar() #输出:son var
思考:实例方法中的self参数的值是从哪来的?
Python 中的__new__和__init__的区别:
【同】
二者均是Python面向对象语言中的函数,__new__比较少用,__init__则用的比较多。
【异】
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象。
__init__是在对象创建好之后被调用的,init给对象的实例变量赋值,说明得事先存在实例变量,实例变量属于对象,实例变量存在则对象肯定也已经存在了。所以说对象存在了,则实例变量存在,实例变量存在则才可使用/调用init给实例变量赋值。
也就是: __new__先被调用,__init__后被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数,然后__init__给这个实例设置一些参数。
如下场景:
假设我有一个学生类和一个班级类,想要实现的功能为:
学生类继承自班级类,每实例化一个学生对象,班级人数都能增加;
最后,我想定义一些学生,获得班级中的总人数。
class ClassRoom():
num = 0 #记录学生对象的个数
#类方法是用来显示计数器num的数值
@classmethod
def getNum(cls):
print(cls.num)
#是用来给num进行加一操作,该方法必须保证,当创建好一个学生对象的时候被调用一次
@classmethod
def addNum(cls):
cls.num += 1
#new最终是可以被继承给Student这个子类
def __new__(cls, *args, **kwargs):
ClassRoom.addNum()
return super().__new__(cls)
class Student(ClassRoom):
def __init__(self,name):
self.name = name
s1 = Student('zhangsan')
s2 = Student('lisi')
s3 = Student('wangwu')
s4 = Student('bobo')
ClassRoom.getNum()
在类的内部,有各种变量和方法。这些数据成员,可以在类的外部通过实例或者类名进行调用,例如:
class Student():
def __init__(self,name):
self.name = name
def study(self):
print('正在学习!')
s = Student('lisi')
s.study()
上面的调用方式是我们大多数情况下都需要的,但是往往我们也不希望所有的变量和方法能被外部访问,需要针对性地保护某些成员,限制对这些成员的访问。这样的程序才是健壮、可靠的,也符合业务的逻辑。
在Python中,如果要让内部成员不被外部访问,可以在成员的名字前加上两个下划线__,这个成员就变成了一个私有成员(private)。私有成员只能在类的内部访问,外部无法访问。
class Student():
def __init__(self,name):
#name属性就变成了私有属性
self.__name = name
def study(self):
#可以访问私有成员属性
print('正在学习!学习的人员是:',self.__name)
s = Student('lisi')
s.study()
print(s.__name) #无法访问私有成员
思考:私有成员是否可以被子类继承?
class Person():
def __init__(self,p):
#私有成员
self.__p = p
class Student(Person):
def get_p(self):
print(self.__p)
s = Student(1)
print(s.get_p()) #无法访问私有成员
#程序执行会报错!
那么,以双下划线开头的数据成员是不是一定就无法从外部访问呢?其实也不是!本质上,从内部机制原理讲,外部不能直接访问__age
是因为Python解释器对外把__age
变量改成了_People__age
,也就是_类名__age
(类名前是一个下划线)。因此,投机取巧的话,你可以通过_ People__age
在类的外部访问__age
变量:
class Person():
def __init__(self,p):
#私有成员
self.__p = p
p = Person(1)
print(p._Person__p) #无法访问私有成员
也就是说:Python的私有成员和访问限制机制是“假”的,没有从语法层面彻底限制对私有成员的访问。这一点和常量的尴尬地位很相似。
首先,我们要区分两个概念——“标识名”和“字符串”。两者字面上看起来一样,却是两种东西,比如下面的func函数和字符串“func”:
def func():
pass
s = "func()" #字符串,不是函数调用
前者是函数func的函数名,后者只是一个叫“func”的字符串,两者是不同的事物。我们可以用func()的方式调用函数func,但我们不能用"func"()的方式调用函数。说白了就是,不能通过字符串来调用名字看起来相同的函数!
实例分析
考虑有这么一个场景:需要根据用户输入url的不同,调用不同的函数,实现不同的操作,也就是一个WEB框架的url路由功能。
首先,有一个commons.py文件,它里面有几个函数,分别用于展示不同的页面。
# commons.py
def login():
print('这是登录页面!')
def logout():
print('这是退出页面')
def home():
print('这是主页面')
其次,有一个visit.py文件,作为程序入口,接收用户输入,并根据输入展示相应的页面
# visit.py
import commons
def run():
inp = input('请输入您要访问的网址:')
if inp == 'login':
commons.login()
elif inp == 'logout':
commons.logout()
elif inp == 'home':
commons.home()
else:
print('404')
if __name__ == '__main__':
run()
运行visit.py,输入home,页面结果如下:
请输入您想访问页面的url: home
这是网站主页面!
这就实现了一个简单的url路由功能,根据不同的url,执行不同的函数,获得不同的页面。
然而,让我们思考一个问题,如果commons文件里有成百上千个函数呢(这很常见)?难道在visit模块里写上成百上千个elif?显然这是不可能的!那么怎么办?
仔细观察visit.py中的代码,会发现用户输入的url字符串和相应调用的函数名好像!
如果能用这个字符串直接调用函数就好了!但是,前面已经说了字符串是不能用来调用函数的。为了解决这个问题,Python提供了反射机制,帮助我们实现这一想法!
现在将前面的visit.py修改一下,代码如下:
# visit.py
import commons
def run():
inp = input('请输入您要访问的网址:')
#inp == "login"
func = getattr(commons,inp) #func == login
func() #login()
if __name__ == '__main__':
run()
func = getattr(commons,inp)
语句是关键,通过getattr()函数,从commons模块里,查找到和inp字符串“外形”相同的函数名,并将其返回,然后赋值给func变量。变量func此时就指向那个函数,func()就可以调用该函数。
getattr()函数的使用方法:接收2个参数,前面的是一个类或者模块,后面的是一个字符串,注意了!是个字符串!
这个过程就相当于把一个字符串变成一个函数名的过程。这是一个动态访问的过程,一切都不写死,全部根据用户输入来变化。
瑕疵:前面的代码还有个小瑕疵,那就是如果用户输入一个非法的url,比如jpg,由于在commons里没有同名的函数,肯定会产生运行错误
那怎么办呢?python提供了一个hasattr()的内置函数,用法和getattr()基本类似,它可以判断commons中是否具有某个成员,返回True或False。现在将代码修改一下:
# visit.py
import commons
def run():
inp = input('请输入您要访问的网址:')
if hasattr(commons,inp):
func = getattr(commons,inp)
func()
else:
print('404')
if __name__ == '__main__':
run()
这下就没有问题了!通过hasattr()的判断,可以防止非法输入导致的错误,并将其统一定位到错误页面。
单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于被外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
应用场景
比如,某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.
class Singleton():
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'instance'):
Singleton.instance = super().__new__(cls)
return Singleton.instance
s1 = Singleton()
s2 = Singleton()
print(id(s1),id(s2))
链表就是用来修正/优化列表存在的某一个弊端的。
列表存在的弊端:
分析:
class Node():
def __init__(self,item):
self.item = item
self.next = None
class Link():
def __init__(self):
#head指向第一个节点
self.head = None
def addHead(self,item): #向链表头部插入新的节点
node = Node(item)
node.next = self.head
self.head = node
def travel(self): #遍历链表中节点的item
# print(self.head.item)
# print(self.head.next.item)
# print(self.head.next.next.item)
# print(self.head.next.next.next.item)
# print(self.head.next.next.next.next.item)
cur = self.head
while cur != None:
print(cur.item)
cur = cur.next
def isEmpty(self):
#判定链表是否为空,空返回True,否则返回False
return self.head == None
def length(self):
#返回链表中节点的个数
count = 0 #记录节点的个数
cur = self.head
while cur != None:
count += 1
cur = cur.next
return count
#向链表尾部添加新的节点
def append(self,item):
node = Node(item)
if self.isEmpty():#如果链表为空
self.head = node
else:#链表为非空的情况
pre = None #pre要指向cur前面的一个节点
cur = self.head
while cur != None:
pre = cur
cur = cur.next
#循环结束后cur指向了None而pre指向了最后一个节点
pre.next = node
#将新的节点插入到pos表示的位置中
def insertNode(self,item,pos):
node = Node(item)
pre = None
cur = self.head
if pos == 0:
self.addHead(item)
return
for i in range(pos):
pre = cur
cur = cur.next
pre.next = node
node.next = cur
#从链表中删除item表示的节点
def removeNode(self,item):
pre = None
cur = self.head
if self.head.item == item:#删除的是第一个节点
self.head = cur.next
return
while cur != None:
if cur.item == item:
#条件成立则cur就是我们要删除的节点
pre.next = cur.next
break
else:
pre = cur
cur = cur.next
link = Link()
link.addHead(1)
link.addHead(2)
link.addHead(3)
link.addHead(4)
link.addHead(5)
link.append(6)
link.removeNode(5)
link.travel()