人工智能(python)开发 —— 面向对象(类的属性、方法、函数以及三大特性[封装、继承和多态])

一、属性

1、初始化(__init__属性)

        作用
                对新创建的对象添加属性等必须的资源
        说明
                a、初始化方法名必须为__init__ 不可改变
                b、初始化方法会在构造函数创建实例后自动调用,且将实例自身通过第一个参数self 传入 __init__ 方法
                c、构造函数的实参将通过 __init__方法的参数列表,传入到 __init__ 方法中
                d、初始化方法内如果需要return 语句返回,则只能返回None
        语法
                class 类名(继承列表):
                        def __init__(self[, 形参列表])
                                语句块
                       注: [] 里的内容代表可省略

        示例

                

2、析构方法(__del__属性)

        作用
                通常用来释放此对象占用的资源
        说明
                a、析构方法会在对象被销毁时自动调用
                b、python语句建议不要在对象销毁时做任何事情,因为对象销毁的时间难以确定
        语法
                class 类名(继承列表):
                        def __del__(self):
                                语句块

3、预置的实例属性

1)__dict__属性

        用来绑定一个存储此实例自身变量的字典

        示例

    class Dog:
        pass
     
    dog1 = Dog()
    print(dog1.__dict__)  # {}
    dog1.color = "白色"
    print(dog1.__dict__)  # {'color': '白色'}
2)__class__ 属性

        用来绑定创建此实例的类(类实例)

        作用

                可以借助于此属性来访问创建此实例的类

        示例

    class Dog:
        pass
    dog1 = Dog()
    print(type(dog1))
    print(dog1.__class__)
    dog2 = dog1.__class__()
    print(dog2.__class__)

4、类变量

        类变量是类的属性,此属性属于类,不属于此类创建的实例
        作用
                通常用来存储该类对象共有的数据
        说明
                a、类变量可以通过类直接访问
                b、类变量可以通过类的实例直接访问
                c、类变量可以通过此类的对象的 __class__属性间接访问
        语法
                class 类名(继承列表):
                        类变量名 = 表达式
                        ...
        示例

# 此示例示意类变量的用法,及类和对象的关系
class Human:
    total_count = 0  # 类变量,此变量用来记录所有对象的个数
    def __init__(self, n):
        self.name = n

# 类变量可以通过类直接访问
print("Human类内的类变量Human.total_count=",Human.total_count)
Human.total_count += 1
print("Human.total_count=", Human.total_count)

# 类变量可以通过类的实例直接访问
h1 = Human('小张')
print("h1.total_count=", h1.total_count)
h1.total_count = 100                               # 此做法是为实例添加一个变量,并不是修改类变量
print('Human.total_count=', Human.total_count)    # 1

# 类变量可以通过此类的对象的 __class__属性间接访问
h1.__class__.total_count = 200
print("Human.total_count=", Human.total_count)     # 200

5、类的文档字符串(__doc__属性)

        类内没有赋值给任何变量的字符串为类的文档字符串
        类的文档字符串由类的__doc__属性绑定
         示例
                class Dog:
                        '''这是类的文档字符串'''
                        pass
         查看方法:(交互模式下)
>>> help(Dog)
>>> dog1 = Dog()
>>> help(dog1)

6、__slots__ 属性

         作用
                限定一个类创建的实例只能有固定的属性(实例变量),不允许对象添加列表以外的属性
                访止用户因错写属性的名称而发生程序错误
         说明
                __slots__ 属性是一个列表,列表的值是字符串
                含有__slots__属性的类所创建的实例没有__dict__属性,即此实例不用字典来存储对象的属性
         示例
class Student:
    # 此列表让Student创建的对象只能用name和 age属性,不能有其它属性
    __slots__ = ['name', 'age']
    def __init__(self, name, age):
        self.name = name
        self.age = age

s1 = Student('小张', 15)
print(s1.__dict__) # 报错,因为没有__dict__字典
print(s1.age)      # 15
s1.Age = 16        # 报错,不允添加__slots__列表以外的属性
print(s1.age)      # 16?

7、 __base__ 属性

        类的__base__属性用来记录此类的基类
         内建类的继承关系
                >>> help(__builtins__)

        示例

class Human:
    pass
class Student(Human):
    pass
class Teacher(Human):
    pass
Student.__base__ is Human  # True

二、方法

1、实例方法(method)

        作用
                用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为
        说明
                实例方法的实质是函数,是定义在类内的函数
                实例方法至少有一个形参,第一个形参代表调用这个方法的实例,一般命名为'self'
        实例方法的调用语法
                实例.实例方法名(调用传参)
                或
                类名.实例方法名(实例, 调用传参)
        语法
                class 类名(继承列表):
                        def 实例方法(self, 形参1, 形参2, ...):
                                '''方法的文档字符串'''
                                语句块
        例子

class Dog:
     '''这是自定义的类, 用来描述小动物行为'''
     def eat(self, food):
          '''小狗吃东西的行为...'''
          print("小狗正在吃", food)
          self.food = food
     def food_info(self):
          print("上次吃的是", self.food)
 
dog1 = Dog()		# 创建一个实例对象
dog1.eat('骨头')	        # 让狗吃东西
 
dog2 = Dog()		# 创建一个实例对象
Dog.eat(dog2,'包子')	# 让狗吃东西
 
dog1.food_info()
Dog.food_info(dog2)

2、类方法@classmethod

        类方法是用于描述、操作类的行为的方法,此方法属于类,不属于该类创建的实例 
        说明
                a、类方法需要使用@classmethod 装饰器定义
                b、类方法至少有一个形参,第一个形参用于绑定类,约定写为'cls'
                c、类和对象实例都可以调用类方法
                d、类方法不能访问此类创建的对象的属性
        语法
                class  A:
                        V = 0
                        @classmethod
                        def  get_v(cls):    # 此方法不是实例方法,是类方法
                                return cls.v
        示例
                

3、静态方法 @staticmethod

        静态方法是定义在类内的函数,此函数的作用域是类的内部
        说明
                a、静态方法需要使用staticmethod装饰器定义
                b、静态方法与普通函数定义相同,不需要传入self实例参数和cls类参数              
                c、静态方法只能凭借该类或类的实例调用
                d、静态方法不能访问类变量和实例变量(属性)
        示例

class A:
    @staticmethod
    def myadd(x, y):
        return x + y

print(A.myadd(100, 200))  # 300
a = A()
print(a.myadd(300, 400))  # 700

三、函数

1、isinstance(obj, class_or_tuple)

        返回这个对象obj 是否是某个类的对象,或者某些类中的一个类的对象,如果是则返回True,否则返回False

2、type(obj)

        返回对象的类

3、示例

isinstance(3.14, float)  # True
isinstance('hello', str)  # True
 
class Dog:
    pass
 
dog1 = Dog()
isinstance(dog1, Dog)                # True
isinstance(dog1, (int, flaot))          # False
isinstance(dog1, (int, flaot, Dog))        # True
 
type(dog1)  is  Dog  # True

4、issubclass(cls, class_or_tuple)

        判断一个类是否继承自其它的类,如果此类cls是class或tuple中的一个派生子类,则返回 True, 否则返False

        示例

class A:
    pass

class B(A):
    pass

class C(B):
    pass

print(issubclass(C, B))                  # True
print(issubclass(B, C))                  # False
print(issubclass(bool, (C, B, A, int)))  # True

5、super 函数

        返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法
         说明
        super(type, obj)   返回绑定超类的实例(要求obj必须为type类型的实例)
        super()   返回绑定超类的实例,等同于 super(__class__, 实例方法的第一个参数),且必须在方法内调用


四、特性

1、封装 enclosure

        封装是指隐藏类的实现细节,让使用者不用关心这些细节
        封装的目的是让使用者通过尽可能少的方法(或属性)操作对象
        私有属性和方法
                python类中以双下划线('__')开头,不以双下划线结尾的标识符为私有成员,私有成员只能用此类的方法进行访问和修改,不能在子类或其他地方使用
        示例

class A:
    def __init__(self):
        self.__p1 = 100  # 创建私有属性,此属性在类外无法访问

    def __m1(self):      # 私有方法
        print("__m1 私有方法被调用")

    def infos(self):
        print("A类的infos访问的__p1属性是:", self.__p1)
        self.__m1()      # 调用自己的私有方法
    
a = A()
# print(a.__p1)    # 出错
a.infos()
# a.__m1()         # 出错  当前主模块不能调用A类的私有方法

2、继承(inheritance)  和  派生 (derived)

        继承是从已有的类中派生出新的类,新类具有原类的数据属性和行为,并能扩展新的行为
        派生就是从一个已有的类衍生出新的类,在新的类上可以添加新的属性和行为

        作用

                a、用继承派生机制,可以将一些共有功能加在基类中,实现代码共享.
                b、在不改变超类的代码的基础上改变原有的功能

        名词

                基类(base class)/超类(super class)/父类(father class)
                派生类(derived class) / 子类(child  class)

        说明

                任何类都直接可间接的继承自object类
                object类是一切类的超类
                        注:类的__base__属性用来记录此类的基类

1)覆盖 override

        覆盖是指在有继承关系的类中,子类中实现了与基类(超类)同名的方法,在子类实例调用该方法时,实际调用的是子类中的覆盖版本的方法的现象叫覆盖

        例子

#示例 B继承A,work覆盖父类中的
class A:
    '''A类'''
    def work(self):
        print("A.work被调用!")

class B(A):
    '''B类'''
    def work(self):
        '''work 方法覆盖了父类的work'''
        print("B.work被调用!")

b = B()
b.work()  # B.work

a = A()
a.work()  # A.work
问题:当覆盖发生时,子类对象能否调用父类中的方法?
        实现方法:b.__class__.__base__.work(b)     # A.work

       super 函数
                返回绑定超类的实例,用超类的实例来调用其父类的覆盖方法
                 说明
                        super(type, obj)   返回绑定超类的实例(要求obj必须为type类型的实例)
                        super()   返回绑定超类的实例,等同于 super(__class__, 实例方法的第一个参数), 且必须在方法内调用
                 示例
# 此示例示意用super构造函数来间接调用父类的覆盖版本的方法
class A:
    def work(self):
        print("A.work()")

class B(A):
    def work(self):
        print("B.work()")

    def super_work(self):
        '''此方法先调用一下子类的work,
        再调用一下父类的work'''
        self.work()  # 调用自己的work
        # super(B, self).work()  # 调用父类的work
        super().work()  # 调用父类的work

b = B()
# b.work()  # B.work(),
# super(B, b).work()  # A.work()
b.super_work()
# super().work()  # 错的!!! super() 不能在方法使用
                super函数显式调用基类的构造方法
                        当子类实现了__init__方法后,父类的__init__方法将被覆盖(即不会主动调用父类的__init__方法),会引起父类的属性得不到初始化,此时需要显式调用父类的初始化方法。
                示例
class Human:
    def __init__(self, n, a):
        self.name = n
        self.age = a
        print("Human.__init__被调用")
    def infos(self):
        print("姓名:", self.name)
        print("年龄:", self.age)

class Student(Human):
    def __init__(self, n, a, s):
        super().__init__(n, a)  # 显式调用父类的初始化方法
        self.score = s          
        print("Student.__init__被调用")

    def infos(self):
        super().infos()
        print("成绩:", self.score)

# h1 = Human('小张', 18)
# h1.infos()
s1 = Student("张学友", 35, 60)
s1.infos()
                        注意:super函数显式调用基类的构造方法时,super().__init__(...)必须紧跟在子类的__init__(...): 之后


2)单继承

        语法
                class 类名(基类名):
                        语句块
        说明
                单继承是指派生类由一个基类衍生出来

        示例

# 此示例示意单继承的语句及定义方法
class Human:
    '''此类用于描述人类的共性行为'''
    def say(self, what):         # 说话的行为
        print("say:", what)
    def walk(self, distance):    # 走路的行为
        print("走了", distance, '公里')

class Student(Human):
    def study(self, subject):
        print("正在学习", subject)

class Teacher(Student):
    def teach(self, subject):
        print("正在教:", subject)

h1 = Human()
h1.say('今天天气真好')
h1.walk(5)
print('-----------------')
s1 = Student()
s1.walk(4)
s1.say("走的有点累")
s1.study('python')

print('---------------')
t1 = Teacher()
t1.say("今天晚饭吃什么?")
t1.walk(3)
t1.teach("继承/派生")
t1.study("魔方")
3)多继承 multiple inheritance
        多继承是指一个子类继承自两个或两个以上的基类
        说明
                a、一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
                b、如果两个父类中有同名的方法,则在子类中又没有覆盖,此方法时,调用结果难以确定
         语法
                class 类名(基类名1, 基类名2, ...)
                        语句块

        示例

# 此示例示意多继承的语法和用法
class Car:
    def run(self, speed):
        print('车正在以', speed, '公里/小时的速度行驶')

class Plane:
    def fly(self, height):
        print('飞机以海拔', height, '米的高空飞行')

class PlaneCar(Plane, Car):
    '''PlaneCar类同时继承是Plane和 Car类'''

p1 = PlaneCar()
p1.fly(10000)
p1.run(300)

        多继承的问题(缺陷)

                标识符(名字空间)冲突的问题

                要谨慎使用多继承

                解决方案:多继承的 MRO (Method  Resolution Order)问题
                        MRO 方法搜索顺序问题  示例:
                                 python 3 广度优先   

                                python 2 深度优先

        多继承的支持语言

                支持: C++ / Python3
                不支持多继承:Java / Objective-C / Swift / C#

3、多态 polymorphic

        字面意思:多种状态
        多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象叫多态。

        说明

                a、多态调用方法与对象相关,不与类相关
                b、python的全部对象只有“运行时状态(动态)”,没有“C++/Java”里的“编译时状态(静态)”

        示例

class Shape:
    '''图形'''
    def draw(self):
        print("Shape的draw() 被调用")

class Point(Shape):
    def draw(self):
        print("正在画一个点")

class Circle(Point):
    def draw(self):
        print("正在画一个圆")
        
def my_draw(s):
    s.draw()  # s.draw调用谁是在运行时由s的类型动态决定
              # 此处显示出运行时状态

shape1 = Circle()
shape2 = Point()
my_draw(shape1)
my_draw(shape2)
         用途
                不同的对象有相同的行为(方法),需要采用多态


五、附录

        人工智能(python)—— 目录汇总

六、习题集

1、练习1(单继承)

        list类里只有append想末尾添加一个元素的方法,但是没有向列表头部添加元素的方法,事项能否为列表在不改变原有功能的基础上添加一个insert_head(n)的方法,在列表的头部添加元素。

class Mylist(list):
    def insert_head(self, element)
        self.insert(0,element)

myl = Mylist(range(3, 6))
print(myl)		# 【3, 4, 5】
myl.insert_head(2)    #  添加2到首部
print(myl)		# 【2, 3, 4, 5】

猜你喜欢

转载自blog.csdn.net/qq_27297393/article/details/80848591