Python面向对象编程.ppt

上传人:牧羊曲112 文档编号:5445844 上传时间:2023-07-07 格式:PPT 页数:71 大小:1.90MB
返回 下载 相关 举报
Python面向对象编程.ppt_第1页
第1页 / 共71页
Python面向对象编程.ppt_第2页
第2页 / 共71页
Python面向对象编程.ppt_第3页
第3页 / 共71页
Python面向对象编程.ppt_第4页
第4页 / 共71页
Python面向对象编程.ppt_第5页
第5页 / 共71页
点击查看更多>>
资源描述

《Python面向对象编程.ppt》由会员分享,可在线阅读,更多相关《Python面向对象编程.ppt(71页珍藏版)》请在三一办公上搜索。

1、第六章 面向对象编程,计算机科学与软件学院,面向对象的一些基本概念和特征,类:用来描述具有相同属性和方法的对象的集合,它定义该集合中每个对象所共有的属性和方法,对象是类的实例。类变量:类变量在整个实例化的对象中是公用的,类变量定义在类中且在函数体之外,类变量通常不作为实例变量使用。数据成员:类变量或者实例变量用于处理类及其实例对象的相关数据。方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override)。,实例变量:定义在方法中的变量,只作用于当前实例的类。继承:即一个派生类(derived class)继承基类(base class)的字段和方法

2、,继承也允许把一个派生类的对象作为一个基类对象对待。实例化:创建一个类的实例,类的具体对象。方法:类中定义的函数。对象:对象包括两类数据成员(类变量和实例变量)和方法,通过类定义的数据结构实例化。,6.1 类的定义与使用,Python中的类是一个抽象的概念,比函数还要抽象。我们可以把它简单看做是数据以及由存取、操作这些数据的方法所组成的一个集合。那为什么还要用类来取代函数呢?,类有如下优点:,类对象是多态的:也就是具有多种形态,这意味着我们可以对不同的类对象使用同样的操作方法,而不需要额外编写代码。类的封装:类封装之后,可以直接调用类的对象来操作内部的一些类方法,不需要让使用者看到代码工作的细

3、节。类的继承:类可以从其它类或者基类中继承它们的方法,直接使用。,6.1.1 类的定义,类是对现实世界中一些事物的封装,所有类的开头都要包括关键字class,紧接着的是类名和冒号,随后是定义类的类体代码。语法格式如下:class ClassName:documentation string.,object是“所有类之父”。如果你的类没有继承任何其他父类,object将作为默认的父类,它位于所有类继承结构的最上层(继承的概念在本章稍后介绍),定义一个类可以采用下面的方式。,【实例6-1】类的定义。class people:#定义基本属性 name=age=0#定义私有属性,私有属性在类外部无法直

4、接进行访问 _weight=0#定义构造方法 def _init_(self,n,a,w):self.name=n self.age=a self._weight=w#定义类本身的方法 def speak(self):print(%s is speaking:I am%d years old%(self.name,self.age)#类调用p=people(tom,10,30)p.speak(),注意:在上面的例子中,name和age是类的公有属性。_weight使用两个下划线开头,表示声明该属性为私有属性,它不能在类的外部被使用或直接访问,但可以在类内部使用self._weight调用。,【

5、实例6-2】接上例。print(p.name)print(p._weight)出错的原因在于,在类的外部使用了私有属性。,6.1.2 类属性与方法,1.类的公有属性public_attrs:符合正常的变量命名规则,开头没有下划线,类外部可以直接进行访问。如上例中的name、age等。2.类的私有属性_private_attrs:由两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时的格式为self._private_attrs。,【实例6-3】类的私有属性。class Counter:_privateCount=1#私有属性 publicCount=1#公有

6、属性 def count(self):self._privateCount+=1 self.publicCount+=1 print(self._privateCount)counter_1=Counter()counter_1.count()#打印数据print(counter_1.publicCount)#打印数据print(counter_1._privateCount)#报错,实例不能访问私有属性,出错的原因在于,在类的外部使用了私有属性。,3.类的构造方法_init_:叫作构造函数或者构造方法,它在生成一个对象时被自动调用。在上文的例子中p=people(tom,10,30)语句就是

7、调用_init_方法将参数传递给self.name、self.age和self._weight。4.类的公共方法public _method:在类的内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数。self在Python里不是关键字,self代表当前对象的地址,类似于Java语言中的this。,5.类的私有方法_private_method:由两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用时格式为self._private_methods。,【实例6-4】类的私有方法。class Site:def _init_

8、(self,name,url):self.name=name#公有属性 self._url=url#私有属性 def printme(self):print(name:,self.name)print(url:,self._url)def _printme_1(self):#私有方法 print(输出私有方法)def printme_1(self):#公共方法 print(输出公共方法)self._printme_1()wz=Site(百度网址,)wz.printme()#打印数据wz.printme_1()#打印数据,调用私有方法_printme_1()wz._printme_1()#报错,

9、实例不能访问私有属性,出错的原因在于,实例不能访问私有方法。,6.单下划线(_)以单下划线开始的成员变量叫做保护变量,意思是只有类对象和子类对象自己能访问到这些变量,简单的模块级私有化只需要在属性名前使用一个单下划线字符。以单下划线开头(_ singlePrivate)的属性代表不能直接访问的类属性,需通过类提供的接口进行访问,这就防止模块的属性用“from mymodule import*”来加载,这是严格基于作用域的,所以这同样适合于函数。,【实例6-5】下划线的使用。class Test():def _init_(self):pass def public(self):print(这是公

10、共方法)def _singlePrivate(self):print(这是单下划线方法)def _doublePrivate(self):print(这是双下划线方法)t=Test()t.public()#可以调用t._singlePrivate()#可以调用t._doublePrivate()#出现错误,注意:f._ singlePrivate()可以直接访问,不过根据Python的约定,应该将其视作private,而不要在外部使用它们,良好的编程习惯是不要在外部使用它。同时,根据Python docs的说明,_object和_object的作用域限制在本模块内。,7.类的专有方法下面是Py

11、thon常用的一些专有方法,如表6-1所示。,表6-1 类的专有方法,【例6-6】_del_和_repr_专有方法的使用。class Test:def _init_(self,name=None):self.name=name def _del_(self):print(hello world!)def _repr_(self):return Study(Jacky)def say(self):print(self.name)Test(Tim)#自动调用_del_方法s=Test(Tim)s.say()print(s)#自动调用_repr_方法print(Test(Kitty)#先自动调用_r

12、epr_方法,然后自动调用_del_方法,【实例6-7】_str_专有方法的使用。class Test:def _init_(self,number):self.a=number0:3 self.b=number3:6 def _str_(self):return“%s%s”%(self.a,self.b)def test():num=Test(input(“请输入数字:n”)print(输入的数字是:,num)#执行脚本test(),6.1.3 关于Python的作用域和命名空间。,1.作用域与命名空间的解释作用域是指Python程序可以直接访问到的命名空间。“直接访问”在这里意味着访问命名

13、空间中的命名时无需加入附加的修饰符。命名空间本质上是一个字典,它的键就是变量名,它的值就是那些变量的值。Python使用命名空间来记录变量的轨迹。,在Python程序中的任何一个地方,都存在三个可用的命名空间:(1)每个函数都有自已的命名空间(称作局部命名空间),它记录了函数的变量,包括函数的参数和局部定义的变量。(2)每个模块都有自已的命名空间(称作全局命名空间),它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。(3)每个模块都有可访问的内置命名空间,它存放着内置函数和异常。,2.命名空间的查找顺序(1)局部命名空间特指当前函数或类的方法。如果函数中定义一个局部变量x,

14、Python将使用这个变量,然后停止搜索。(2)全局命名空间特指当前的模块。如果模块中定义名为x的变量、函数或类,Python将使用这个变量,然后停止搜索。,(3)内置命名空间对每个模块都是全局的,作为最后的尝试,Python将假设x是内置函数或变量。(4)如果Python在这些命名空间中都找不到x,它将放弃查找并引发一个NameError异常,同时传递“There is no variable named x”这样一条信息。,当函数被调用时创建一个局部命名空间,我们可以通过globals()和locals()内建函数判断某一名字属于哪个名称空间。locals()是只读的,globals()不

15、是。,【实例6-8】locals()函数示例。def foo(arg,a):x=1 y=abc for i in range(5):j=2 k=i print(locals()#调用函数的打印结果foo(2,3)locals()实际上没有返回局部命名空间,它返回的是一个拷贝。所以对它进行改变对局部命名空间中的变量值并无影响。,【实例6-9】globals()函数示例。print(当前的全局命名空间:)var=globals()print(var)globals()函数返回实际的全局命名空间,而不是一个拷贝。所以对globals()函数所返回的var的任何改动都会直接影响到全局变量。,3.嵌套函

16、数命名空间的查找步骤:(1)先在当前函数(嵌套的函数或lambda匿名函数)的命名空间中搜索。(2)然后在父函数的命名空间中搜索。(3)接着在模块命名空间中搜索。(4)最后在内建函数的命名空间中搜索。下面举例说明。,【实例6-10】嵌套函数命名空间示例。address=地址:def func_country(country):def func_part(part):city=天津#覆盖父函数的part变量 print(address+country+city+part)city=北京#初始化city变量#调用内部函数 func_part(西青)#初始化part变量#调用外部函数func_cou

17、ntry(中国)#初始化country变量以上实例中,address在全局命名空间中,country在父函数的命名空间中,city、part在子函数的命名空间中。,6.2 Python类与对象,类对象类对象支持两种操作:属性引用和实例化。类对象的属性引用和Python中所有属性的引用一样,都使用标准的语法:obj.name。类对象创建之后,类命名空间中所有的命名都是有效属性名。,在Python中,方法定义在类的定义中,但只能被类对象的实例所调用。调用一个方法的途径分三步:1.定义类和类中的方法。2.创建一个或若干个实例,即将类实例化。3.用所创建的实例调用方法。,【实例6-11】类的定义与实例

18、化。class MyClass:一个简单的类实例 i=12 def f(self):return hello world#实例化类MyClass=MyClass()#访问类的属性和方法print(MyClass 类的属性 i 为:,MyClass.i)print(MyClass 类的方法 f 输出为:,MyClass.f(),本例中,MyClass.i和MyClass.f()是有效的属性引用,分别返回一个整数和一个方法对象。也可以对类属性赋值,即可以通过给MyClass.i赋值来修改它。如:MyClass.i=56print(修改后MyClass 类的属性 i 为:,MyClass.i),类的

19、实例化使用函数符号,只要将类对象看作是一个返回新的类实例的无参数函数即可。例如(假设沿用前面的类):MyClass=MyClass()该语句创建了一个新的类实例(对象),并将该对象赋给局部变量MyClass。通过实例化操作(“调用”一个类对象)来创建一个空的对象时,通常会把这个新建的实例赋给一个变量。赋值在语法上不是必须的,但如果不把这个实例保存到一个变量中,它就没有用,会被垃圾收集器自动回收,因为没有任何引用指向这个实例。,很多类都倾向于创建一个有初始化状态的对象。因此类可能会定义一个名为 _init_()的特殊方法(构造方法),像下面这样:def _init_(self):self.dat

20、a=,当类被调用时,实例化的第一步就是创建实例对象,一旦对象创建,Python就检查是否已经实现_init_()方法。默认情况下,如果没有定义(或覆盖)特殊方法_init_(),对实例不会施加任何特别的操作。任何所需的特定操作,都需要程序员实现_init_()方法,覆盖它的默认行为。所以在下例中,可以这样创建一个新的实例:MyClass_1=MyClass()_init_()方法可以有参数。事实上,正是通过_init_()方法,参数被传递到类的实例上。,【实例6-12】使用带参数的_init_()方法初始化。class Complex:def _init_(self,realpart,imag

21、part):self.r=realpart self.i=imagpartx=Complex(2.4,-4.6)print(x.r,x.i),类的属性有两种有效的属性名:数据属性和特殊类属性。1.数据属性这相当于Smalltalk中的“实例变量”或C+中的“数据成员”。和局部变量一样,数据属性不需要声明,第一次使用时它们就会生成。,【实例6-13】数据属性说明。class foo(object):f=100print(foo.f)print(foo.f+1),2.特殊类属性对任何类foo,类foo的部分特殊属性如表6-2所示。,表6-2 特殊类属性,【实例6-14】类属性说明。class My

22、Class(object):MyClass 类定义 myVer=3.4 def showMyVer(self):print(MyClass.myVer)print(dir(MyClass)print(MyClass._dict_)根据上面定义的类,我们使用dir()和特殊类属性_dict_来查看一下类的属性:,从上面可以看到,dir()返回的仅是对象的属性的一个名字列表,而_dict_返回的是一个字典,它的键是属性名,值是相应的属性对象的数据值。结果还显示MyClass类中两个熟悉的属性,showMyVer和myVer,以及一些新的属性。,实例属性内建函数dir()可以显示类属性,同样还可以打

23、印所有实例属性。【实例6-15】实例属性说明。class foo(object):passfoo_1=foo()print(dir(foo_1),实例有两个特殊属性,如表6-3所示。表6-3 特殊实例属性,现在使用类foo及其实例foo_1来看看这些特殊实例属性。【实例6-16】查看实例属性_dict_和_class_。class foo(object):passfoo_1=foo()print(foo_1._dict_)print(foo_1._class_),foo_1现在还没有数据属性,但我们可以添加一些再来检查_dict_属性。【实例6-17】查看类的数据属性。class foo(ob

24、ject):passfoo_1=foo()foo_1.f=100foo_1.b=helloprint(foo_1._dict_)print(foo_1._class_),注意:_dict_属性由一个字典组成,包含一个实例的所有属性。键是属性名,值是属性相应的数据值。字典中仅有实例属性,没有类属性或特殊属性。,6.2.4 一些说明同名的数据属性会覆盖方法属性,最好以某种命名约定来避免冲突,因为这在大型程序中可能会导致难以发现的bug。可选的约定包括:(1)类名由大写字母书写。(2)方法的首字母大写。(3)数据属性名前缀小写(可能只是一个下划线)。(4)方法使用动词而数据属性使用名词。,数据属性可

25、以由方法引用,也可以由普通用户调用。程序员应该小心使用数据属性,程序员可能会因为随意修改数据属性而破坏本来由方法维护的数据一致性。需要注意的是,程序员只要注意避免命名冲突,就可以随意向实例中添加数据属性而不会影响方法的有效性再次强调,命名约定可以省去很多麻烦。,对Python而言,self绝对没有任何特殊含义。通过使用self参数的方法属性,方法可以调用其它的方法。【实例6-18】self参数的使用。class Bag:def _init_(self):self.data=def add(self,x):self.data.append(x)print(self.data)def addtwi

26、ce(self,x):self.add(x)print(self.data)bag_1=Bag()bag_1.add(5)bag_1.addtwice(6),6.3 继承,单继承Python同样支持类的继承,如果一种语言不支持继承,类就没有什么意义,类还允许派生,用户可以创建一个子类,它也是类,而且继承父类所有的特征和属性。派生类的定义如下所示:class DerivedClassName(BaseClassName):命名BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。基类可以定义在另一个模块中,这一点非常有用,格式如下:class DerivedClassNam

27、e(modname.BaseClassName):,【实例6-19】单继承实例。#类定义class people:#定义基本属性 name=age=0#定义私有属性,私有属性在类外部无法直接进行访问 _weight=0#定义构造方法 def _init_(self,n,a,w):self.name=n self.age=a self._weight=w def speak(self):print(%s says:I am%d years old%(self.name,self.age),#单继承class student(people):grade=def _init_(self,n,a,w,

28、g):#调用父类的构造函数 people._init_(self,n,a,w)self.grade=g#重写父类的方法 def speak(self):print(%s says:I am%d years old,I am in Grade%d.%(self.name,self.age,self.grade)s=student(Tom,10,90,3)s.speak(),提示:派生类定义的执行过程和基类是一样的。构造派生类对象时,就继承基类。这在解析属性引用的时候尤其有用:如果在类中找不到请求调用的属性,就搜索基类。如果基类是由别的类派生而来,这个规则会递归地应用上去。,6.3.2 多继承Py

29、thon同样有限地支持多继承形式,多继承的类定义的一般形式如下:class DerivedClassName(Base1,Base2,Base3):这里唯一需要解释的语义是解析类属性的规则。顺序是深度优先,从左到右。因此,如果在DerivedClassName(示例中的派生类)中没有找到某个属性,就会搜索Base1,然后递归地搜索其基类,如果最终没有找到,就搜索Base2,依此类推。深度优先不区分属性继承自基类还是直接定义。,【实例6-20】多继承实例。#类定义class people:#定义基本属性 name=age=0#定义私有属性,私有属性在类外部无法直接进行访问 _weight=0#定

30、义构造方法 def _init_(self,n,a,w):self.name=n self.age=a self._weight=w def speak(self):print(%s says:I am%d years old%(self.name,self.age),#单继承示例class student(people):grade=def _init_(self,n,a,w,g):#调用父类的构函 people._init_(self,n,a,w)self.grade=g#覆写父类的方法 def speak(self):print(“%s says:I am%d years old,I a

31、m in Grade%d.”%(self.name,self.age,self.grade),#另一个类,多重继承之前的准备class speaker():topic=name=def _init_(self,n,t):self.name=n self.topic=t def speak(self):print(“I am%s,I am a speaker,my topic is%s”%(self.name,self.topic)#多重继承class sample(speaker,student):a=def _init_(self,n,a,w,g,t):student._init_(self

32、,n,a,w,g)speaker._init_(self,n,t)test_1=sample(Tom,12,90,3,One World One Dream)test_1.speak()#方法名同,默认调用的是在括号中排前的父类的方法,即speaker类里面的方法。,注意:不加限制地使用多继承会带来维护上的噩梦,因为Python中只依靠约定来避免命名冲突。多继承一个很有名的问题是派生继承的两个基类都是从同一个基类继承而来。目前还不清楚这在语义上有什么意义,然而这会造成意料之外的后果。,6.3.3 方法重写如果父类方法的功能不能满足需求,可以在子类里面重写父类的方法。【实例6-21】方法重写。c

33、lass Parent:#定义父类 def myMethod(self):print(调用父类方法)class Child(Parent):#定义子类 def myMethod(self):print(调用子类方法)Child_1=Child()#子类实例Child_1.myMethod()#子类调用重写方法,6.4 项目实例类与继承实例本例定义三个类,分别为Member类、Student类、Teacher类,Student类和Teacher类分别继承Member类,并且定义自己的tell()方法,其中使用了Member类的方法。,class Member:def _init_(self,na

34、me,age):self.name=name self.age=age def tell(self):print(Name:%s,Age:%d%(self.name,self.age)class Student(Member):def _init_(self,name,age,marks):Member._init_(self,name,age)self.marks=marks def tell(self):Member.tell(self)print(Marks:%d%self.marks)class Teacher(Member):def _init_(self,name,age,sala

35、ry):Member._init_(self,name,age)self.salary=salary def tell(self):Member.tell(self)print(Salary:%d%self.salary),Stu_1=Student(Tom,21,77)Stu_2=Student(Tim,19,87)Stu_3=Student(Tam,22,93)Tea_1=Teacher(Mrs.Wang,42,5200)Tea_2=Teacher(Mr.Zhang,39,4800)members=Stu_1,Stu_2,Stu_3,Tea_1,Tea_2for mem in member

36、s:mem.tell(),6.5 本章小结,本章对面向对象技术进行了简单介绍,重点内容如下:1.类的定义与使用首先介绍类、类变量、数据成员、方法重写、实例变量、继承、实例化、方法、对象等概念;其次介绍类的定义与使用,包括使用类的优点、类定义的语法格式、类的属性与方法以及Python常用的专有方法。,2.类与对象首先介绍类对象支持的两种操作:属性引用和实例化;其次介绍类的属性:两种有效的属性名、数据属性和特殊类属性,包括_name_、_doc_等;再次介绍实例属性:内建函数dir()的使用、两个特殊属性_class_和_dict_等;最后介绍命名约定,并对self的使用情况进行举例说明。,3.类的继承首先介绍了单继承和多继承的概念,并分别举例说明;其次介绍了方法重写。4.实例项目类的继承、方法重写。,本章结束谢谢,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号