自学内容网 自学内容网

2024-10-17 学习人工智能的Day9

Python类和对象

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。

如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。

接下来我们先来简单的了解下面向对象的一些基本特征。


1. 面向对象编程 Object-Oriented Programming

  • 什么是对象

    • 对象是指现实中的物体或实体
  • 什么是面向对象

    • 把一切看成对象(实例),用各种对象之间的关系来描述事务。
  • 对象都有什么特征

    • 对象有很多属性(名词)
      • 姓名, 年龄, 性别,
    • 对象有很多行为(动作,动词)
      • 学习,吃饭,睡觉,踢球, 工作
  • 什么是类:

    • 拥有相同属性和行为的对象分为一组,即为一个类
    • 类是用来描述对象的工具,用类可以创建此类的对象(实例)
  • 面向对象 示意

       /-------> BYD  E6(京A.88888) 实例,对象
车(类)  
       \-------> BMW  X5(京B.00000) 实例(对象)
    
       /-------> 小京巴(户籍号:000001)
狗(类)  
       \-------> 导盲犬(户籍号:000002)

       /-------> 100 (对象)
int(类)  
       \-------> 200 (对象)

2. 类和对象的基础语法

2.1 类的定义

类是创建对象的 ”模板”。

  • 数据成员:表明事物的特征。 相当于变量

  • 方法成员:表明事物的功能。 相当于函数

  • 通过class关键字定义类。

  • 类的创建语句语法:

    class 类名 (继承列表):
    实例属性(类内的变量) 定义
        实例方法(类内的函数method) 定义
        类变量(class variable) 定义
        类方法(@classmethod) 定义
        静态方法(@staticmethod) 定义
    

示例代码:

class Dog:  # 定义一个Dog类
    pass

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

    def introduce(self):
        print(f"My name is {self.name} and I am {self.age} years old.")

类的创建的说明:

  • 类名必须为标识符(与变量的命名相同,建议首字母大写)
  • 类名实质上就是变量,它绑定一个类

2.2 实例化对象(构造函数)

(1) 构造函数调用表达式

变量 = 类名([参数])

(2) 说明

– 变量存储的是实例化后的对象地址。

– 类名后面的参数按照构造方法的形参传递

  • 对象是类的实例,具有类定义的属性和方法。
  • 通过调用类的构造函数来创建对象。
  • 每个对象都有自己的状态,但共享相同的方法定义。

示例代码:

class Dog:
    pass

# 创建第一个实例:
dog1 = Dog()
print(id(dog1))  # 打印这个对象的ID
# 创建第二个实例对象
dog2 = Dog()  # dog2 绑定一个Dog类型的对象
print(id(dog2))


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

    def introduce(self):
        print(f"My name is {self.name} and I am {self.age} years old.")
        
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)

实例说明

  • 实例有自己的作用域和名字空间,可以为该实例添加实例变量(也叫属性)
  • 实例可以调用类方法和实例方法
  • 实例可以访问类变量和实例变量

2.3 self

大家学Python面向对象的时候,总会遇到一个让人难以理解的存在:self

​ 这个self到底是谁啊,为什么每个类实例方法都有一个参数self,它到底有什么作用呢?

「先下结论:类实例化后,self即代表着实例(对象)本身」

​ 想要理解self有个最简单的方法,就是你把self当做**「实例(对象)的身份证」**。

类比人类,人类就是一个Python类,每个个体的人代表着实例(对象),而每个人的身份证代表的Python中self,每个人可以凭借身份证去上大学、坐高铁、住酒店…(方法),而Python中的实例(对象)也可以凭着self去调用类的方法。

图片描述
  • self是类方法的第一个参数,用于引用对象本身。
  • self不是Python关键字,但是约定俗成的命名,可以使用其他名称代替,但通常不建议。

示例代码:

class Students:
    # 构造方法
    def __init__(self,name):
        self.name = name
 
    # 实例方法
    def study(self,examination_results):
        self.examination_results = examination_results
        print("同学{}的考试分数是{}".format(self.name,self.examination_results))
        print("该实例对象的地址是{}".format(self))
  • 先来个实例student_a
studend_a = Students('studend_a')
print(studend_a.name)
  • 再来个实例student_b
studend_b = Students('studend_b')
print(studend_b.name)

可以看出,实例(对象)不一样,打印出的结果也不一样,当类被实例化后,self.name其实就等于实例(对象).name

还是以刚刚的代码为例,我们再来调用里面的实例方法,里面会打印出self,就能看得更加明显了

实例student_a:

studend_a.study(80)

实例student_b:

studend_b.study(80)

大家能清楚看到两个实例打印出的self是不一样的,因为self代表着实例(对象)本身。

打印self出现下面对象信息

<main.Students object at 0x00000129EB0F6B38>

<main.Students object at 0x00000129EB0F6B00>

这个时候是不是就清楚了,类实例化后,self即代表着实例(对象)本身

3. 属性和方法

3.1 属性

  • 每个实例可以有自己的变量,称为实例变量(也叫属性)

  • 属性的使用语法

    实例.属性名
  • 属性的赋值规则

    • 首次为属性赋值则创建此属性.
    • 再次为属性赋值则改变属性的绑定关系.
  • 作用

  • 记录每个对象自身的数据

  • 属性使用示例:

    # file : attribute.py
    class Dog:
        def eat(self, food):
             print(self.color, '的', self.kinds, '正在吃', food)
        pass
    # 创建一个实例:
    dog1 = Dog()
    dog1.kinds = "京巴"  # 添加属性
    dog1.color = "白色"
    dog1.color = "黄色"  # 改变属性的绑定关系
    print(dog1.color, '的', dog1.kinds)
    
    dog2 = Dog()
    dog2.kinds = "藏獒"
    dog2.color = "棕色"
    print(dog2.color, '的', dog2.kinds)
  • 实例方法和实例属性(实例变量)结合在一起用:
    class Dog:
        def eat(self, food):
            print(self.color, '的',
                  self.kinds, '正在吃', food)


    # 创建第一个对象
    dog1 = Dog()
    dog1.kinds = '京巴'  # 添加属性kinds
    dog1.color = '白色'  # 添加属性color
    # print(dog1.color, '的', dog1.kinds)  # 访问属性
    dog1.eat("骨头")
    
    dog2 = Dog()
    dog2.kinds = '牧羊犬'
    dog2.color = '灰色'
    # print(dog2.color, '的', dog2.kinds)  # 访问属性
    dog2.eat('包子')
  • 练习:

    • 定义一个’人’类:
        class Human:
            def set_info(self, name, age, address='不详'):
                '''此方法用来给人对象添加'姓名'、'年龄'和 '家庭住址' 属性
                # 此处自己实现
            def show_info(self):
                '''此处显示此人的信息'''
                # 此处自己实现
    
        # 如:
        s1 = Human()
        s1.set_info('小张', 20, '北京市朝阳区')
        s2 = Human()
        s2.set_info('小李', 18)``
        s1.show_info()  # 小张 今年 20 岁, 家庭住址: 北京市朝阳区
        s2.show_info()  # 小李 今年 18 岁, 家庭住址: 不详
    

3.2 方法

class 类名(继承列表):
    def 实例方法名(self, 参数1, 参数2, ...):
        "文档字符串"
        语句块
  • 实例方法的作用

  • 用于描述一个对象的行为,让此类型的全部对象都拥有相同的行为

  • 实例方法说明

    • 实例方法的实质是函数,是定义在类内的函数
    • 实例方法至少有一个形参,第一个形参绑定调用这个方法的实例,一般命名为"self"
    • 实例方法名是类属性
  • 实例方法的调用语法

    实例.实例方法名(调用传参)
    # 或
    类名.实例方法名(实例, 调用传参)
    
  • 带有实例方法的简单的Dog类

    # file: instance_method.py
    class Dog:
        """这是一个种小动物的定义
        这种动物是狗(犬)类,用于创建各种各样的小狗
        """
        def eat(self, food):
            '''此方法用来描述小狗吃东西的行为'''
            print("小狗正在吃", food)
        def sleep(self, hour):
            print("小狗睡了", hour, "小时!")
        def play(self, obj):
            print("小狗正在玩", obj)
    
    dog1 = Dog()
    dog1.eat("骨头")
    dog1.sleep(1)
    dog1.play('球')
    
    dog2 = Dog()
    dog2.eat("窝头")
    dog2.sleep(2)
    dog2.play('飞盘')
    
    >>> help(Dog) # 可以看到Dog类的文档信息

3.3 类属性

  • 类属性是类的属性,此属性属于类,不属于此类的实例

  • 作用:

    • 通常用来存储该类创建的对象的共有属性
  • 类属性说明

    • 类属性,可以通过该类直接访问
    • 类属性,可以通过类的实例直接访问
  • 类属性示例

    class Human:
        total_count = 0  # 创建类属性  self.name = name
        def __init__(self, name):
            self.name = name
    
    print(Human.total_count)
    h1 = Human("小张")
    print(h1.total_count)
    

3.4 类方法

  • 类方法是用于描述类的行为的方法,类方法属于类,不属于该类创建的对象

  • 说明

    • 类方法需要使用@classmethod装饰器定义
    • 类方法至少有一个形参,第一个形参用于绑定类,约定写为’cls’
    • 类和该类的实例都可以调用类方法
    • 类方法不能访问此类创建的对象的实例属性
  • 类方法示例1

    class A:
        v = 0
        @classmethod
        def set_v(cls, value): # def fun01(self)
            cls.v = value
        @classmethod
        def get_v(cls):
            return cls.v
    print(A.get_v())
    A.set_v(100)
    print(A.get_v())
    a = A()
    print(a.get_v())
    
    
    
  • 类方法示例2

class MyClass:
    class_attr = 0  # 类属性

    def __init__(self, value):
        self.instance_attr = value  # 实例属性

    @classmethod
    def modify_class_attr(cls, new_value):
        cls.class_attr = new_value
        print(f"类属性已修改为: {cls.class_attr}")

    @classmethod
    def try_modify_instance_attr(cls):
        try:
            cls.instance_attr = 10  # 尝试修改实例属性(会失败)
        except AttributeError as e:
            print(f"错误: {e}")

    def show_attrs(self):
        print(f"实例属性: {self.instance_attr}")
        print(f"类属性: {self.class_attr}")

# 创建类的实例
obj = MyClass(5)

# 调用类方法修改类属性
MyClass.modify_class_attr(20)  # 输出: 类属性已修改为: 20
obj.show_attrs()
# 输出:
# 实例属性: 5
# 类属性: 20

# 调用类方法尝试修改实例属性
MyClass.try_modify_instance_attr()
# 输出: 错误: type object 'MyClass' has no attribute 'instance_attr'

# 尝试调用类方法修改实例属性
obj.try_modify_instance_attr()
# 输出: 错误: type object 'MyClass' has no attribute 'instance_attr'

cls

在Python中,cls 是一个约定俗成的名称,用于表示类本身。在类方法(使用 @classmethod 装饰的方法)中,cls 作为第一个参数传递给方法。这使得类方法可以访问和修改类属性以及调用其他类方法,而不需要引用具体的实例。

cls 的作用

  1. 访问类属性:类方法可以通过 cls 访问和修改类属性。
  2. 调用类方法:类方法可以通过 cls 调用其他类方法。
  3. 创建类实例:类方法可以使用 cls 来创建类的实例。

示例

class MyClass:
    class_attr = 0  # 类属性

    def __init__(self, value):
        self.instance_attr = value  # 实例属性

    @classmethod
    def modify_class_attr(cls, new_value):
        cls.class_attr = new_value
        print(f"类属性已修改为: {cls.class_attr}")

    @classmethod
    def show_class_attr(cls):
        print(f"类属性当前值: {cls.class_attr}")

    @classmethod
    def create_instance(cls, value):
        # 使用 cls 创建类实例
        return cls(value)

# 调用类方法修改类属性
MyClass.modify_class_attr(20)  # 输出: 类属性已修改为: 20

# 调用类方法显示类属性
MyClass.show_class_attr()  # 输出: 类属性当前值: 20

# 使用类方法创建类的实例
new_instance = MyClass.create_instance(10)
print(f"新实例的实例属性: {new_instance.instance_attr}")  # 输出: 新实例的实例属性: 10
print(f"新实例的类属性: {new_instance.class_attr}")  # 输出: 新实例的类属性: 20

3.5 静态方法 @staticmethod

  • 静态方法是定义在类的内部函数,此函数的作用域是类的内部

  • 说明

    • 静态方法需要使用@staticmethod装饰器定义
    • 静态方法与普通函数定义相同,不需要传入self实例参数和cls类参数
    • 静态方法只能凭借该类或类创建的实例调用
    • 静态方法可以访问类属性但是不能访问实例属性
  • 静态方法示例

    class A:
        class_attr = 42  # 类属性
    
        def __init__(self, value):
            self.instance_attr = value  # 实例属性
    
        @staticmethod
        def myadd(a, b):
            # 只能访问传递的参数,不能访问类属性和实例属性
            return a + b
    
    # 创建类实例
    a = A(10)
    
    # 调用静态方法
    print(A.myadd(100, 200))  # 输出: 300
    print(a.myadd(300, 400))  # 输出: 700
    
    # 尝试在静态方法内访问类属性或实例属性(会导致错误)
    class B:
        class_attr = 42
    
        def __init__(self, value):
            self.instance_attr = value
    
        @staticmethod
        def myadd(a, b):
            # return a + b + B.class_attr
            # 以下访问会导致错误
            # return a + b + self.instance_attr
            return a + b
    
    # 创建类实例
    b = B(10)
    
    # 调用静态方法
    print(B.myadd(100, 200))  # 输出: 300
    print(b.myadd(300, 400))  # 输出: 700
    
    

课堂练习

list01 = [
    ["00","01","02","03","04"],
    ["10","11","12","13","04"],
    ["20","21","22","23","34"],
    ["30","31","32","33","34"],
]

# 需求:30位置上向右获取3个元素 用面向对象的思想

3.6 初始化方法

  • 初始化方法的作用:

    对新创建的对象添加属性

  • 初始化方法的语法格式:

    class 类名(继承列表):
        def __init__(self[, 形参列表]):
            语句块
    # [] 代表其中的内容可省略
    
  • 初始化方法的说明:

    • 初始化方法名必须为__init__ 不可改变
    • 初始化方法会在构造函数创建实例后自动调用,且将实例自身通过第一个参数self传入__init__方法
    • 构造函数的实参将通过__init__方法的参数列表传入到 __init__方法中
    • 初始化方法内如果需要return语句返回,则必须返回None
  • 初始化方法示例:

    # file : init_method.py
    class Car:
        def __init__(self, c, b, m):
            self.color = c  # 颜色
            self.brand = b  # 品牌
            self.model = m  # 型号
        def run(self, speed):
            print(self.color, "的", self.brand, self.model, "正在以", speed, "公里/小时的速度行驶")
        def change_color(self, c):
            self.color = c
    
    a4 = Car("红色", "奥迪", "A4")
    a4.run(199)
    a4.change_color("黑色")
    a4.run(230)
    

3.7 魔术方法

Python中的魔术方法(Magic Methods)是一种特殊的方法,它们以双下划线开头和结尾,例如__init____str____add__等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。

以下是一些常用的Python魔术方法:

  1. __init__(self, ...): 初始化对象,通常用于设置对象的属性。
  2. __str__(self): 定义对象的字符串表示形式,可通过str(object)print(object)调用。例如,您可以返回一个字符串,描述对象的属性。
  3. __repr__(self): 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)调用。
  4. __len__(self): 定义对象的长度,可通过len(object)调用。通常在自定义容器类中使用。
  5. __getitem__(self, key): 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]
  6. __setitem__(self, key, value): 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value
  7. __delitem__(self, key): 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]
  8. __iter__(self): 定义迭代器,使对象可迭代,可用于for循环。
  9. __next__(self): 定义迭代器的下一个元素,通常与__iter__一起使用。
  10. __add__(self, other): 定义对象相加的行为,使对象可以使用+运算符相加。例如,object1 + object2
  11. __sub__(self, other): 定义对象相减的行为,使对象可以使用-运算符相减。
  12. __eq__(self, other): 定义对象相等性的行为,使对象可以使用==运算符比较。
  13. __lt__(self, other): 定义对象小于其他对象的行为,使对象可以使用<运算符比较。
  14. __gt__(self, other): 定义对象大于其他对象的行为,使对象可以使用>运算符比较。
  15. __call__(self, other) 是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。

一些参考代码

1.__init__(self, ...): 初始化对象

class MyClass:
    def __init__(self, value):
     self.value = value

obj = MyClass(42)

2.__str__(self): 字符串表示形式

class MyClass:
   def __init__(self, value):
      self.value = value

   def __str__(self):
      return f"MyClass instance with value: {self.value}"


obj = MyClass(42)
print(obj)  # 输出:MyClass instance with value: 42

3.__repr__(self): 官方字符串表示形式

class MyClass:
   def __init__(self, value):
      self.value = value

   def __repr__(self):
      return f"MyClass({self.value})"
    
   #def __repr__(self):
      #return f"Person(name={self.name}, age={self.age})"


obj = MyClass(42)
print(obj)  # 输出:MyClass(42)

4.__len__(self): 定义对象的长度

class MyList:
   def __init__(self, items):
      self.items = items

   def __len__(self):
      return len(self.items)


my_list = MyList([1, 2, 3, 4])
print(len(my_list))  # 输出:4

5.__getitem__(self, key): 索引操作

class MyDict:
   def __init__(self):
      self.data = {}

   def __getitem__(self, key):
      return self.data.get(key)


my_dict = MyDict()
my_dict.data = {'key1': 'value1', 'key2': 'value2'}
print(my_dict['key1'])  # 输出:value1

6.__setitem__(self, key, value): 赋值操作

class MyDict:
   def __init__(self):
      self.data = {}

   def __setitem__(self, key, value):
      self.data[key] = value


my_dict = MyDict()
my_dict['key1'] = 'value1'
print(my_dict.data)  # 输出:{'key1': 'value1'}

7.__delitem__(self, key): 删除操作

class MyDict:
   def __init__(self):
      self.data = {}

   def __delitem__(self, key):
      del self.data[key]


my_dict = MyDict()
my_dict.data = {'key1': 'value1', 'key2': 'value2'}
del my_dict['key2']
print(my_dict.data)  # 输出:{'key1': 'value1'}

8.__iter__(self): 迭代器

class MyIterable:
   def __init__(self):
      self.data = [1, 2, 3, 4]

   def __iter__(self):
      self.index = 0
      return self

   def __next__(self):
      if self.index >= len(self.data):
         raise StopIteration
      value = self.data[self.index]
      self.index += 1
      return value


my_iterable = MyIterable()
for item in my_iterable:
   print(item)
# 输出:1, 2, 3, 4

9.__call__(self, *args, **kwargs)
class MyCallable:
    def __call__(self, *args, **kwargs):
        print("Called with arguments:", args, kwargs)

# 创建类的实例
my_callable = MyCallable()

# 像调用函数一样调用实例
my_callable(1, 2, 3, key="value")



4. 继承/派生

  • 什么是继承/派生

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

    • 继承的目的是延续旧的类的功能
    • 派生的目地是在旧类的基础上添加新的功能
  • 继承/派生的作用

    • 用继承派生机制,可以将一些共有功能加在基类中。实现代码的共享。
    • 在不改变基类的代码的基础上改变原有类的功能
  • 继承/派生名词:

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

4.1 单继承

  • 单继承的语法:

    class 类名(基类名):
        语句块
    

    单继承说明:

  • 单继承是指派生类由一个基类衍生出来的

  • 单继承的示例1:

    class Human:  # 人类的共性
        def say(self, what):  # 说话
            print("说:", what)
        def walk(self, distance):  # 走路
            print("走了", distance, "公里")
    
    class Student(Human):
        def study(self, subject):  # 学习
            print("学习:", subject)
    
    class Teacher(Human):
        def teach(self, language):
            print("教:", language)
    
    h1 = Human()
    h1.say("天气真好!")
    h1.walk(5)
    
    s1 = Student()
    s1.walk(4)
    s1.say("感觉有点累")
    s1.study("python")
    
    t1 = Teacher()
    t1.teach("面向对象")
    t1.walk(6)
    t1.say("一会吃点什么好呢")
    

4.2 多继承

Python支持多继承形式。多继承的类定义形如下例:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

#类定义
class people:
    #定义基本属性
    name = ''
    age = 0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0
    #定义构造方法
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s 说: 我 %d 岁。" %(self.name,self.age))
 
#单继承示例
class student(people):
    grade = ''
    def __init__(self,n,a,w,g):
        #调用父类的构函
        people.__init__(self,n,a,w)
        self.grade = g
    #覆写父类的方法
    def speak(self):
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
 
#另一个类,多继承之前的准备
class speaker():
    topic = ''
    name = ''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
 
#多继承
class sample(speaker,student):
    a =''
    def __init__(self,n,a,w,g,t):
        student.__init__(self,n,a,w,g)
        speaker.__init__(self,n,t)
 
test = sample("Tim",25,80,4,"Python")
test.speak()   #方法名同,默认调用的是在括号中参数位置排前父类的方法

4.3 覆盖 override

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

  • 作用:

    • 实现和父类同名,但功能不同的方法
  • 覆盖示例

    class A:
        def work(self):
            print("A.work 被调用!")
    
    class B(A):
        '''B类继承自A类'''
        def work(self):
            print("B.work 被调用!!!")
        pass
    
    b = B()
    b.work()  # 请问调用谁?  B
    
    a = A()
    a.work()  # 请问调用谁?  A
    

原文地址:https://blog.csdn.net/ctrey_/article/details/143026788

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!