python 3 基础之类和对象的创建、面向对象的三大特性

面向对象简单理解:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程

类:对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类

  类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象

  如字典就是一类数据结构,字符串是一类数据结构,它们各自都具有相同的特征属性和方法

对象:某个具体事物的存在,在现实世界看得见摸得着,对象归属于一类;创建一个对象需要依赖于类

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。类根据继承可以分为父类和子类
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,所以Dog也是一个Animal。(派生类相当于子类,基类相当于父类,只是称呼不同)
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法

1、创建类和对象

  1.1、类

    经典类和新式类,从字面上可以看出一老一新,新的必然包含了更多的功能,是推荐的写法,从写法上区分:如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类

    创建一个类

# 经典类1
class Hhh:
    pass
# 经典类2
class Jor:
    pass
# 新式类
class Fa(object):
    pass

  1.2、创建一个对象

# 自定义一个狗类(自定义类名一般遵循大驼峰命名)
class Dog(object):
    # 定义一个方法(实例方法 或 对象方法)
    # 实例方法第一个参数为self(python默认的)
    # 实例方法 下划线 或小驼峰(公司的要求)
    def move(self):
        print('狗会吃骨头')
# 使用自定义的类创建一个对象
wangcai = Dog()
# 调用狗类中的方法(想要使用其类中的方法,要使用这个类创建一个对象 使用对象调用其类里面的方法)
wangcai.move()

2、添加对象属性和判别同一个类创建的多个对象是否为同一个对象

  2.1、方法外添加对象属性

 1 # 定义一个Dog类
 2 class Dog(object):
 3     def eat(self):
 4         print('狗吃骨头')
 5     def zuoyong(self):
 6         print('狗会看家')
 7 
 8 # 使用类创建一个对象
 9 wang = Dog()
10 # 在方法外赋予对象属性
11 wang.name = '旺财'
12 wang.age = 4
13 wang.colour = '白色'
14 print(wang.name)

  2.2、判别同一个类创建的多个对象是否为同一对象

  python中每创建一个新的对象,需要开辟一个内存空间,占用内存地址,而内存地址是唯一的,以此判断是否为同一个对象,不同对象开辟的内存地址也不同

 1 class Dog(object):
 2     def eat(self):
 3         print('狗吃骨头')
 4 # 使用类创建多个对象
 5 wang = Dog()
 6 wang1 = Dog()
 7 wang2 = Dog()
 8 # 用16进制查看对象的内存地址
 9 print(wang,wang1,wang2)
10 # 用10进制查看对象的内存地址
11 print(id(wang))
12 print(id(wang1))
13 print(id(wang2))
14 
15 ================================
16 
17 运行结果:<__main__.Dog object at 0x000002AFC4E21CC8>
18  <__main__.Dog object at 0x000002AFC4E21D48>
19  <__main__.Dog object at 0x000002AFC4E21D88>
20 2953945685192
21 2953945685320
22 2953945685384

  运行结果是各不相同,证明同一个类创建的多个对象时唯一的

3、面向对象的三大特征:封装、继承、多态

  3.1、封装

    顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容;对于面向对象来说,其实就是使用构造方法(__init__)将内容封装到对象中,然后通过对象直接或self间接获取被封装的内容

    封装的意义:

    1. 将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;
    2. 隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;
    3. 对类的属性和方法增加 访问权限控制

    

    3.1.1、通过 对象.属性 直接调用被封装的内容

class Hero(object):
    # 构造方法
    def __init__(self, name, hp, atk):
        # 设置属性的值
        self.name = name
        self.hp = hp
        self.atk = atk
# 创建一个对象
laosun = Hero('俺老孙',100,10)# 实则就是把'俺老孙',100,10三个数据分别封装到name,hp,atk里
# 通过对象直接调用
print(laosun.name)

    3.1.2、通过 对象.方法 间接调用

class Dog(object):
    # 构造方法
    def __init__(self, new_name, new_age, new_colour="白色"):
        # 给对象的属性赋值
        self.name = new_name
        self.age = new_age
        self.colour = new_colour
    def info(self):
        print("名字:%s" % self.name)
        print("年龄:%d" % self.age)
        print("毛色:%s" % self.colour)
# 创建一个对象
wang = Dog('黑狗',4,'黑色')
# 间接调用
wang.info()

  3.2、继承

    面向对象的继承和现实中的继承相似,面向对象的继承指的是类的继承,当一个类继承了另外一个类,被继承的类称之为父类,继承的类叫子类

    子类会继承父类的所有方法,属性;对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法

    在继承关系中,如果一个实例的数据类型是某个子类,那它也可以被看做是父类。但是,反过来就不行。

    继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树

    3.2.1、单继承

      只是继承一个父类

# 创建一个类,继承于object
class Dog(object):
    # 构造方法
    def __init__(self, new_name,):
        # 给对象的属性赋值
        self.name = new_name
    def info(self):
        print("名字:%s" % self.name)
# 创建一个单继承的子类Heigou,继承类Dog
class Heigou(Dog): def eat(self): print('黑狗血很贵听说') # 创建一个对象 wang = Dog('黑狗') hei = Heigou('大黑') # 根据对象调用类的方法 wang.info() hei.eat() # 根据对象调用父类的方法 hei.info() ============================================= 结果是成功调用父类的方法

    虽然子类没有定义__init__方法初始化属性,也没有定义实例方法,但是父类有。所以只要创建子类的对象,就默认执行了那个继承过来的__init__方法

    3.2.2、多继承

      子类继承多个父类(Python的类可以继承多个类,Java和C#中则只能继承一个类)

      多继承可以继承多个父类,也继承了所有父类的属性和方法
      注意:如果多个父类中有同名的 属性和方法,则默认使用第一个父类的属性和方法(根据类的魔法属性mro的顺序来查找);多个父类中,不重名的属性和方法,不会有任何影响

# 创建两个类,继承于object
class Hero(object):
    def __init__(self, name, hp, atk):
        self.name = name
        self.hp = hp
        self.atk = atk
class Dog(object):
    def __init__(self, new_name,):
        self.name = new_name
    def info(self):
        print("名字:%s" % self.name)
# 创建一个多继承的类
class Heigou(Dog,Hero):
    def eat(self):
        print('黑狗血很贵听说')
# 创建一个对象
wang = Dog('黑狗')
hei = Heigou('大黑')
# 调用父类的方法
hei.info()
# 利用子类的魔法属性__mro__查看属性和方法的查找顺序
print(Heigou.__mro__)

     当多继承中多个父类都定义了相同的函数(包括函数名,函数内容),子类调用函数时调用的是哪个父类的函数?

    当类是经典类时,会按照深度优先方式查找(子类a继承父类b、c,c又继承了d,当子类调用相同方法时,先查找a是否有此方法,若无,调用b的,若b也无,查看b是否有继承父类,有则 继续查找b的父类 ,没有则开始查找c,c若无,找c的父类,无则继续找父类的父类)

    当类时新式类时,按照广度优先查找(子类a继承父类b、c,c又继承了d,当子类调用相同方法时,先查找a是否有此方法,若无,调用b的,若b也无,先查找a的第二个父类c,若无,继续查找a的父类,此级父类均没有才开始查找父类的父类)

    如下图

 注意:在上述查找过程中,一旦找到,则寻找过程立即中断,转而执行方法,不会再继续找

  

  3.3、多态(同一个对象,多种形态)

     所谓鸭子类型:看着像鸭子,我们就说它是鸭子

    3.3.1、变量的多态

      多态在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说.

      比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态

    3.3.2、类的多态

      在说明多态是什么之前,在 Child 类中重写 print_title() 方法:若为male,print boy;若为female,print girl

class Person(object):
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

    def print_title(self):
        if self.sex == "male":
            print("man")
        elif self.sex == "female":
            print("woman")

class Child(Person):                # Child 继承 Person
    def print_title(self):
        if self.sex == "male":
            print("boy")
        elif self.sex == "female":
            print("girl")

May = Child("May","female")
Peter = Person("Peter","male")

print(May.name,May.sex,Peter.name,Peter.sex)
May.print_title()
Peter.print_title()

  当子类和父类都存在相同的 print_title()方法时,子类的 print_title() 覆盖了父类的 print_title(),在代码运行时,会调用子类的 print_title()

  这样,我们就获得了继承的另一个好处:多态。 

  多态的好处就是,当需要传入更多的子类,例如新增 Teenagers、Grownups 等时,我们只需要继承 Person 类型就可以了,而print_title()方法既可以直接继承,不重写(即使用Person的),也可以重写一个特有的。这就是多态的意思。调用方只管调用,不管细节,而当我们新增一种Person的子类时,只要确保新方法编写正确,而不用管原来的代码。

  用自己的话说多态:子类继承了父类,子类对父类的方法进行了重写,用子类进行创建对象,用对象可以调用子类的方法,也可以调用父类的方法,这就是多态

     

原文地址:https://www.cnblogs.com/will-wu/p/13259898.html