Python学习笔记-面向对象

一、类和实例

1. 定义

类:具有一些相同特征的物体

实例:确定的某一个个体

比如:人-----刘德华         汽车-----车牌号为xxxx的车               猪-----佩奇         

2. 一般格式

      class 类名:

              def __init__(self, 形参, ...):      #初始化方法

                      self.变量名=形参

                       ...

               方法...

1)根据约定,类名首字母大写,实例首字母小写

2)类中的函数称为方法,函数的一切都适用于方法,只是调用的方式不同

3)根据类创建实例时,会自动运行初始化方法

4)self必不可少,是一个指向实例本身的引用,让实例能够访问类中的属性和方法,每个实例方法的调用都会自动传递self,即不需要给self传值,需要给后面的形参传值

5)self.变量名可以供类中所有方法使用,可以通过实例名.变量名来访问变量,这种变量称为属性,查看实例的属性:实例名.__dict__

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
rec=Rectangle(2,1)       #实例化一个长方形
print(rec.permeter())    #6
print(rec.area())        #2
print(rec.length)        #2
print(rec.__dict__)      #{'length': 2, 'width': 1}

3. 属性

1)默认值

跟之前函数里的形参默认值类似

class Rectangle():
    def __init__(self,length=1,width=1):      #给形参添加默认值
        self.length=length
        self.width=width
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
rec=Rectangle()        #没有传任何实参
print(rec.permeter())     #4
print(rec.area())         #1
print(rec.__dict__)       #{'length': 1, 'width': 1}

在初始化方法里指定,就不需要再写该形参了

class Rectangle():
    def __init__(self,length,width):
        self.length=length
        self.width=width
        self.color='black'

rec=Rectangle(2,1)
print(rec.color)    #black

2)实例属性

定义在初始化方法内,要加self前缀,只能由实例调用,不能由类调用

class Rectangle():
    def __init__(self,length,width):
        self.length=length
        self.width=width

rec=Rectangle(2,1)
print(rec.length)    #2
print(Rectangle.length)    #AttributeError: type object 'Rectangle' has no attribute 'length'

3)类属性  

定义在类里,没有self前缀,实例和类都能调用

class Rectangle():
    disc='两边的长相等,两边的宽相等,长和宽的夹角为90°'

rec=Rectangle()
print(rec.disc)    #两边的长相等,两边的宽相等,长和宽的夹角为90°
print(Rectangle.disc)    #两边的长相等,两边的宽相等,长和宽的夹角为90°

 4)修改属性值

直接修改

class Rectangle():
    def __init__(self,length,width):
        self.length=length
        self.width=width
    
rec=Rectangle(2,1)
print(rec.length)    #2
rec.length=3         #访问属性修改length的值
print(rec.length)    #3

通过类中的方法修改,这样就不需要在外面访问属性

class Rectangle():
    def __init__(self,length,width):
        self.length=length
        self.width=width
    def update_length(self,new_length):   #定义一个修改长的方法
        self.length=new_length
    def update_width(self,new_width):     #定义一个修改宽的方法
        self.length=new_width
rec=Rectangle(2,1)
print(rec.length)    #2
rec.update_length(3)   #调用修改长的方法
print(rec.length)    #3

 对于类属性,可以通过类名.属性名永久修改属性值,通过实例名.属性名修改只对当前实例有效

class Rectangle():
    disc='两边的长相等,两边的宽相等,长和宽的夹角为90°'

rec=Rectangle()
rec.disc='这是一个长方形'     #临时修改类属性
print(rec.disc)    #这是一个长方形
print(Rectangle.disc)     #两边的长相等,两边的宽相等,长和宽的夹角为90°
rec1=Rectangle()    #新建一个实例
print(rec1.disc)       #两边的长相等,两边的宽相等,长和宽的夹角为90° 
Rectangle.disc='这是一个长方形'     #永久修改类属性
print(rec.disc)    #这是一个长方形
print(Rectangle.disc)     #这是一个长方形
rec2=Rectangle()    #新建一个实例
print(rec2.disc)    #这是一个长方形

5)将实例用作属性

在比较复杂的类中,可以将类划分成一个个小类,这样就会使得代码清晰易懂

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width    
        self.disc=Discription()
    
class Discription:
    def __init__(self,disc='这是一个长方形'):   
        self.disc=disc
    def discribe_rectangle(self):
        print('两边的长相等,两边的宽相等,长和宽的夹角为90°')
    
rec=Rectangle(2,1)
print(rec.disc.disc)          #这是一个长方形  rec.disc创建了一个Discription的实例,通过rec.disc.disc访问disc属性
rec.disc.discribe_rectangle()     #两边的长相等,两边的宽相等,长和宽的夹角为90°

4. 方法

1)实例方法

只能由实例调用,不能由类调用

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
rec=Rectangle(2,1)       #实例化一个长方形
print(rec.permeter())    #6
print(Rectangle.permeter())   #TypeError: permeter() missing 1 required positional argument: 'self'

2)类方法

实例和类都能调用

在类方法的上一行加一个装饰器@classmethod,表示下面的方法都是类方法

cls必不可少,约定实例方法用self,类方法用cls

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    @classmethod
    def discription(cls):
        print('两边的长相等,两边的宽相等,长和宽的夹角为90°')
rec=Rectangle(2,1)       #实例化一个长方形
rec.discription()           #两边的长相等,两边的宽相等,长和宽的夹角为90°
Rectangle.discription()     #两边的长相等,两边的宽相等,长和宽的夹角为90°
print(type(rec.discription))       #<class 'method'>

3)静态方法

实例和类都能调用

在类方法的上一行加一个装饰器@staticmethod,表示下面的方法都是静态方法

本质上是函数,只是写在了类里面,不依赖类和实例

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    @staticmethod
    def sum(a,b):
        return a+b
rec=Rectangle(2,1)       #实例化一个长方形
print(rec.sum(1,2))           #3
print(Rectangle.sum(1,2))     #3  
print(type(rec.sum))          #<class 'function'>

5. 导入其他模块的类

方法跟导入其他模块的函数类似,把函数名换成类名就可以了,具体请参考另一篇笔记:Python学习笔记-函数,模块,包-CSDN博客

二、继承 

1. 定义

编写类可以不用从0开始,如果要编写的类跟一个现成的类很类似,可以使用继承

父类:原有的类

子类:新类

继承时,子类会自动获得父类的所有属性和方法,同时可以定义自己的属性和方法

2. 格式

class 子类名(父类名):

        ...

对于任何一个父类而言,名称后面的括号可加可不加,因为所有的类都是object的子类,这也是为什么类会有自带的很多方法和属性,以下三种写法结果是一致的

class Rectangle:
    pass
class Rectangle():
    pass
class Rectangle(object):
    pass

object类的一些方法

class Rectangle:
    pass
print(Rectangle.__name__)      #Rectangle  显示类的名称
print(Rectangle.__bases__)     #(<class 'object'>,)   显示父类的名称

3.继承方式 

1. 完全继承

子类跟父类完全一样,这种情况下,跟父类的实例没有区别,所以完全继承没有必要

class Rectangle:     #父类
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
class Square(Rectangle):     #子类
    pass    #占位符,防止语法错误
sq=Square(2,2)
print(sq.permeter())     #8
print(sq.area())         #4

2. 全部重写

相当于没有继承,所以这种也没必要

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
class Square(Rectangle):
    def __init__(self,side):   
        self.side=side                 
    def permeter(self):
        return (self.side)*4
    def area(self):
        return self.side**2
sq=Square(2)
print(sq.permeter())      #8
print(sq.area())          #4

3. 部分继承

有父类的部分方法或属性,也有自己的方法或属性

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width           
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
class Square(Rectangle):
    def __init__(self,length,width):   
        self.length=length          
        self.width=width
        self.side=length         #子类自己的属性  
    def half_permeter(self):     #子类自己的方法
        return self.length+self.width
sq=Square(2,2)
print(sq.permeter())      #8
print(sq.half_permeter()) #4
print(sq.area())          #4
print(sq.side)            #2

当子类的方法与父类的方法重名,会覆盖父类的方法,即重写父类的方法

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    def permeter(self):
        return (self.length+self.width)*2
    def area(self):
        return self.length*self.width
class Square(Rectangle):   
    def permeter(self):      #与父类方法同名,覆盖父类方法
        return self.length+self.width
sq=Square(2,2)
print(sq.permeter())      #4  调用的是子类中的方法
print(sq.area())          #4

如果既要继承父类的方法或属性,同时又要在方法中增加一些新的代码,或者增加一些新的属性,可以使用super()

class Rectangle:
    def __init__(self,length,width):   
        self.length=length          
        self.width=width            
    @classmethod
    def discription(cls):
        print('两边的长相等,两边的宽相等,长和宽的夹角为90°')
    
class Square(Rectangle):
    def __init__(self,length,width):     #与父类方法同名
        super().__init__(length,width)   #使用super()继承父类的属性
        self.side=length                 #新增自己的属性
    @classmethod
    def discription(cls):          #与父类方法同名
        super().discription()      #使用super()继承父类方法中的代码
        print('长和宽也相等')    #新增自己的代码
    
sq=Square(2,2)
print(sq.side)    #2
sq.discription()
'''
两边的长相等,两边的宽相等,长和宽的夹角为90°
长和宽也相等
'''

4. 私有属性与私有方法

私有属性:不能被子类继承,也不能被自己实例使用的属性,格式是__属性名

私有方法:不能被子类继承,也不能被自己实例使用的方法,格式是__方法名

如果前后都有__: 类中自带的属性或方法

class Class1:
    def __init__(self):      
        __private_attribute='私有属性'
    def __private_method(self):
        print("私有方法")
class Class2(Class1):
    pass
cls1=Class1()
cls2=Class2()
cls1.__private_attribute     #AttributeError: 'Class1' object has no attribute '__private_attribute'
cls1.__private_method()      #AttributeError: 'Class1' object has no attribute '__private_method'
cls2.__private_attribute     #AttributeError: 'Class2' object has no attribute '__private_attribute'
cls1.__private_method()      #AttributeError: 'Class2' object has no attribute '__private_method'

私有属性和私有方法可以在类内部通过self访问

如果想要在外部获取私有属性和私有方法,可以通过在类里面定义非私有方法,在这个方法里调用私有属性或私有方法

class Class1:
    __private_attribute='私有属性'     
    def __private_method(self):
        print("私有方法")
    def use_private(self):
        print(self.__private_attribute)
        self.__private_method()
class Class2(Class1):
    pass
cls1=Class1()
cls2=Class2()
cls1.use_private()    
cls2.use_private()
'''
私有属性
私有方法
私有属性
私有方法
'''

5. 多继承

一个子类继承多个父类,可以继承父类所有能够被继承的属性和方法

class Class1:
    attr1='attr1'
    def method1(self):
        print("Class1_method1")

class Class2:
    attr2='attr2'
    def method2(self):
        print("Class2_method2")
        
class Class3(Class1,Class2):
    pass
cls3=Class3()
print(cls3.attr1)      #attr1
print(cls3.attr2)      #attr2
cls3.method1()         #Class1_method1
cls3.method2()         #Class2_method2

如果不同父类中同名方法,按顺序继承第一个父类的方法,注意:初始化方法只执行第一个父类中的

class Class1:
    attr1='attr1'
    def method(self):
        print("Class1_method1")

class Class2:
    attr2='attr2'
    def method(self):
        print("Class2_method2")
        
class Class3(Class1,Class2):
    pass
cls3=Class3()
cls3.method()        #Class1_method1

6. 多态

一个父类可以有多个子类,这些子类可以重写父类中同一个方法,当使用这个方法时,可以通过一个接口(函数),传入不同子类的实例(对象),得到不同的结果

class Animal:         #父类
    def sound(self):
        pass
class Dog(Animal):    #Animal的子类:Dog
    def sound(self):  #重写sound方法
        print('汪汪汪')       
class Cat(Animal):    #Animal的子类:Cat
    def sound(self):  #重写sound方法
        print('喵喵喵')
def animal_sound(obj):   #定义一个调用不同子类sound方法的函数
    obj.sound()

dog=Dog()   #实例化Dog类
cat=Cat()   #实例化Cat类
animal_sound(dog)    #汪汪汪    调用animal_sound函数,传入dog对象,得到'汪汪汪'
animal_sound(cat)    #喵喵喵    调用animal_sound函数,传入cat对象,得到'喵喵喵'

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值