带你掌握Python面向对象方法,与C++面向对象编程到底有啥区别?

面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。

 

类和对象是面向对象程序设计的两个重要概念。

类和对象的关系即数据类型与变量的关系,根据一个类可以创建多个对象,而每个对象只能是某一个类的对象。类规定了可以用于存储什么数据,而对象用于实际存储数据,每个对象可存储不同的数据。

与C/C++等语言不同,Python中提供的基本数据类型也是类,如int、float等。

 

类中可以包含各种属性及各种方法。属性对应一个类可以用来保存哪些数据,而方法对应一个类可以支持哪些操作(即数据处理)。

 

通过类,可以把数据和操作封装在一起,从而使得程序结构更加清晰,这也就是所谓的类的封装性。例:定义一个空类

class Student: #定义一个名字为Student的类    pass #一个空语句,起到占位作用,表示Student类中         #没有任何属性和方法if __name__=='__main__':    stu=Student() #创建Student类的对象,并将创建的对象赋给变量stu    print(stu) #输出stu   #  输出  <__main__.Student object at 0x00000216EE7DF0F0>#  提示:每次创建对象时,系统都会在内存中选择一块区域分配给对象,每次# 选择的内存通常是不一样的。因此,实际运行时会看到一个不同的stu对象地址。

对类属性的访问,既可以直接通过类名访问,也可以通过该类的对象

访问,访问方式为:

类名或对象名.属性名

 

私有属性,是指在类内可以直接访问、而在类外无法直接访问的属性。

Python中规定,在定义类时,如果一个类属性名是以__(两个下划线)开头,则该类属性为私有属性。

实际上,Python中并不存在无法访问的私有属性。如果我们在类中定

义了一个私有属性,则在类外访问该私有属性时需要在私有属性名

前加上“_类名”。例如:

class Student: #定义Student类   __id='未知' #定义Student类中有一个__id私有属性
if __name__=='__main__':  stu=Student() #定义Student类对象stu  print('身份证号:%s'%stu._Student__id)

类中的方法分为两类:普通方法和内置方法。

• 普通方法需要通过类的实例对象根据方法名调用;

• 内置方法是在特定情况下由系统自动执行。

 

在定义类的普通方法时,要求第一个参数需要对应调用方法时所使用的实例对象(一般命名为self,但也可以改为其他名字)。在通过类的实例对象调用类中的普通方法时,并不需要传入self参数的值,self会自动对应调用该方法时所使用的对象。

 

注意:通过实例对象调用时会自动将该实例对象传给self,而通过类调用时则不会有这个隐含的参数传递。

 

构造方法是Python类中的内置方法之一,它的方法名为__init__,在创建一个类对象时会自动执行,负责完成新创建对象的初始化工作。

 

析构方法是类的另一个内置方法,它的方法名为__del__,在销毁一个类对象时会自动执行,负责完成待销毁对象的资源清理工作,类对象销毁有如下三种情况:

(1)局部变量的作用域结束。

(2)使用del删除对象。

(3)程序结束时,程序中的所有对象都将被销毁。

常见的内置方法

 

__str__ 函数  :str函数对类对象进行处理时或者调用Python内置函数format()和print()时自动执行,__str__方法的返回值必须是字符串。

比较运算的内置方法

 

__gt__(self, other) 进行self>other运算时自动执行

__lt__(self, other) 进行self<other运算时自动执行

__ge__(self, other) 进行self>=other运算时自动执行

__le__(self, other) 进行self<=other运算时自动执行

__eq__(self, other) 进行self==other运算时自动执行

__ne__(self, other) 进行self!=other运算时自动执行

 

class Student: #定义Student类    def __init__(self, name, age): #定义构造方法        self.name=name #将self对应对象的name属性赋为形参        #name的值        self.age=age #将self对应对象的age属性赋为形参age的值    def __le__(self, other): #定义内置方法__le__        return self.age<=other.ageif __name__=='__main__’:    stu1=Student('李晓明',19) # 定义Student类对象stu1    stu2=Student('马红',20) #定义Student类对象stu2    print('马红的年龄小于等于李晓明的年龄:', stu2<=stu1) #输出 马红的年龄小于等于李晓明的年龄:False

 

内置函数isinstance 用于判断一个对象所属的类是否是指定类或指定类的子类;

内置函数issubclass 用于判断一个类是否是另一个类的子类;

内置函数type  用于获取一个对象所属的类。

 

如果我们要判断一个对象的类型是否是指定类或该类的子类,则可以使用isinstance函数

如果我们要判断一个对象的类型是否是指定类,则可以使用“type(对象名)==类名”的方式。

 

继承

继承允许开发者基于已有的类创建新的类。

-如果一个类C1通过继承已有类C而创建,则将C1称作子类(subclass),将C称做基类、父类或超类(base class、super class)

-子类会继承父类中定义的所有属性和方法,另外也能够在子类中增加新的属性和方法。

-如果一个子类只有一个父类,则将这种继承关系称为单继承;如果一个子类有两个或更多父类,则将这种继承关系称为多重继承

子类的定义 。定义子类时需要指定父类,格式为:

class 子类名(父类名1, 父类名2, …, 父类名M):
 
​​​​​​​ 语句1    
 语句2
    …

 语句N

 

方法重写 是指子类可以对从父类中继承过来的方法进行重新定义,从而使得

子类对象可以表现出与父类对象不同的行为。

class Person: #定义Person类    def __init__(self, name): #定义构造方法        self.name=name #将self对象的name属性赋为形参name的值    def PrintInfo(self): #定义PrintInfo方法        print('姓名:%s'%self.name)class Student(Person): #以Person类作为父类定义子类Student    def __init__(self, sno, name): #定义构造方法        self.sno=sno #将self对象的sno属性赋为形参sno的值        self.name=name #将self对象的name属性赋为形参name的值    def PrintInfo(self): #定义PrintInfo方法        print('学号:%s,姓名:%s'%(self.sno,self.name))def PrintPersonInfo(person): #定义普通函数PrintPersonInfo    print('PrintPersonInfo函数中的输出结果', end='#')    person.PrintInfo() #通过person调用PrintInfo方法if __name__=='__main__':    p=Person('李晓明') #创建Person类对象p    stu=Student('1810100','李晓明') #创建Student类对象stu    p.PrintInfo()    stu.PrintInfo()    PrintPersonInfo(p)    PrintPersonInfo(stu)#输出     李晓明1810100,姓名:李晓明李晓明1810100,姓名:李晓明

多态,是指在执行同样代码的情况下,系统会根据对象实际所属的类去调用相应类中的方法。

super方法

super方法用于获取父类的代理对象,以执行已在子类中被重写的父

类方法,其语法格式为:

super([类名[, 对象名或类名]])

super方法有两个参数:

第一个参数是要获取父类代理对象的类名。

第二个参数如果传入对象名,则该对象所属的类必须是第一个参数指定的类或该类的子类,找到的父类对象的self会绑定到这个对象上;如果传入类名,则该类必须是第一个参数指定的类的子类。

 

在一个类A的定义中调用super方法时,可以将两个参数都省略,此时,super()等价于super(A, self),即获取A的父类代理对象,且获取到的父类代理对象中的self绑定到当前A类对象的self上。

class Person: #定义Person类  def __init__(self, name): #定义构造方法    print('Person类构造方法被调用!')    self.name=name #将self对象的name属性赋为形参name的值class Student(Person): #以Person类作为父类定义子类Student  def __init__(self, sno, name): #定义构造方法    print('Student类构造方法被调用!')    super().__init__(name) #调用父类的构造方法9     self.sno=sno #将self对象的sno属性赋为形参sno的值class Postgraduate(Student): #以Student类作为父类定义子类Postgraduate  def __init__(self, sno, name, tutor): #定义构造方法    print('Postgraduate类构造方法被调用!')    super().__init__(sno, name) #调用父类的构造方法    self.tutor=tutor #将self对象的tutor属性赋为形参tutor的值if __name__=='__main__':  pg=Postgraduate('1810100','李晓明','马红') #创建Postgraduate类对象pg  print('学号:%s,姓名:%s,导师:%s'%(pg.sno,pg.name,pg.tutor))
#输出  Postgraduate类构造方法被调用!Student类构造方法被调用!Person类构造方法被调用!学号:1810100,姓名:李晓明,导师:马红

“super().__init__(sno,name)”与“super(Postgraduate,self).__init__(sno, name) ”等价。

类方法

类方法是指使用@classmethod修饰的方法,其第一个参数是类本身(而不是类的实例对象)。

类方法的特点是既可以通过类名直接调用,也可以通过类的实例对象调用。

class Complex: #定义Complex类   def __init__(self,real=0,image=0): #定义构造方法       self.real=real #初始化一个复数的实部值       self.image=image #初始化一个复数的虚部值   @classmethod   def add(cls,c1,c2): #定义类方法add,实现两个复数的加法运算       print(cls) #输出cls       c=Complex() #创建Complex类对象c       c.real=c1.real+c2.real #实部相加       c.image=c1.image+c2.image #虚部相加       return cif __name__=='__main__':   c1=Complex(1,2.5)   c2=Complex(2.2,3.1)   c=Complex.add(c1,c2) #直接使用类名调用类方法add   print('c1+c2的结果为%.2f+%.2fi'%(c.real,c.image))#输出   <class '__main__.Complex'>c1+c2的结果为3.20+5.60i

“c=Complex.add(c1,c2) ”改为“c=c1.add(c1, c2) ”或

“c=c2.add(c1, c2)”或“c=Complex().add(c1, c2) ”,程序运行后可得到相同的输出结果,即类方法也可以使用实例对象调用。

通过“print(cls) ”输出类方法add的第一个参数,从输出结果中可以看到cls是Complex类。

 

静态方法

静态方法是指使用@staticmethod修饰的方法。静态方法既可以直接通过类名调用,也可以通过类的实例对象调用。

与类方法不同的地方在于,静态方法中没有类方法中的第一个类参数。

@staticmethoddef add(c1,c2): #定义类方法add,实现两个复数的加法运算   c=Complex() #创建Complex类对象c   c.real=c1.real+c2.real #实部相加   c.image=c1.image+c2.image #虚部相加   return c

 

动态扩展类

Python作为一种动态语言,除了可以在定义类时定义属性和方法外,还可以动态地为已经创建的对象绑定新的属性和方法。

在给对象绑定方法时,需要使用types模块中的MethodType方法,其第一个参数是要绑定的函数名,第二个参数是绑定的对象名。

​​​​​​​

from types import MethodType #从types模块中导入MethodType方法 class Student: #定义学生类     pass def SetName(self,name): #定义SetName函数     self.name=name def SetSno(self,sno): #定义SetSno函数     self.sno=snoif __name__=='__main__':    stu1=Student() #定义Student类对象stu1    stu2=Student() #定义Student类对象stu2    stu1.SetName=MethodType(SetName,stu1)    #为stu1对象绑SetName方法    Student.SetSno=SetSno #为Student类绑定SetSno方法    stu1.SetName('李晓明')    stu1.SetSno('1810100')    #stu2.SetName('张刚') #取消注释则会报错,因为职位stu1绑定了方法    stu2.SetSno('1810101')

 

__slots__函数:在定义类时,Python提供了__slots__变量以限制可动态扩展的属性。该限制只对__slots__所在类的实例对象有效。如果子类中没有__slots__定义,则子类的实例对象可以进行任意属性的动态扩展。

(一般也用不到,作为了解)

@property装饰器

类中的属性可以直接访问和赋值,这为类的使用者提供了方便,但也带来了问题:类的使用者可能会给一个属性赋上超出有效范围的值。

为了解决这个问题,Python提供了@property装饰器,可以将类中属性的访问和赋值操作自动转为方法调用,这样可以在方法中对属性值的取值范围做一些条件限定。

 

直接使用@property就可以定义一个用于获取属性值的方法(即getter)。如果要定义一个设置属性值的方法(setter),则需要使用名字“@属性名.setter”的装饰器。

如果一个属性只有用于获取属性值的getter方法,而没有用于设置属性值的setter方法,则该属性是一个只读属性,只允许读取该属性的值、而不能设置该属性的值。​​​​​​​

import datetimeclass Student: #定义Student类    @property    def score(self): #用@property装饰器定义一个用于获取score值的方法        return self._score    @score.setter    def score(self, score): #用score.setter定义一个用于设置score值的方法        if score<0 or score>100: #不符合0~100的限定条件            print('成绩必须在0~100之间!')        else:            self._score=score    @property    def age(self): #用@property装饰器定义一个用于获取age值的方法        return datetime.datetime.now().year-self.birthyearif __name__=='__main__':    stu=Student() #创建Student类对象stu    stu.score=80 #将stu对象的score属性赋值为80    stu.birthyear=2000 #将stu对象的birthyear属性赋值为2000    print('年龄:%d,成绩:%d'%(stu.age,stu.score))
#输出年龄:18,成绩:80#stu.age=19 #取消前面的注释符则会报错stu.score=105 #将stu对象的score属性赋值为105print('年龄:%d,成绩:%d'%(stu.age,stu.score))

注意:在类的setter和getter方法中使用self访问属性时,需要在属性名前加上下划线,否则系统会因不断递归调用而报错。

 

end

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值