黄朝忆的个人博客
登录|注册

7. 面向对象

创建 2026-10-19 22:268780 字0 浏览0 评论

什么是?

    在 Python 里,对象(object)就是内存中一个有类型、有值、能操作的数据实体;一个手机、一辆车都是对象


面向对象

    一种以对象为中心去思考和组织代码的方式,它更关注: “谁来做这件事”


面向过程

    关注过程


类(class)

    用来描述一类事物的“模板”,它规定了一类事物所具有的【属性】和【行为】


实例(instance)

    根据【类】创建出来的一个具体的对象就是实例(实例对像)

    类是抽象的、实例是具体的


实例化

    根据类“制造出”对象的过程,就是实例化


定义一个类

    在类中定义了函数时,这个函数我们称为方法

    __init__: 称为初始化方法,主要作用是给当前创建实例化对象添加属性;self表示正在创建的实例对象;__init__ 实际化方法,python会自动调用

    __init__里面的属性称为实例属性,只能通过实例访问,不能通过类访问;每个实例都有自己的【独一份】实例nttn,各个实例属性是互不干扰的

class Person:
    # __init__: 实际化就去,主要作用:给当前正在创建的实际对象添加属性
    # self 表示正在创建的实例对象
    # __init__ python会自动去调用
    def __init__(self, name, age):
        # 下面这些都是实例属性,只能通过实例问,不能通过类访问
        # 每个实例都有自己的【独一份】实例nttn,各个实例属性是互不干扰的
        self.name = name
        self.age = age


类的__dict__属性

    可以查找到类上所有的属性

    实例上也有__dict__属性



创建实例

    创建实例、查看属性、修改属性、追加属性、查看全部属性

class Person:
    # __init__: 实际化就去,主要作用:给当前正在创建的实际对象添加属性
    # self 表示正在创建的实例对象
    # __init__ python会自动去调用
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("huangcy", 18)
print(p.name) # huangcy
print(p.age) # 18

# 修改属性
p.age = 33

# 追加属性
p.height = 176

# 通守__dict__ 可以查看实际上所有的属性
print(p.__dict__)

# 通过type 函数,可以查看实例是哪个对象创建出来的
print(type(p))


自定义方法

    speak就是自定义方法

    因为是给实例调有的,所以也叫实列方法;

    也可以通过类.方法的方式来调用,但是要注意的是, 第一个参数要传入一个实例

class Person:
    # __init__: 实际化就去,主要作用:给当前正在创建的实际对象添加属性
    # self 表示正在创建的实例对象
    # __init__ python会自动去调用
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 自定义方法
    # speak方法只有一份,保存在Person类身上,所有Person类的实际对象,都可以调用到这个方法
    def speak(self, msg):
        print(f'我是{self.name}! 我的年龄是{self.age}, 我想说:{msg}')

p1 = Person('huangcy', 33)
p2 = Person('张三', 20)

# 实际对象上是没有speak方法的
# 当实行到p1.speak方法时,查找speak方法过程: 实例对象自身(p1) -> 实际的【缔造者(Person)】身上查找
print(p1.__dict__)


p1.speak('hello')
p2.speak('hi')

#通过类来调用实例方法
Person.speak(p1, ' hello')


类属性

    类属性可以通过类访问,也可以通过实例访问

    类属性通常用于保存:公共数据

    可以通过类名.属性名的方式进行修改,也可以通过实例对象来修改,通过实例对象修改的类属性,不会影响之前创建的实例

class Person:
    # 类属性
    max_age = 120
    address = '中国'


类方法

    使用@classmethod装饰器的方法,就叫类方法

    类方法收到的参数:当前类本身(cls)、自定义参数

    因为收到了cls参数,所以类方法中也是可以访问类属性的

    类方法通常用于实际:与类相关的逻辑,例如:操作类级别的信息、工厂方法

   注意:也可以通过实例对象来调用类方法,非常不推荐

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

    # 类方法
    # 例子是一个工厂方法
    @classmethod
    def create(cls, value):
        name, age = value.split('-')
        return cls(name, age)
    
p1 = Person.create('huangcy-25')
print(p1.name, p1.age) 


静态方法

    使用@staticmethod装饰的方法就叫静态方法

    静态方法只是单纯的定义在类中,它不会收到self、cls参数,它只能收到自定义参数

    由于静态方法没有收到self、cls参数,所以其内部不会访问任何中类和实例相关的内容

    静态方法通常用于定义:与类相关的工具方法

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

    @staticmethod
    def show():
        print('我是一个类静态方法')

p1 = Person('huangcy', 25)
Person.show()
p1.show() # 不推荐


继承

    通过括号里加父类的方式来实现继承


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

# 定义一个Student类(子类、派生类),继承自Person类(父类、超类、基类)
class Student(Person):
    def __init__(self, name, age, gender):
        # 调用父类的__init__方法来执行初始化相关属性的操作
        # 方式1
        super().__init__(name, age)
        # s = super()
        # s.__init__(name, age)

        # 方式2
        # Person.__init__(self, name, age)

        self.gender = gender

s1 = Student('huangcy', 25, '男')
print(s1.name)


类的__mro__属性

    用于记录属性和方法的查找顺序、继承查找调用关系就很有用了



方法重写

    当子烦躁定义了一个与父类中相同的方法,那子类中的方法就会“覆盖”父类的方法

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

    def speak(self, msg):
        print(f'我是{self.name}, 我想说: {msg}')

class Student(Person):
    def speak(self, msg):
        print(f'我是学生{self.name}, 我会说 {msg}')


s1 = Student('huangcy', 25)
s1.speak('你好')


super

    可以调用父类中的各种方法或者属性

 result = super().__dict__


类中的常用方法

isinstance

    isinstance(instance, Class) 判断某个对象是否为指定类或者子类的实例


issubclass

    issubclass(Calss1, Class2) 判断某个类是否为另一个类的子类


多重继承

    多重继承指一个类同时继承多个父类,从而拥有多个父类的属性和方法

    举例:就像孩子不仅继承爸爸的长相,也能继承妈妈的性别。

# 多重继承指一个类同时继承多个父类,从而拥有多个父类的属性和方法
# 举例:就像孩子不仅继承爸爸的长相,也能继承妈妈的性别。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def speak(self):
        print(f'我是{self.name}, 年龄是{self.age}')

class Worker:
    def __init__(self, company):
        self.company = company
    def to_work(self):
        print(f'我在{self.company}工作')

class Student(Person, Worker):
    def __init__(self, name, age, height, company):
        Person.__init__(name, age)
        Worker.__init__(company)
        self.height = height
    def study(self):
        print(f'我是全校最高的学生,我的身高是{self.height}')

s1 = Student('huangcy', 25, 178, '清川智算')


面向对象的三种访问权限

    通过变量名之前加下划线来控制权限(笑死)

    受保护的属性:在外面其实还是能访问,只是不推荐(笑死)

    私有属性: 哪里访问都会报错

class Person:
    def __init__(self, name, age, idcard):
        self.name = name # 公有属性:当前类中,子类中、类外部,都可以访问
        self._age = age # 受保护的属性:当前类中、子类中都可以访问
        self.__idcard = idcard # 私有属性:仅在当前类中可以访问


面向对象之getter和setter

    私有属性、成员属性其实都可以通过自定义方法修改或者读取,但显得不够优雅,而且还要加括号

class Person:
    def __init__(self, name, age, idcard):
        self.name = name # 公有属性:当前类中,子类中、类外部,都可以访问
        self._age = age # 受保护的属性:当前类中、子类中都可以访问
        self.__idcard = idcard # 私有属性:仅在当前类中可以访问

    # 注册age属性的getter方法,当访问Person实例的age属性时,下面的方法就会被自动调用
    # 当然这里的age函数名,可以随意;一般约定俗成就用不带下划线的命名
    @property
    def age(self):
        return self._age

    # 注册age属性的setter方法,当修改Person实例的age属性时,下面的方法就会被自动调用
    # 当然这里的age函数名,可以随意;一般约定俗成就用不带下划线的命名
    @age.setter
    def age(self, age):
        if age < 0 or age > 100:
            print('年龄非法')
        else:
            self._age = age


p1 = Person('huangcy', 25, '123')
p1.age = 202
print(p1.age)


魔法方法(魔术方法)

    以__xxx__命名的特殊方法(双下划线开头和结尾)

    特点:不需要我们手动调用,我们只要准备好这些方法,python 就会在特定场景下,去自动调用

    以下是常用的几个,还有很多


__str__

    当执行print(实例对象) 或者 str(实例对象)时自动调用

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self) -> str:
        return f'{self.name}, {self.age}'

p1 = Person('huangcy', 25)
# 打印p1实例,就会自动调用类的__str__
print(p1)
# 上面这行等同于
print(str(p1))


__len__

    当len(对象) 时自动调用


__lt__

    当执行 对象1 < 对象2时调用


__gt__

    当执行 对象1 > 对象2时调用


__eq__

    当执行 对象1 == 对象2时调用


__getattr__

    当访问属性不存在的属性时


__main__

    只有当你直接运行这个 .py 文件时,它才执行;被别的文件 import 时不执行


object类

    python中,所有的类都继承了object类,即object类是所有类的顶层父类

    因为object 是所有类的父类,所以python中的所有对象,都间接是object类的实例

    像int、str、list、tuper等等,其实都是内置类(函数);所有对象都继承了object类所提供的:各种属性和方法,从而保证了每个对象都具备了统一的基本能力;object.__dict__


dir函数

    dir() 用来列出“一个对象有哪些属性/方法名”,返回一个字符串列表

    这就非常好玩了,可以判断一个属性/函数上是不是有属性或者方法之类的了


多态

    多态的概念: 同一个方法名,在不同的对象上调用时,能呈现出不同的行为

    python中支持:标准多态和鸭子多态


# 标准多态

class Animal:
    def speak(self):
        print('动物正在发出声音...')

class Dog(Animal):
    def speak(self):
        print('小狗在汪汪汪...')

class Cat(Animal):
    def speak(self):
        print('小猫在喵喵喵...')

# animal: Animal 类型注解,后面会详细讲
def make_sound(animal: Animal):
    animal.speak()

# 创建实例对象
a1 = Animal()
d1 = Dog()
c1 = Cat()

make_sound(a1)
make_sound(d1)
make_sound(c1) 


鸭子多态:如果一个东西看起来像鸭子,叫起来也像鸭子,那它就是鸭子。

鸭子类型是一种编程风格,它不检查对象的类型,只关注对象能否“做某件事”(是否有对应的方法)


class Dog:
    def speak(self):
        print('小狗在汪汪汪...')

class Cat:
    def speak(self):
        print('小猫在喵喵喵...')

class Pig:
    def speak(self):
        print('小猫在哼哼哼...')

class Fish :
    def speak(self):
        print('小猪在咕咕咕...')

def make_sound(animal):
    animal.speak()

# 创建实例对象
d1 = Dog()
c1 = Cat()
p1 = Pig()
f1 = Fish()

make_sound(d1)
make_sound(c1)
make_sound(p1)
make_sound(f1)



抽象类

    抽象类是一种不能直接实例化的类,它通常作为“规范”,让子类去继承,并实现其中定义的【抽象方法】

    通过继续ABC类,那么这个类就是抽象类了

    通过@abstractmethod注解的方法,就是抽象方法了


from abc import ABC, abstractmethod


class MustRun(ABC):
    # 抽象方法
    @abstractmethod
    def run(self):
        pass

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

    def run(self):
        print(f'我是{self.name},我已经{self.age}岁了')
        print('python 这些真的挺抽象的,学习要笑抽了...')


d1 = Dog('huangcy', 25)
d1.run()


内存地址

    python中万物即对象?

    python中常见的不可变对象有: int、float、bool、str、tuple、frozenset、None

    python中常见的可变对象有:list、dict、set、自定义类的实例对象


  不可变对象分析图

image.png


可变类型变量分析

image.png



函数也是对象(重新认识函数)

  • 函数也是实例对象:function的实例对象
  • 函数也可以动态添加属性
  • 函数可以赋值给变量
  • 函数的可变参数和不可变参数
    • 传参的区别:其实就是不可变类型,进去后怎么改都不会影响外层的;可变类型的,里面有调整,那么外面也就会变化(因为是引用地址)
  • 函数也可以作为参数(高阶函数)
  • 函数也可以作为返回值(高阶函数)
  • 函数多个返回值(自动转换成元组)


def test():
    print('test')

# test函数function类的实例对象
print(type(test))

# 函数可以动态添加属性
test.name = 'test'
test.version = '1.0'
print(test.name)
print(test.version)

# 函数可以赋值给变量
say_test = test

say_test()

# 可变参数 vs 不可变参数
# 传参的区别:其实就是不可变类型,进去后怎么改都不会影响外层的;可变类型的,里面有调整,那么外面也就会变化(因为是引用地址)
a = 666
def welcome(data):
    print(data, id(data)) # 666
    data = 888
    print(data, id(data)) # 888

print(a) # 666
welcome(a)
print(a) # 666

# 可变参数的例子
b = [1, 2, 3]
def welcome1(data):
    print('b是', data, id(data))
    data[1] = 888
    print('b是', data, id(data))
print('b是',b)
welcome1(b)

print('------')
# 函数也可以作为参数
def a():
    print('a')
def b(fn):
    fn()
b(a)

print('------')
# 函数也可以作为返回值
def c(msg):
    print(f'c的msg是 {msg}')
def d(msg):
    return c(msg)

d('ss')

print('------')
def e():
    return 5, 3 # 自动转换成元组

print(e()) # (5, 3)






评论(共 0 条)

编辑器加载中...
7. 面向对象 - python快速入门