python 之面向对象

继承粗体文本

标签(空格分隔): 继承



什么是继承:
继承是指类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代买重用问题,继承是一种创建新类的方式,在python中,新建的类是可以继承多个父类,父类又可以成为基类或者超类,新建的类称为派生类或者子类;

  • python中的继承分为:单继承和多继承:


派生

派生:是在继承中,子类有自己的特点,有自己的东西,即使是同一个方法,子类也可以有自己的特色;

继承的实现原理:


继承的原则:
深度优先,广度优先;

子类继承后,对方法重写


如果子类中有的方法,并且重写了,在实例化的时候,还是先用子类的方法,如果子类找不到就用,继承来的;

  • 继承是指的类与类之间的关系;

例如:选课系统:
选课系统里面:有老师,学生,这些可以定义为类;


class Teacher:
    school ='luffycity'
    def __init__(self,name,age,sex,level,salary):
        self.name=name
        self.age=age
        self.sex=sex
        self.level=level
        self.salary=salary

    def teach(self):
        print('%s is teaching '%self.name)
class Student:
    school ='luffycity'
    def __init__(self,name,age,sex,class_time):
        self.name=name
        self.age=age
        self.sex=sex
        self.class_time=class_time
    def learn(self):
        print(%s is learning '%self.name)

上述代码会发现我们这里面有很多的重复代码,会有很多的重复的代码,所以针对类之间的重复的代码,我们可以使用继承,把相同的功能,封装,然后继承,如上述我们可以,定义一个people,然后老师和学生继承就好了;

so:如下代码;

class People:
    school = 'luffycity'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

class Teacher(People):
    def __init__(self,name,age,sex,level,salary):
        super().__init__(name,age,sex)
        self.level=level
        self.salary=salary

    def teach(self):
        print('%s is teaching '%self.name)
class Student:
    school ='luffycity'
    def __init__(self,name,age,sex,class_time):
        super().__init__(name,age,sex)
        self.class_time=class_time
    def learn(self):
        print(%s is learning '%self.name)

teacher1 = Teacher('www',18,'male',10,3000)
student1=Student('zhangsan',28,'feamal','18:34:45')

如上的代码如果:老师有课程,课程周期,课程价格的属性的时候,怎么办呢,代码如下:我们可以给__init__增加属性

class People:
    school = 'luffycity'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

class Teacher(People):
    def __init__(self,name,age,sex,level,salary,course_name,course_price,course_period):
        super().__init__(name,age,sex)
        self.level=level
        self.salary=salary
        self.course_name=course_name
        self.course_price=course_price
        self.course_period=course_period

    def teach(self):
        print('%s is teaching '%self.name)
class Student:
    school ='luffycity'
    def __init__(self,name,age,sex,class_time):
        super().__init__(name,age,sex)
        self.class_time=class_time
    def learn(self):
        print(%s is learning '%self.name)

teacher1 = Teacher('www',18,'male',10,3000,'python',3000,'dkkd')
teacher1 = Teacher('aaa',18,'male',10,3000,'python',3000,'dkkd')

如上述的代码会有很多,关于课程的信息,写了很多重复的代码;

这样我们可以把课程单独的定义一个类:

class People:
    school = 'luffycity'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex

class Teacher(People):
    def __init__(self,name,age,sex,level,salary,):
        super().__init__(name,age,sex)
        self.level=level
        self.salary=salary

    def teach(self):
        print('%s is teaching '%self.name)
class Student:
    school ='luffycity'
    def __init__(self,name,age,sex,class_time):
        super().__init__(name,age,sex)
        self.class_time=class_time
    def learn(self):
        print(%s is learning '%self.name)

class Course:
    def __init__(self,course_name,course_price,course_period)
        self.course_name =course_name
        self.course_price=course_price
        self.course_period =course_period
    def tell_info(self):
        print('课程名称<%s> 课程价格<%s> 可传给你周期<%s>'%(self.course_name,self.course_price,self.course))
teacher1.course.tell_info()

这就是组合

teacher1 =Teacher(‘alex‘,18,‘male‘,10,3000,)
teacher1.course=‘python‘
teacher2.course=‘python‘

```;

多态

多态指的是一类事物有多种形态,比如动物有多种形态:人,狗,猪

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')

研究多态,就是研究同一种事物多种状态,

多态性:指的是可以在不考虑实例的类型的情况下,而直接使用对象,
peo1=People()
dog1=Dog()
pig1=Pig()

peo1.talk()
dog1.talk()
pig1.talk()

以上的多态性,指的是动态的多态性,多态性,不用考虑具体的实例类型,就可以直接用;

def func(animal):
    animal.talk()
func(peo1)
func(pig1)
func(dog1)

二 为什么要用多态性(多态性的好处)

其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?

1.增加了程序的灵活性

  以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

2.增加了程序额可扩展性

 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用  
 
 Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系

#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))

#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

封装

从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子。照这种逻辑看,封装=‘隐藏’,这种理解是相当片面的

如何实现隐藏:

  • 在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class A:
    __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
    def __init__(self):
        self.__X=10 #变形为self._A__X
    def __foo(self): #变形为_A__foo
        print('from A')
    def bar(self):
        self.__foo()
        print('from bar')
        #只有在类内部才可以通过__foo的形式访问到.
#A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

注意:以上的__N是隐藏的属性,注意python里面,以__开头的是隐藏,以__开头,__结尾是python内置的属性和方法,这点大家切记!,不要搞混了;

变形的特点:
1.外部无法直接访问obj.__attrName
2.在类的内部可不可以obj.__AttriName,答案是可以的
3.子类无法覆盖父类__开头的属性;(因为他两个不是一个名字)

封装的意义

1.封装数据属性:明确的区分内外

class People:
    def __init__(self,name,age):
        self.__name =name
        self.__age=age
p=People('egon',18)
P.__name

数据属性分装之后外部是不可以访问的,在内部是可以,但是外部可以间接的访问,我们可以在类的内部开一个接口,通过接口访问,

class People:
    def __init__(self,name,age):
        self.__name =name
        self.__age=age
    def tell_info(self):
        print('Name:<%s> Age:<%s>' %(self.__name , self.__age))

p=People('egon',18)
p.tell_info()

如上述的代码,我们把隐藏的属性放在:tell_info()中,外部的实例化对象,要想访问,就通过实例对象.tell_info()这种方法,这就要通过接口方法来访问的,方便快捷;

2.同样上述的代码,用户不能对name,age直接进行修改了,我们需要开一个接口可以供用户进行修改;

class People:
    def __init__(self,name,age):
        self.__name =name
        self.__age=age
    def tell_info(self):
        print('Name:<%s> Age:<%s>' %(self.__name , self.__age))
    def set_info(self,name,age):
        if not isinstance(name,str):
            print("名字是字符串")
            return
        if not isinstance(age,str):
            print("年龄是字符串")
            return
        self.__name =name
        self.__age=age

p=People('egon',18)
p.tell_info()
P.set_info('EGON',38)#这里我们用的开的接口来修改的
P.set_info('egon','12')
  • 这就是我们数据属性的封装,明确的区分内外,控制外部对影藏属性的操作行为;

封装方法的目的

  • 为了:隔离复杂度;

例如我有一个取款的例子:

class ATM:
    def __card(self):
        print('插卡')
    def __auth(self):
        print('用户认证')
    def __input(self):
        print('输入取款金额')
    def __print——bill(self):
        print('打印账单')
    def __take_money(self):
        print('取款')
    def withdraw(self):
        self.__card()
        self.__auth()
        self.__input()
        self.__print_bill()
        self.__take_money()
    a=ATM()
    a.withdraw()
>* 如上述的代码可以看出,我们外部的实例通过,withdraw可以访问完全;

封装与扩展性:

以前我们说过:面向对象的优点有:可扩展性高,其实封装也是可扩展性的高的一个方面;

class Room:
    def __init__(self,namek,owner,height,weight,length)
        self.name = name
        self.owner=owner
        #如果只想让用户访问:房间的长度和宽度,这里我们就可以把宽度和长度变为隐藏;
        self.__weight=weight
        self.__length=length
r=Room('房间','wo',10,10)

1.如果问题来了,我们要只想访问房间的面积而不是房间的属性呢?

class Room:
    def __init__(self,namek,owner,height,weight,length)
        self.name = name
        self.owner=owner
        #如果只想让用户访问:房间的长度和宽度,这里我们就可以把宽度和长度变为隐藏;
        self.__weight=weight
        self.__length=length

    def tell_area(self):
        return self._weight*self.__length

r=Room('房间','wo',10,10)
print(r.tell_area())

如上述我们使用者,只需要关心的是:r.tell_area()究竟里面的逻辑如何我们不用管,这就为我们提供了方便,类的扩展性;

  • 如果计算房间的体积呢?
class Room:
    def __init__(self,namek,owner,height,weight,length,height)
        self.name = name
        self.owner=owner
        #如果只想让用户访问:房间的长度和宽度,这里我们就可以把宽度和长度变为隐藏;
        self.__weight=weight
        self.__length=length
        self.__height=height

    def tell_area(self):
        return self._weight*self.__length*self.__height

r=Room('房间','wo',10,10)
print(r.tell_area())

同样对于使用者来说,他们不需关心内部的处理逻辑,他们只需要调用就好了;

property的使用:

例如:如下描述:

实现BMI指数程序:

class People:
    def __init__(self,name,weiht,height):
        self.name=name
        self.weight=weigth
        self.height=height
P=People('ll',1.81,75)
bmi=p.weight/(p.height ** 2)
#或者可以写成如下的:
p.bmi =p.weight / (p.height **2)
print(p.bmi)

问题:
如上述的方法bmi,虽然我们实现了,但是我们每次都要定义bmi,是不是很麻烦,而且bmi不是固定的,是随着人的身高体重变化的,而不是一成不变的,那么问题来了,我们怎么实现简单化呢?

  • 这里我们可以把bmi,定义成为方法,然后放置在类里面 ,这样以后的实例只需要调用这个方法就好了,不用每次实例化去计算了;
class People:
    def __init__(self,name,weiht,height):
        self.name=name
        self.weight=weigth
        self.height=height
    def bmi(self):
        return self.weight/(p.height ** 2)

P=People('ll',1.81,75)
print(p.bmi())#bmi后边的()意味着调用函数

如上述的代码,对于用户而言,他把bmi看成指数,加()他们反而不懂,或者说是会误解,对于用户他们就把指数bmi当成了一个名词,而不是()的方法;用户最终想实现的其实就是p.bmi
所以要实现p.bmi我要在class类里面,bmi()上边加个,装饰器:

class People:
    def __init__(self,name,weiht,height):
        self.name=name
        self.weight=weigth
        self.height=height
    @property
    def bmi(self):
        return self.weight/(p.height ** 2)
P=People('ll',1.81,75)
print(p.bmi())#bmi后边的()意味着调用函数

补充一个知识点:property的使用:
比如自己定义一个property的用法;

class People:
    def __init__(sefl,name):
        self.__name=name
p =People('egon') 

如上述我们肯定获取不到名字怎么办呢?

答案:我们肯定要通过接口来获取名字

class People:
    def __init__(sefl,name):
        self.__name=name
    def get_name(self):
        return self.__name

p =People('egon')
print(p.get_name())

然后对于使用者而言:他们就想访问属性而已,不用通过方法,要不然用户会懵逼;

那么问题来了,我们怎么来搞呢?(答案只有加装饰器了,如下图代码)

class People:
    def __init__(sefl,name):
        self.__name=name
    @property
    def get_name(self):
        return self.__name

p =People('egon')
print(p.name)

这里我们通过property来说明,另一个property的用法:

class People:
    def __init__(sefl,name):
        self.__name=name

    @property
    def name(sefl):
        return self.__name
    @name.setter
    def name(self,val):
        if not isinstance(val,str):
            print('名字必须是字符串类型的')
            return
        self.__name =val
    @name.deleter
    def name(self):
        print('不让删除')

p =People('egon')
p.name #这里触发的是第一个,return self.__name
p.name='DDD'#这个是访问行为,触发的是def name(self,val),如上述的修改的逻辑

del p.name#删除属性

如上述所述:我们之要掌握,不需要掌握太多;

@property
    def name(sefl):
        return self.__name
  • 总结,如果说一些东西不能像属性一样,需要定一个方法来实现,但是用户又想把这些当做属性来访问,而不是方法,()之类的东西,所以要这里我们需要使用property装饰之类东西来满足需要;
    这里上述的
@property
    def name(sefl):
        return self.__name
  • 就是一些东西无法通过属性直接访问的,所以就定义一个方法,然后呢,我们用户又不懂什么方法不方法的,用户要按照属性一个的访问,所以这时候就用到了装饰器;

原文地址:https://www.cnblogs.com/surewing/p/9733732.html

时间: 2024-07-30 21:10:25

python 之面向对象的相关文章

My way to Python - Day05 - 面向对象-思维导图

My way to Python - Day05 - 面向对象 思维导图

Python -面向对象(一 基本概念)

一 Python简单介绍 Python是一个可移植的面向对象的脚本语言. Python尽管是一个脚本语言,但也是一个全然面向对象的语言. 由于它设计之初把易用性做为很重要的一个考量标准,所以用起来很简洁,优美(语法很灵活).所以使用Python能够高速地编写出可执行代码.与C/C++相比.Python程序的执行速度比較慢,一门语言既然能够生存下来.就有它自己的原因,Python语言也一样. 当今的计算机处理速度已经很快.对某些任务来说.执行速度并非首要考虑的因素.比方说为了实现数据库訪问的自己主

Python的面向对象3

接下来,我们接着讲Python的面向对象,在上一次的博客中,我们详细介绍了类与对象的属性,今天,我们来详细介绍一下面向对象中的方法! 1.定义实例方法 一个实例的私有属性就是以__开头的属性,无法被外部访问,但是,从类的内部是可以访问的,除了可以定义实例的属性,还可以定义实例的方法. 其实,实例的方法就是在类中定义函数,它的第一个参数永远是self,指向调用该方法的实例本身,其他参数和普通参数一致. get_name()就是一个实例方法,它的第一个参数是self,这个参数不需要显示传入 调用实例

个人理解的python的面向对象

在学习到python的面向对象的时候,发现python的类的的属性是有区分类的属性及对象的属性的,代码示例如下: class test: a = 'test' def test1(self,a): self.a = a def show(self): print(test.a) def show1(self): test.a = 'for test' print(test.a) t = test() t.a = 'zjc' t.test1('zjc')print(t.a) t.show() t.

六、定制数据对象(Python的面向对象) ----- 打包代码与数据

创建Python字典 python字典即为键值对,相当于Java中的map,其创建的两种形式: a = {} # 普通方式 b = dict() # 使用工厂函数 字典的赋值与访问 #创建字典 >>> cleese['Name'] = 'John Cleese' >>> cleese['Occupations'] = ['actor','comedian','writer','film producer'] >>> palin = {'Name':'M

Python 3面向对象编程

这篇是计算机类的优质预售推荐>>>><Python 3面向对象编程> 编辑推荐 本书不是Python 的入门书籍,适合具有Python 基础经验的开发人员阅读.如果你拥有其他面向对象语言的经验,你会更容易理解本书的内容. 内容简介 Python 是一种面向对象的解释型语言,面向对象是其非常重要的特性.本书通过Python 的数据结构.语法.设计模式,从简单到复杂,从初级到高级,一步步通过例子来展示了Python 中面向对象的概念和原则.本书不是Python 的入门书籍,

Python-面向对象(三 元编程)

译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得不太明白,希望大家可以给出一些实际的例子和代码片段以帮助理解,以及在什么情况下需要进行元编程.于是e-satis同学给出了神一般的回复,该回复获得了985点的赞同点数,更有人评论说这段回复应该加入到Python的官方文档中去.而e-satis同学本人在Stack Overflow中的声望积分也高达6

what&#39;s the python之面向对象

编程分为面向过程和面向对象,首先我们要了解什么是面向对象. 面向对象 面向过程就是我们之前学的内容,主要是函数式,其核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可. 缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身. 应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等. 面向对象的

what&#39; the python之面向对象(进阶)

面向对象的知识点补充(进阶版) classmethod和staticmethod:这两个函数的用途就是可以不用实例化对象就可以调用方法 class Classmethod_Demo(): role = 'dog' @classmethod def func(cls): print(cls.role) Classmethod_Demo.func() class Staticmethod_Demo(): role = 'dog' @staticmethod def func(): print("当普

Python之面向对象进阶

Python之面向对象进阶 进阶有:Python 类的成员.成员修饰符.类的特殊成员. 一.类的成员 类的成员可以分为三大类:字段.方法和属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段.而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份. 1.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 1 class Province: