Python面向对象编程

一、面向过程与面向对象的对比

1.1 面向过程

面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西.

优点:极大的降低了程序的复杂度.
缺点:一套流水线或者流程就是用来解决一个问题.
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等.

1.2 面向对象

面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。对象是特征和技能的结合,其中特征和技能分别对应对象的数据属性和方法属性。

优点:解决了程序的扩展性,对某一个对象单独修改,会立刻反映到整个体系中.
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间
     的交互解决问题,即便是上帝也无法预测最终结果.
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手
         的好地方。 

二、类和对象

把一类事物的静态属性和动态可以执行的操作组合在一起所得到的这个概念就是类;类的一个个体就是对象,对象是具体的,实实在在的事物;对象是特征与技能的结合体,其中特征和技能分别对应对象的数据属性和方法属性

1. 对象(实例)本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法
   唯一绑定一个对象,同一个类的方法绑定到不同的对象上,属于不同的方法,内存地址都不会一样。
2. 在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间
3. 创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性:而类中有两种属性:数据属性和函数
   属性,其中类的数据属性是共享给所有对象的,而类的函数属性是绑定到所有对象的。
4. 创建一个对象(实例)就会创建一个对象(实例)的名称空间,存放对象(实例)的名字,称为对象(实例)的属性
5. 在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类…最后都找不到就抛出异常。
6. 类的相关方法:
         类的相关方法(定义一个类,也会产生自己的名称空间) 
         类名.__name__   # 类的名字(字符串)
         类名.__doc__    # 类的文档字符串 
         类名.__base__   # 类的第一个父类(在讲继承时会讲) 
         类名.__bases__  # 类所有父类构成的元组(在讲继承时会讲) 
         类名.__dict__   # 类的字典属性、名称空间 
         类名.__module__ # 类定义所在的模块 
         类名.__class__  # 实例对应的类(仅新式类中)

7.拓展
    - 创建出类会产生名称空间,实例化对象也会产生名称空间。
    - 用户自己定义的一个类,实际上就是定义了一个类型,类型与类是统一的。
    - 通过类来访问,访问的是函数,通过对象来访问,访问的是方法,在类内部定义的方式实际上是绑定到对象的身上来用的。
    - 总结:
         - 类的数据属性是大家共有的,而且大家的内部地址是一样的,用的就是一个。
         - 类的函数属性是绑定到大家身上的,内部地址不一样,绑定方法指的是绑定到对象身上。
         - 绑定方法:绑定到谁的身上,就是给谁用的,谁来调用就会自动把自己当做第一个参数传入。
               1)定义在类内部的变量,是所有对象共有的,id全一样,
               2)定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.fun()会把obj本身当做一个参数来传递。
    - 在类内部定义的函数虽然可以由类来调用,但是并不是为了给类用的,在类内部定义的函数的目的就是为了绑定到对象身上的。
    - 在类的内部来说,__init__是类的函数属性,但是对于对象来说,就是绑定方法。
    - 命名空间的问题:先从对象的命名空间找,随后在从类的命名空间找,随后在从父类的命名空间找。
# 类的定义和调用
class Person:
    count = 0
    # 对实体进行初始化,构造函数
    def __init__(self,Type,Sex,Age,Name):
        self.race = Type
        self.sex =Sex
        self.age = Age
        self.name = Name
        Person.count += 1

    def talk(self,msg):
        self.msg = msg
        if self.msg != 0:
            print(self.name,'Saying:',self.msg)
if __name__ == '__main__':
    #在构造对象的时候会自动调用初始化构造函数
    p = Person('Black','Female','24','Susan')
    print(p.__dict__)
    print(Person.count)
    p.name = 'dtr'
    p.talk('Hello,my name is %s'% p.name)

三、初始化构造函数__init__的作用(重点)

所谓初始化构造函数就是在构造对象的同时被对象自动调用,完成对事物的初始化,一个类只要生成一个类对象,它一定会调用初始化构造函数.

特点:
   1. 一个类中只能有一个初始化构造函数
   2. 不能有返回值
   3. 可以用它来为每个实例定制自己的特征
class Student(): 
    def __init__(self,name,age): 
        self.name = name 
        self.age = age 
        print(self.name,self.age) 

if __name__ == '__main__': 
    #在构造对象的时候会自动调用初始化构造函数 
    student = Student("Alex",100)
  • self关键字

    1.为了辨别此时此刻正在处理哪个对象,self指针变量指向当前时刻正在处理的对象,即构造出来的对象
    2.在构造方法中self代表的是:self指针变量指向当前时刻正在创建的对象
    3.构造函数中self.name = name 的含义:将局部变量name的数值发送给当前时刻正在创建的对象中的name成员 
    

四、封装&继承&多态

4.1 封装

在面向对象中,所有的类通常情况下很少让外部类直接访问类内部的属性和方法,而是向外部类提供一些按钮,对其内部的成员进行访问,以保证程序的安全性,这就是封装.

class Student:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
    
    def set_name(self,name):
        self.__age = name
        return self.__name
    
    def get_name(self):
        return self.__name

    def set_age(self,age):
        self.__age = age
        return self.__age
    
    def get_age(self):
        return self.__age
    
    # 属性重置
    def setter(self,name,age):
        if not isinstance(name,str):
            raise TypeError("名字必须是字符串类型")
        if not isinstance(age,int):
            raise TypeError("年龄必须是整型类型")

        self.__name = name
        self.__age = age

if __name__ == "__main__":
    xiaoming = Student('xiaoming',18)
    print(xiaoming.get_age())
    # xiaoming.set_age(20)
    # print(xiaoming.get_age())
    xiaoming.setter('Tom',20)
    print(xiaoming.get_name())
    print(xiaoming.get_age())

4.2 继承

一个类从已有的类那里获得其已有的属性与方法,这种现象叫做类的继承

方法重写指在子类中重新定义父类中已有的方法,这中现象叫做方法的重写

若A类继承了B类,则a对象既是A,又是B,继承反映的是一种谁是谁的关系,只有在谁是谁的情况下,才能用继承解决代码冗余的问题。

寻找属性和方法的顺序问题:先从对象自己的命名空间中找,然后在自己的类中,最后在从父类当中去找

在Python3当中,所有的类都是新式,所有的类都直接或者间接的继承了Object

在Python中,新建的类可以继承一个或多个父类
# 类的继承
class People:
    def __init__(self,name, age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    
    def tell(self):
        print("%s-%s-%s"%(self.name,self.age,self.sex))

class Student(People):
    def __init__(self, name, age, sex,salary):
        # self.name = name
        # self.age = age
        # self.sex = sex   
        People.__init__(self,name,age,sex)
        self.salary = salary

    # 方法重写
    def tell(self):
        print("%s是 最棒的!"%self.name)
        # super关键字产生的原因:在子类当中可以通过使用super关键字来调用父类的中相应的方法,简化代码。 
        super().tell()

if __name__ == "__main__":
    Tom = Student('Tom',18,'男',12000)  
    print(Tom.tell())   
  • super关键字

    super关键字产生的原因:在子类当中可以通过使用super关键字来调用父类的中相应的方法,简化代码。
    
    使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表。
    

4.3 多态

在其他语言中,类似于c++和Java这一类强类型的语言中,函数的参数规定死了是什么数据类型就必须传递这种数据类型的数据进来,否则就会报错,但是在Python中内置的就是支持多态的,Python是一门弱类型语言,在函数的定义的参数中不需要指定参数的数据类型,可以传递任意数据类型的参数到函数中去。所以对于Python来说不存在多态的问题,那么在Java和C++中的多态是什么意思呢?说的是函数的参数中指定了参数类型是父类的对象,那么这个父类的子类的对象也可以传递进这个函数中,这样就实现了参数的多态性。

1. 所谓多态指的是一个父类的引用既可以指向父类的对象,也可以指向子类的对象,它可以根据当前时刻指向的不同,自动调用不同对象
   的方法,这就是多态的概念。(当然,Python中的多态没必要理解的这么复杂,因为Python自带多态的性能)
2. 多态性依赖于同一种事物的不同种形态
3. Python是一门弱类型的语言,所谓弱类型语言指的是对参数没有类型限制,而这是我们可以随意传入对象的根本原因 

五、面向对象进阶

5.1 成员修饰符

Python的类中只有私有成员和公有成员两种,不像C++中的类有公有成员(public),私有成员(private)和保护成员(protected).并且Python中没有关键字去修饰成员,默认Python中所有的成员都是公有成员,但是私有成员是以两个下划线开头的名字标示私有成员,私有成员不允许直接访问,只能通过内部方法去访问,私有成员也不允许被继承。

5.2 特殊成员

5.3 @property的用法

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性
的使用方式遵循了统一访问的原则(使用的原因)

一旦给函数加上一个装饰器@property,调用函数的时候不用加括号就可以直接调用函数了 
# 在定义普通方法的时候,在上面加上@property装饰器装饰时,生成的是一个类似于属性的方法。
class Student:
    @property
    def learn(self):
        print("I like study!")

if __name__ == '__main__':
    student = Student()
    student.learn 

5.4 接口&抽象类

5.5 组合的概念

一个类的属性可以是一个类对象,通常情况下在一个类里面很少定义一个对象就是它本身,实际意义很少。

将另外一个对象作为自己的属性成员(自己的一个属性来自于另外一个对象),这就是组合。

组合也可以解决代码冗余的问题,但是组合反应的是一种什么是什么的关系。
class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
        
    def tell(self):
        print("%s--%s--%s"%(self.year,self.month,self.day))

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

class Student(People):
    def __init__(self,name,age,sex,year,month,day):
        People.__init__(self,name,age)
        self.sex = sex
        self.birth = Date(year,month,day)

if __name__ == '__main__':
    student = Student("alex",25,"man",2015,12,31)
    print("student的birth成员指向了一个Date对象!")
    print("%s"%student.birth)
    student.birth.tell()

未完待续…

主要参考:https://blog.csdn.net/a2011480169/article/details/73087097

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值