24.面向对象(类、封装)

2019-12-27  本文已影响0人  哈哈大圣

面向对象(类、封装)

一、类与实例对象

1). 类的定义与实例化

  1. 实例化之前先定义类,类名要大写 (解释性语言特点)
class Student:
    # Python很奇葩:这里定义为静态数据变量
    name = '哈哈大圣'   # 静态数据属性:

    def learn(self):   # 函数属性
        print('is learning')

    def eat(self):     # 函数属性
        print('is sleeping')
  1. 实例化对象
stu1 = Student()
print(stu1)

2). 类内元素操作

  1. 查看类的名称空间
a = Student.__dict__
name = Student.__dict__['name']
learn = Student.__dict__['learn']
  1. 获取类的属性
name = Student.name    # 等同于Student.__dict__['name']
learn = Student.learn  # 等同于Student.__dict__['learn']
  1. 增加类的属性,可以增加成员属性,也可以增加函数属性;(解释性语言特点)
Student.county = 'China'

def like():
    print("like")
Student.like = like
Student.like()
  1. 修改类的属性
Student.school = '双一流大学'
  1. 删除类的属性
del Student.county
del Student.like

3). 构造函数

  1. __init__: 用来为对象定制对象自己独有的特征
    • 此方法中定义才为实例变量
class Student: #定义的时候执行该类

    school='双一流大学'

    def __init__(self, name, sex, age):
        self.Name=name
        self.Sex=sex
        self.Age=age

    def learn(self):
        print('is learning')

    def eat(self):
        print('is sleeping')
  1. 执行定义的构造函数
stu1=Student('王二丫','女',18) 
# 等同于Student.__init__(stu1,'王二丫','女',18)

4). 类方法、普通方法以及数据属性

  1. 调用普通方法,方法所在的地址都是一样的
  2. 对象中的绑定方法与对象之间进行绑定,不同的对象相同的绑定方法所占的内存地址是不一样的。
  3. 通过.访问的数据属性,会先在对象命名空间找,没有就在类的命名空间找,在没有就在父类中去找,但不会到所在模块中去找了,这是类的特性

二、继承

1). Python中的继承

  1. 支持多继承,通过C3线性查找算法生成一个MRO列表,根据列表顺序查找
  2. 继承的语法
class A:
    name = "A"
    
    def func(self):
        print("A func")

class B:
    name = "B"
    
    def func(self):
        print("B func")

# 继承的写法
class C(A, B):
    name = "C"
    
    def func(self):
        print("B func")

2). 派生

  1. 派生,重写父类的方法或者属性
  2. 案例
class Hero:
    def __init__(self, name, life_count, attact_count):
        self.name = name
        self.life_count = life_count
        self.attact_count = attact_count

    def attact_enemy(self, enemy):
        enemy.life_count -= self.attact_count

# 加个括号表示继承
class Galen(Hero): 
    # 当子类中重写了父类的方法之后,就会调用子类的方法,这就叫做派生
    def attact_enemy(self): 
        print("攻击无效")

class Ruiwen(Hero):
    pass
    
g1 = Galen("草丛伦",100,30) #生成一个对象
r1 = Ruiwen("瑞文妹妹",80,50)
g1.attact_enemy()

3). C3线性查找算法

  1. 经典类的查找方式

经典类.png
  1. 新式类 (Py3中的类) 的查找方式:C3线性查找算法
    • 根据继承关系生成对应的图,根据相应的图算法确定顺序。
    • 很明显,如果多个分支有共同的父类,会将此父类的遍历位置放在其他分支的深度优先遍历之后。

新式类.png
  1. 任何父类中查找的起始点为发起方法/数据属性的子类所在的内存空间。
temp = "temp"
class Hero:
    def f1(self):
        print("Hero's f1")

    def f2(self):
        print("Hero's f2")
        self.f1()        # 注意,这里又开始从对象中开始查找了
        print(self.nice) # 注意,这里又开始从对象中开始查找了
        print(temp)      # 这个temp不是用.调用的,不和对象产生关系,所以查找的方式是普通的命名空间的规则

class Galen(Hero):
    def __init__(self):
        self.nice  = "nice"
        
    def f1(self):
        print("Galen's f1")

g1 = Galen()
g1.f2()
"""
Hero's f2
Galen's f1
nice
temp
"""
  1. 查看父类
class Foo:
    pass

print(Foo.__bases__) #查看父类

print(Foo.mro()) #打印MRO列表(经典类没有这个方法)

4). 子类中重用父类的方法属性

  1. 子类中重用父类的方法和属性有两种方式
    1. 指名道姓(不依赖继承)
    2. super(): (依赖继承,基于对象所产生的MRO列表)

class Hero:
    def __init__(self,nickname, life_value, aggresivity):
        self.nickname = nickname
        self.life_value = life_value
        self.aggresivity = aggresivity
        
    def attack(self, enemy):
        enemy.life_value -= self.aggresivity


class Garen(Hero):
    camp='Demacia'
    def __init__(self, nickname, life_value, aggresivity):
        # 依赖性继承的方式,py3中的简写方式(找MRO)
        super().__init__(nickname, life_value, aggresivity)

    def attack(self, enemy):
        # 指名道姓重用父类的方法,不依赖于继承
        Hero.attack(self, enemy)   
        print('from Garen Class')

class Riven(Hero):
    camp='Noxus'

g = Garen('草丛伦',100,30)
r = Riven('锐雯雯',80,50)

三、组合

1). 组合概述

  1. 组合描述的是 has a 关系
  2. 对于类数据属性,通过实例对象“.”的方式进行数据子元素的增删改,如果没有实例变量则会找静态变量。
  3. 通过实例.数据属性 = ?这种形式,则此数据属性为对象属性,非静态的。
import datetime
class Person:
    def __init__(self,name,gender,date):
        self.name = name
        self.gender = gender
        self.date = date
        self.age = self.calculate_age()

    def calculate_age(self):
        time_lag = datetime.datetime.now().year - self.date.date_struct.year
        return time_lag

class Student(Person):
    course_list = [] # 静态变量
    def __init__(self,name,gender,date,course):
        super().__init__(name,gender,date)
        Student.course_list.append(course)  # 这么写了就成了静态变量了

    def learning_course(self):
        print("%s is learing!" % self.name)

class Teacher(Person):
    pass

class Date:
    def __init__(self,year,month,day):
        self.date_struct = datetime.datetime.now().replace(year=year,month=month,day=day)

    def show_info(self):
        print("%s年%s月%s日" % (self.date_struct.year,self.date_struct.month,self.date_struct.day))

d1 = Date(1996, 12, 12)
s1 = Student("a", "male", d1, "python")

# 通过对象直接增删改,对象没有则找静态变量
s1.course_list.append("python进阶")

# 直接赋值,数据属性属于对象。
s1.course_list = ["art"]

# 通过组合的方式调用了其他类中的属性(组合关系,非继承关系)就是有的关系
s1.date.show_info()
上一篇 下一篇

猜你喜欢

热点阅读