【Python3_基础系列_016】Python3-面向对象

本文详细介绍了Python3的面向对象编程概念,包括类的定义、属性、方法、私有属性,以及类的继承与多态特性。通过实例解析类属性、实例属性、私有属性的定义与访问,探讨类的继承规则和多态应用。

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

一、Python3的面向对象

高级编程语言都有面向对象的概念,简单来说就是类的抽象。Python中的类与面向对象与JAVA语言的语言略有不同。类是面向对象的基础也是最重要的部分。下面简单的介绍下什么是类:

类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

Python中的所有东西都是类(都是对象,对象是类的实例),即使是int,str,他们的定义也都是类(参考前面的文章,基础数据类型)。

下面介绍类的构成:

>属性:类里面的特性 不加()
>方法:类里面的函数 要加()

我们从另一个角度去理解类:类也是一种数据类型,和int,char,float等基本数据类型一样,只不过它是一种复杂的数据类型。因为类的本质是数据类型,而不是具体的数据,所以无法直接存储于内存中,需要实例化后才会进入内存,并可以操作。

二、类的定义

Python3中定义类的语法很简单,类似于函数的定义,语法如下:

class ClassName(object):
      Statement
1.class定义类的关键字 2.ClassName类名,类名的每个单词的首字母大写(驼峰规则)。 3.object是父类名,object是一切类的基类。在python3中如果继承类是基类可以省略不写。

例子1:定义1个动物类,包含属性和方法

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self.__color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

>定义类时,这种方法可以使类对象实例按某种特定的模式生产出来。
>后面的参数中第一个参数我们约定俗成的为self参数名,self代表的是在类实例化后这个实例对象本身。
>__init__初始化函数除了有self这个参数表示实例对象本身之外,其他的参数的定义也遵循函数的必备参数和默认参数一样的原则,
>必备参数就是在实例化是一定要传入的参数,
>默认参数就是在定义时可以给这个参数一个初始值。

 三、类的实例化

类的实例化很简单,就是按照类的初始化函数(__init__())定义一个具体的类对象。

例子1:

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self.__color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()
        
minions = Animal('minions','banana')  #minions 小黄人 实例化一个类对象
minions.play()

输出:
minionsbanana:lalala

例子2:

很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为 __init__() 的特殊方法(构造方法),像下面这样:
def __init__(self): self.data = []
类定义了 __init__() 方法的话,类的实例化操作会自动调用 __init__() 方法。所以在下例中,可以这样创建一个新的实例:
x = MyClass()
当然, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:

>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)

四、属性-类属性

我们知道:类=属性+方法。但是属性还可以继续划分:属性=类属性+实例属性。我们先来介绍类属性,类属性简单来说就是类里面直接定义的属性,不是在方法里面的属性。

类属性有如下特点:

>.类属性是可以直接通过“类名.属性名”来访问和修改。(Animal.eye=2,dog.eye=2)
>.类属性是这个类的所有实例对象所共有的属性,
>任意一个实例对象都可以访问并修改这个属性(私有隐藏除外)。
>对类属性的修改,遵循基本数据类型的特性:列表可以直接修改,字符串不可以,
>所以当类属性是一个列表时,可以通过任意一个实例对象对其进行修改。
>但字符串类型的类属性不能通过实例对象对其进行修改。
>当实例对不可变对象进行修改之后,会查找实例的类属性,不会查找类的属性,同时类的属性不会变。
>.实例的类属性都是指向类的,但是如果实例改变类属性,就会建一个对象,不会改变类的属性
>.类本身属性变量啦,实例是指向类的话,也会改变,实例如果指向自己,就不会受影响

 

仍然以之前的Animal类为例:

class Animal():
    'this is a class'
    eye=2  ## 类属性

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self.__color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

在这个类的定义里面可以看到,直接定义了一个 eye=2的变量,这个变量就是类的属性,并且是类属性。意思就是说这个属性,属于这个类,不仅仅属于具体的实例,类和实例可以改变类属性。

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self._color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

minions = Animal('minions','banana')  #minions 小黄人
dog = Animal("wangwang",'gutou')

print(minions.eye)
print(dog.eye)
print(Animal.eye)

输出:
2
2
2

》多个实例可以访问该类的类属性

》实例可以修改类属性

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self._color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

minions = Animal('minions','banana')  #minions 小黄人
dog = Animal("wangwang",'gutou')

minions.eye=3 ##实例中改变类属性
dog.eye=4  ##实例中改变类属性

print(minions.eye)
print(dog.eye)
print(Animal.eye)

输出:
3
4
2

#实例虽然可以改变类属性,但是仅仅只改变当前实例的类属性,并不会改变类的属性,所以Animai.eye还是=2.
#可以通过类.类属性的方法修改类属性,例如:
Animal.eye=5,那么print(Animal.eye)=5

》如果通过类修改类属性,那么实例的类属性都会改变

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self._color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

minions = Animal('minions','banana')  #minions 小黄人
dog = Animal("wangwang",'gutou')

Animal.eye=5

print(minions.eye)
print(dog.eye)
print(Animal.eye)

输出:
5
5
5

五、属性-实例属性

在类的定义中,如果变量前面是self.attribute。那么这种属性就是实例属性,类无法直接访问实例属性。下面的例子中的红色部分的属性就是实例属性。

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self.__color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

实例1:访问实例属性:实例.属性名

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self._color = color
        self.__leg = leg

    def play(self):
        print('%s:lalala' % (self.name + self.food))

    def get_name(self):
        self.play()

minions = Animal('minions','banana')  #minions 小黄人
dog = Animal("wangwang",'gutou')

print(minions.name)
print(dog.food)
print(Animal.name)


输出:
minios
gutou

 Traceback (most recent call last):
 File "D:/WorkSpace/Python3/cekai/class1.py", line 22, in <module>
 print(Animal.name)
 AttributeError: type object 'Animal' has no attribute 'name'

可以看出来,实例属性只能通过实例.属性名的方式访问,但是类无法访问实例属性('Animal' has no attribute 'name')

六、类的私有属性,方法

java的变量权限有public,protected,private之分,python中对类属性(变量)的权限划分只有普通的类属性和私有属性。但是私有属性不是通过关键字来定义的,而是通过特殊的变量名来确定。

>在Python中,通过单下划线”_”来实现模块级别的私有化,一般约定以单下划线”_”开头的变量、函数为模块私有的,
>也就是说”from moduleName import *”将不会引入以单下划线”_”开头的变量、函数
>对于Python中的类属性,可以通过双下划线”__”来实现一定程度的私有化,因为双下划线开头的属性在运行时会被”混淆”(mangling)。

实例:类的私有属性,方法的定义和获取

class Animal():
    'this is a class'
    eye=2

    def __init__(self,name,food,color="yellow",leg=2):
        self.food = food
        self.name = name
        self._color = color ##单下划线类私有属性:self._attr
        self.__leg = leg ##双下划线类私有属性:self.__attr

    def _play(self):##单下划线类私有方法:self._fun()
        print('%s:lalala' % (self.name + self.food))

    def __get_name(self): ##双下划线类私有方法:self.__fun()
        self._play() ##单下划线私有方法在类内部直接 self._fun()

    def run(self):
        self.__get_name() ##双下划线私有方法在类内部直接 self.__fun()

minions = Animal('minions','banana')  #minions 小黄人
dog = Animal("wangwang",'gutou')

print(dog._color) ##访问单下划线私有属性:实例._attr
print(dog._Animal__leg) ##访问双下划线私有属性:实例._Class__attr
#print(dog.__leg) ##无法通过 ‘实例.__attr’直接访问双下划线私有属性

dog.run()
dog._play()   ##访问单下划线私有方法:实例._fun()
dog._Animal__get_name()##访问单下划线私有方法:实例._Class__fun()
#dog.__get_name() ##无法通过 ‘实例.__fun()’直接访问双下划线私有方法

输出:
yellow
2
wangwanggutou:lalala
wangwanggutou:lalala
wangwanggutou:lalala

总结如下:

 定义访问
私有属性(_attr):单下划线self._attr实例._attr
私有属性(_ _attr):双下划线self._ _attr实例._Class_ _attr
私有方法(_fun()):单下划线def _fun(self):实例._fun()
私有方法(_ _fun()):双下划线def _ _fun(self):实例._Class_ _fun()

 

 

 

 

 

说明:

>_”和” _ _”的使用 更多的是一种规范/约定,不没有真正达到限制的目的:
>_”:以单下划线开头只能允许其本身与子类进行访问
> _ _”:双下划线的表示的是私有类型的变量。这类属性在运行时属性名会加上单下划线和类名。

七、类的继承与多态

上面介绍了类的定义和类属性,方法。面向对象的3大特征:封装,继承,多态。其中封装就是体现在了类的属性,方法和私有属性,方法的定义与访问上。下面我们介绍一下面向对象的其他特性:继承和多态

1.继承

Python3在定义类时,可以从已有的类继承,被继承的类称为基类(父类),新定义的类称为派生类(子类)。object类是所有类的基类,如果定义类没有指定父类,那么默认就是object类。

继承具有如下特性:

特性1:如果子类中没有定义初始化函数,那么将继承父类的初始化函数,子类在实例化的时候需要按照父类的初始化函数定义进行传参数。

class Animal:  #父类
    eye = 2
    leg = []
    """ animal  class"""
    def __init__(self,name,food,color = 'yellow'):
        self.name = name
        self.food = food

    def play(self):
        print('Animals are strong')


class People(Animal):
    pass

minions = Animal('minions','banana')
dog = Animal('dog','bone')

people = People()
#
输出:
Traceback (most recent call last):
  File "D:/WorkSpace/Python3/cekai/class2.py", line 20, in <module>
    people = People()
TypeError: __init__() missing 2 required positional arguments: 'name' and 'food'

People类没有定义__init__初始化函数,但是父类Animal类定义了初始化函数。那么People类在初始化的时候,会向上搜索Animal的初始化函数,如果找到单独定义的初始化函数,那么People类在定义的时候必须使用父类的初始化函数进行初始化。

所以上面的People类实例化的方法如下:people = People('man','food') #正确的实例化

 

特性2:如果子类中定义了自己的初始化函数,那么子类在实例化的时候按照自己的实例化函数进行传参。

class Animal:  #父类
    eye = 2
    leg = []
    """ animal  class"""
    def __init__(self,name,food,color = 'yellow'):
        self.name = name
        self.food = food

    def play(self):
        print('Animals are strong')


class People(Animal):
    def __init__(self, weight):
        self.weight = weight


people = People(60) ##子类定义了__init__方法,子类实例化的时候必须使用自己的初始化函数实例化

特性3--重要:子类自己定义了初始化函数,同时也想访问父类的初始化函数,可以通过如下几种方式进行父类的初始化。

class Animal:  #父类
    eye = 2
    leg = []
    """ animal  class"""
    def __init__(self,name,food,color = 'yellow'):
        self.name = name
        self.food = food

    def play(self):
        print('Animals are strong')


class People(Animal):
    def __init__(self, weight):
        super().__init__("FatherName","FatherFood") ##方式1:推荐。可以屏蔽父类的细节,即使父类改变,代码无需改变。
        Animal.__init__(self,"FatherName","FatherFood")
        super(People, self).__init__("FatherName","FatherFood")
        self.weight = weight


minions = Animal('minions','banana')
dog = Animal('dog','bone')

people = People(60)

类继承的特性:

  .在类中找不到调用的属性时就搜索基类,如果基类是从别的类派生而来,这个规则会递归的应用上去。反过来不行。

  .如果派生类中的属性与基类属性重名,那么派生类的属性会覆盖掉基类的属性。包括初始化函数。

  .派生类在初始化函数中需要继承和修改初始化过程,使用’类名+__init__(arg)’来实现继承和私有特性,也可以使用super()函数。

  .issubclass(类名1,类名2): 判断类1是否继承了类2

  .作用:面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。 继承完全可以理解成类之间的类型和子类型关系。子类在重写父类方法之后,如果要继承父类方法中的功能,要先调用父类的方法  class.fun(self)

 

2.多态

如果子类中重写了父类的方法,同一个函数有了不同的用法,就是多态。

class Animal:  #父类
    eye = 2
    leg = []
    """ animal  class"""
    def __init__(self,name,food,color = 'yellow'):
        self.name = name
        self.food = food

    def play(self):
        print('Animals are strong')


class People(Animal):
    def __init__(self, weight):
        super().__init__("FatherName","FatherFood") ##方式1:推荐。可以屏蔽父类的细节,即使父类改变,代码无需改变。
        Animal.__init__(self,"FatherName","FatherFood")
        super(People, self).__init__("FatherName","FatherFood")
        self.weight = weight

    def play(self):
        print("This is People Play")


minions = Animal('minions','banana')
dog = Animal('dog','bone')

people = People(60)
people.play()

可以看出子类重写父类的方法后在,子类的方法按照自己的定义执行。

八、类的多继承

Python和Java的一个很大的区别就是Python支持多继承,而Java是单继承。

例子1:类的多继承--当继承的多个类有同种方法的时候,只会继承前面一个的方法-


class Animal:  #父类
eye = 2
leg = []
""" animal class"""
def __init__(self,name,food,color = 'yellow'):
self.name = name
self.food = food

def play(self):
print('Animals are strong')


class People(Animal):
def __init__(self,weight):
super().__init__(self,'xiaoming','apple')
self.weight = weight

def play(self):
print('People is playing')


class Asian(Animal):
def play(self):
print('Asian is playing')


class Chinese(People,Asian):
def play(self):
super().play()

xmb = Chinese (89)
xmb.play()
输出:People is saying

多继承的特性:

特性1:当继承的类有同种方法的时候,只会继承前面一个的方法---实例1

特性2:多继承时,默认的初始化函数是继承的第一个父类,如果第一个父类没有定义自己的初始化函数,那么将按照第二个父类的初始化函数。如果两个父类都没初始化函数,会调用父类的父类的初始化函数。

特性3:super 会对继承树做排序,保证每个父类只会被调用一次,在多继承里面:子类永远在父类前面,如果有多个父类,会根据它们在列表中的顺序被检查,前面的父类的方法优先于后面父类的方法,super保证所有的类只被调用一次,不会被重复调用

下面这个例子要注意:

class Animal:  #父类
    eye = 2
    leg = []
    """ animal  class"""
    def __init__(self,name,food,color = 'yellow'):
        self.name = name
        self.food = food

    def play(self):
        print('Animals are strong')


class People(Animal):
       def __init__(self,weight):
              super().__init__(self,'xiaoming','apple')
              self.weight = weight

       def play(self):
              super(People,self).__init__('xiaoming','apple')
              super(People ,self).play()
              print('People is playing')


class Asian(Animal):
       def play(self):
              super().play()
              print('Asian is playing')


class Chinese(People,Asian):
       def play(self):
            super().play()
            print('Chinese is No.1')

xmb = Chinese (89)
xmb.play()

输出:
Animals are strong
Asian is playing
People is playing
Chinese is No.1

Animal--People--Chinese

Animal--Asian---Chinese

对于Chinese.play(),由于Chinese继承了People,Asian,并且都继承了Animal.并且People和Asian的play方法中都调用了super.play()。按理说如果层级输出的时候Animal.play方法应该被对多次输出,但是super做了特性3处理,只输出一次。因此在Chinses的super.play()会首先输出所有父类的方法,并且父类中的super方法不会被重复输出。

转载于:https://www.cnblogs.com/forfreewill/articles/9318946.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值