Python面向对象编程学习笔记

本文介绍了Python面向对象编程的基础概念,包括封装性、继承性和多态性。讲解了类与对象、实例变量与类变量的区别,构造方法、实例方法、类方法和静态方法的用法,以及如何实现封装、继承和多态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

接上篇Python函数及函数式编程,打卡~
简述面向对象编程思想:按照真实客观世界客观事物的自然规律进行分析,客观世界中存在什么样的实例,构建的软件系统就会存在什么样的实体。


注意:类名采用大驼峰命名法(英文单词首字母大写),例如:ClassRroom。

1.1 面向对象的三个基本特征

1.1.1 封装性

封装能够使外部访问者不能随意存取对象的内部数据,隐藏了对象内部的细节,只保留有限的对外接口。外部访问者不用关心对象的内部细节,操作对象变得简单。

1.1.2 继承性

在面向对象中分为一般类和特殊类。特殊类拥有一般类的全部数据和操作,称为特殊类继承一般类。一般类称为“父类”或“超类”,特殊类称为“子类”或“派生类”。

1.1.3 多态性

多态性是指在父类中成员被子类继承之后,可以具有不同的状态或表现行为。

2.1 类和对象

Python中的数据类型都是类,类是组成Python程序的基本元素,它封装了一个类对象的数据和操作。

2.1.1 定义类

Python语言中一个类的定义包括类定义和类体。格式如下:

class Animal(object):
	#类体
	pass

上述代码声明了动物类,它继承了object类,object是所有类的根类,在Python中任何一个动物类都直接或间接继承object,所以(object)部分代码可以省略。

注意:代码的pass语句什么操作都不执行,用来维持程序结构的完整。有些不想编写的代码,又不想有语法错误,可以使用pass语句占位。

2.1.2 创建和使用对象

“对象”也可称为“实例”。一个对象的生命周期包括三个阶段:创建、使用和销毁。销毁对象时Python的垃圾回收机制释放不再使用的对象的内存,不需要程序员负责。

创建对象的语法很简单,只需在类后面加上一对小括号,表示调用类的构造方法。例如:

animal = Animal()

这样就创建好了,通过animal变量可以使用刚刚创建的动物对象。

2.1.3 实例变量

在类体中可以包含类的成员,类方法如下图所示,其中包括成员变量、成员方法和属性,成员变量又分为实例变量和类变量,成员方法又分为实例方法、类方法和静态方法。

在这里插入图片描述

“实例变量”就是某个实例(或对象)个体特有的“数据”,例如你家狗狗的名字、年龄和性别与邻居家的狗狗的名字、年龄和性别是不一样的。
举个例子:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex,weight):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量

dog1 = Animal(2,1,5)

print('年龄: {0}'.format(dog1.age))
print('性别: {0}'.format(dog1.sex))
print('体重: {0}'.format(dog1.weight))

结果为:

年龄: 2
性别: 1
体重: 5

构造方法是用来创建和初始化实例变量的,有关构造方法下文中会提及。构造方法中的self指向当前对象实例的应用。其中self.age表示对象的age实例变量。访问age实例变量需要通过“实例名.变量名”的形式访问。

2.1.4 类变量

“类变量”是所有实例变量共有的变量。例如有一个Account(银行账户)类,它有三个成员变量 : amount(账户金额)、interest_rate(利率)和owner(账户名)。在这三个成员变量中,amount和owner会因人而异,但是所有账户的interest_rate都是相同的。amount和owner成员变量与账户个体实例有关,称为“实体变量”,interest_rate成员变量与个体实例无关,或者说是个体实例共有的,这个变量被称为“类变量”。
例如:

class Account:
    '''定义银行账户类'''

    interest_rate = 0.0668

    def __init__(self,owner,amount):
        self.owner = owner    #定义实例变量账户名
        self.amount = amount  #定义实例变量账户金额

account1 = Account('Tony',18000.0)
account2 = Account('Amy',24000.0)

print('账户{0}的金额为{1},年利率为{2}'.format(account1.owner,account1.amount,account1.interest_rate))
print('账户{0}的金额为{1},年利率为{2}'.format(account2.owner,account2.amount,account2.interest_rate))

运行结果如下:

账户Tony的金额为18000.0,年利率为0.0668
账户Amy的金额为24000.0,年利率为0.0668

可以看到类变量是所有实例变量所共有的。

注意:不要通过实例存取类变量数据。当通过实例读取变量时,Python解释器会在实例中找这个变量,如果没有找到,再去类中找;当通过实例为变量赋值时,无论类中有没有该同名变量,Python解释器都会创建一个同名实例变量。

2.1.5 构造方法

__init__()

该方法用来创建和初始化实例变量,这种方法是“构造方法”,也属于魔法方法。定义时,它的第一个参数应该是self,其后的参数才是用来初始化实例变量的。调用构造方法时不需要传入self。
例如:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量

dog1 = Animal(2,1,5)
dog2 = Animal(1,weight = 10)
dog3 = Animal(1,sex = 1)

print('dog1年龄: {0},性别:{1},体重:{2}'.format(dog1.age,dog1.sex,dog1.weight))
print('dog2年龄: {0},体重:{1}'.format(dog2.age,dog2.weight))
print('dog3年龄: {0},性别:{1}'.format(dog3.age,dog3.sex))
dog1年龄: 2,性别:1,体重:5
dog2年龄: 1,体重:10
dog3年龄: 1,性别:1

不需要传入self,只需要提供后面三个实际参数。

2.1.6 实例方法

实例方法和实例对象都是某个实例所特有的。
方法是在类中定义的函数。而定义实例方法时它的第一个参数也应该是self,这个过程是将当前实例与该方法绑定起来,使之成为实例方法。
例如:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量

    def eat(self):
        self.weight += 0.05
        print('eat...')

    def run(self):
        self.weight -= 0.01
        print('run...')

a1 = Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.eat()
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.run()
print('a1体重:{0:0.2f}'.format(a1.weight))
a1体重:10.00
eat...
a1体重:10.05
run...
a1体重:10.04

2.1.7 类方法

“类方法”与“类变量”类似,属于类而不属于个体实例方法,类方法不需要与实力绑定,但需要与类绑定,定义是它的第一个参数不是self,而是类的type实例。
例如:

class Account:
    '''定义银行账户类'''

    interest_rate = 0.0668

    def __init__(self,owner,amount):
        self.owner = owner    #定义实例变量账户名
        self.amount = amount  #定义实例变量账户金额

    @classmethod
    def interest_by(cls,amt):
        return cls.interest_rate * amt

interest = Account.interest_by(12000.0)

print('计算利息:{0:0.4f}'.format(interest))

执行结果:

计算利息:801.6000

定义类方法有两个关键:第一,方法的第一个参数cls是type类型的一个实例;第二,方法使用装饰器@classmethod声明该方法是类方法。

注意:类方法可以访问类变量和其他类方法,但不能访问其他实例方法和实例变量

2.1.8 静态方法

如果定义的方法既不想与实例绑定,也不想与类绑定,只是想把类作为它的命名空间,那么可以用静态发方法。
例如:

class Account:
    '''定义银行账户类'''

    interest_rate = 0.0668

    def __init__(self,owner,amount):
        self.owner = owner    #定义实例变量账户名
        self.amount = amount  #定义实例变量账户金额

    @classmethod
    def interest_by(cls,amt):
        return cls.interest_rate * amt

    @staticmethod
    def interest_with(amt):
        return Account.interest_by(amt)

interest1 = Account.interest_by(12000.0)
interest2 = Account.interest_with(12000.0)

print('计算利息:{0:0.4f}'.format(interest1))
print('计算利息:{0:0.4f}'.format(interest2))

执行结果为:

计算利息:801.6000
计算利息:801.6000

使用了@staticmethod装饰器,声明该方法是静态方法,方法参数不需要指定self和csl。

3.1封装性

3.1.1 私有变量

默认情况下Python中的变量是共有的,可以在类的外部访问它们。如果想让他们成为私有变量,可以在变量前加上双下划线"__"。
例如:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.__weight = weight  #定义体重实例变量

    def eat(self):
        self.__weight += 0.05
        print('eat...')

    def run(self):
        self.__weight -= 0.01
        print('run...')

a1 = Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.eat()
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.run()
print('a1体重:{0:0.2f}'.format(a1.weight))

运行结果如下:

Traceback (most recent call last):
  File "C:/Users/SZN/Desktop/test.py", line 18, in <module>
    print('a1体重:{0:0.2f}'.format(a1.weight))
AttributeError: 'Animal' object has no attribute 'weight'

__weight变量在类内部访问没有问题,但是如果在外部访问则会发生错误。

注意:如果想在外部访问私有变量也是可以的,只需要将访问的格式改为“_类名___变量”。所以将上述代码a1.weight改为a1_Animal__weight就可以访问了。但是及不推荐这样做,会破坏封装性

3.1.2 私有方法

原理同私有变量。
举个例子:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.__weight = weight  #定义体重实例变量

    def eat(self):
        self.__weight += 0.05
        print('eat...')

    def __run(self):
        self.__weight -= 0.01
        print('run...')

a1 = Animal(2,0,10.0)
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.eat()
print('a1体重:{0:0.2f}'.format(a1.weight))
a1.run()
print('a1体重:{0:0.2f}'.format(a1.weight))


运行结果如下:

eat...
Traceback (most recent call last):
  File "C:/Users/SZN/Desktop/test.py", line 21, in <module>
    a1.run()
AttributeError: 'Animal' object has no attribute 'run'

3.1.3 定义属性

封装通常是对成员变量的封装。在严格意义上的面对对象设计中,一个类是不应该有共有实例成员变量的,这些实例成员变量应该被设计成为私有的,然后通过共有的setter和getter访问器访问。
但是访问器形式封装在编写代码时比较麻烦。为了解决这个问题,Python中提供了属性,定义属性可以使用@property和@属性名.setter装饰器。@property用来修饰getter访问器,@属性名.setter用来修饰setter访问器。
例如:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.__weight = weight  #定义体重实例变量

    @property
    def weight(self):
        return self.__weight

    @weight.setter
    def weight(self,weight):
        self.__weight = weight

运行结果:

a1体重:10.00
a1体重:123.45

4.1 继承性

4.1.1 继承性的概念

上栗子:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量

class Dog(Animal):
    '''继承动物类'''

    def __init__(self,name,age,sex = 1,weight = 0.0):
        super().__init__(age,sex,weight)
        self.name = name
dog1 = Dog('Lucky',2,1,5)
dog2 = Dog('Bob',1,weight = 10)
dog3 = Dog('Lucy',1,sex = 1)

print('{0}年龄: {1},性别:{2},体重:{3}'.format(dog1.name,dog1.age,dog1.sex,dog1.weight))
print('{0}年龄: {1},体重:{2}'.format(dog2.name,dog2.age,dog2.weight))
print('{0}年龄: {1},性别:{2}'.format(dog3.name,dog3.age,dog3.sex))

运行结果:

Lucky年龄: 2,性别:1,体重:5
Bob年龄: 1,体重:10
Lucy年龄: 1,性别:1

Dog类继承Animal类,其中小括号中的是父类,如果没有指明父类(一对空的小括号或者省略小括号),则默认父类为object,object类是Python的根类。子类中定义构造方法时首先要调用父类的构造方法,初始化父类变量。super().__init__(age,sex,weight)就是调用父类的构造方法,super()函数时返回父类的引用,通过它可以调用父类中的实例变量和方法。

注意:子类继承父类时只是继承父类中公有的成员变量和方法,不能继承私有的成员变量和方法。

4.1.2 重写方法

如果子类方法名与父类方法名相同,而参数列表也相同,只是方法体不同,那么子类重写了父类的方法。
例如:

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量
	def eat(self):
        self.weight += 0.05
        print('Animal eat...')
        
class Dog(Animal):
    '''继承动物类'''

    def __init__(self,name,age,sex = 1,weight = 0.0):
        super().__init__(age,sex,weight)
        self.name = name

    def eat(self):
        self.weight += 0.03
        print('Dog eat...')
        
dog1 = Dog('Lucky',2,1,5)
dog1.eat()

运行结果:

Dog eat...

可见子类重写了父类的方法,通过子类实例调用eat()方法时,会调用子类重写的eat()。

4.1.3 多继承性

就是一个子类可以有多个父类。当子类实例调用一个方法时,先从子类中查找,如果没有找到则查找父类。父类的查找顺序是按照子类声明的父类列表从左往右查找,如果没有找到再找父类的父类,依次查找下去。
例如:

class ParentClass1:
    def run(self):
        print('ParentClass1 run...')

class ParentClass2:
    def run(self):
        print('ParentClass2 run...')
        
class SubClass1(ParentClass2,ParentClass1):
    pass

sub1 = SubClass1()
sub1.run()
ParentClass2 run...

5.1 多态性

5.1.1 多态概念

发生多态要有两个前提条件:
继承——多态发生一定是再子类和父类之间。
重写——子类重写父类的方法。

5.1.2 类型检查

运行期类型检查使用isinstance(object,classinfo)函数,它可以检查object实例是否由classinfo类或classinfo子类所创建的实例。

class Animal(object):
    '''定义动物类'''

    def __init__(self,age,sex = 1,weight =0.0):
        self.age = age    #定义年龄实例变量
        self.sex = sex    #定义性别实例变量
        self.weight = weight  #定义体重实例变量
	    def eat(self):
        self.weight += 0.05
        print('Animal eat...')

    def run(self):
        self.weight -= 0.01
        print('Animal run...')

class Dog(Animal):
    '''继承动物类'''

    def __init__(self,name,age,sex = 1,weight = 0.0):
        super().__init__(age,sex,weight)
        self.name = name

    def eat(self):
        self.weight += 0.03
        print('Dog eat...')

    def run(self):
        self.weight -= 0.02
        print('Dog run...')


class Cat(Animal):
    '''继承动物类'''

    def __init__(self,name,age,sex = 1,weight = 0.0):
        super().__init__(age,sex,weight)
        self.name = name

    def eat(self):
        self.weight += 0.03
        print('Cat eat...')

    def run(self):
        self.weight -= 0.02
        print('Cat run...')
        
a1 = Animal(2,0,10.0)
a2 = Dog(2,0,10.0)
a3 = Cat(2,0,10.0)

print(isinstance(a1,Dog))  #没有发生多态
print(isinstance(a2,Dog))  #发生多态
print(isinstance(a3,Dog))  #没有发生多态
print(isinstance(a2,Animal))  #发生多态

运行结果为:

False
True
False
True

今天就学到这里了


总结

以上就是今天学习的内容,自己在学习的时候还是有点懵的,还需要多加以运用。上文如有错误,希望各位大佬值正。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值