卡码笔记-最强八股文
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
首页
计算机基础
Python
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
大模型Github (opens new window)
代码随想录 (opens new window)
  • 本栏必读

    • Python面试题专栏介绍
    • Python学习路线
    • Python零基础入门课
  • 基础语法

  • 函数、作用域与模块

  • 面向对象

    • Python中的类和对象是什么?
      • 简要回答
      • 详细回答
      • 知识拓展
    • 实例属性和类属性有什么区别?
    • 实例方法、类方法和静态方法有什么区别?
    • __new__和__init__有什么区别?
    • Python如何实现封装、继承和多态?
    • Python多继承的MRO是什么?super()如何工作?
    • Python常见魔术方法有哪些?
  • 进阶语法与语言机制

# Python类和对象:类是蓝图,对象是实例

面试官问:"Python中的类和对象是什么关系?为什么叫self?"

这题很多人会说"类是模板,对象是实例"就完了。但真正要讲清楚的是:类定义了对象的结构和行为,对象是类的一个具体副本;每个对象都有自己的属性字典,而方法是通过self绑定到具体对象上的。 另外,Python对象不像其他语言那样有内存布局的限制,属性可以随时增删。

# 简要回答

类是一个代码模板,对象是类的一个运行时实例。 定义类时,用class声明属性和方法;创建对象时,调用类名(触发__new__和__init__),得到一个真实存在的对象。

self是方法接收的第一个参数,指向调用该方法的对象本身。 当你写dog.bark()时,Python自动把dog这个对象作为self传给bark()方法。self让方法能访问和修改对象自己的属性。

每个对象维护自己的属性字典__dict__。 实例属性存在对象的__dict__里,类属性存在类的__dict__里。访问属性时,Python先查对象的__dict__,再查类的__dict__。

# 详细回答

# 类与对象的关系

类是定义,对象是实例。定义类时写的代码在类体执行一次;创建对象时,会触发__new__(创建对象),然后调用__init__(初始化属性)。

class Dog:
    species = "Canis familiaris"  # 类属性
    
    def __init__(self, name):
        self.name = name  # 实例属性
    
    def bark(self):
        return f"{self.name} says: Woof!"

# 创建两个Dog对象
dog1 = Dog("Buddy")
dog2 = Dog("Max")

print(dog1.name)  # Buddy
print(dog2.name)  # Max
print(dog1.bark())  # Buddy says: Woof!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

每个对象是独立的,修改dog1.name不会影响dog2。

# self的本质

方法的第一个参数self是Python约定,用来指向调用该方法的对象。当你写dog1.bark()时,Python会把这个调用改写成Dog.bark(dog1):

class Dog:
    def bark(self):
        print(f"self is {self}")
        print(f"self.name is {self.name}")

dog = Dog()
dog.name = "Buddy"
dog.bark()
# 等价于:Dog.bark(dog)
1
2
3
4
5
6
7
8
9

这就是为什么第一个参数必须是self——它接收的是调用方的对象。self只是个约定名字,技术上可以写成其他名字,但会让代码难以理解。

# 对象的属性字典

每个对象都有一个__dict__,存放它的实例属性:

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

p = Person("Alice", 30)
print(p.__dict__)  # {'name': 'Alice', 'age': 30}

# 可以直接修改或增删属性
p.city = "Beijing"
print(p.__dict__)  # {'name': 'Alice', 'age': 30, 'city': 'Beijing'}

del p.age
print(p.__dict__)  # {'name': 'Alice', 'city': 'Beijing'}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

这是Python对象模型的灵活性:属性不是固定的,对象就像一个活字典。

# 属性查找的顺序

访问obj.attr时,Python按以下顺序查找:

  1. 对象自己的__dict__(实例属性)。
  2. 类的__dict__及其父类(类属性和方法)。
  3. 描述符协议(属性、类方法、静态方法等特殊对象)。
  4. 如果都没找到,抛出AttributeError。
class Dog:
    breed = "Mixed"  # 类属性
    
    def __init__(self, name):
        self.name = name  # 实例属性
    
    def info(self):  # 方法
        return f"{self.name} is a {self.breed}"

dog = Dog("Buddy")
print(dog.name)    # 从dog.__dict__查找
print(dog.breed)   # dog.__dict__里没有,查找Dog类
print(dog.info)    # 找到方法,返回一个绑定方法对象
1
2
3
4
5
6
7
8
9
10
11
12
13

当访问dog.info时,Python实际返回的是一个绑定方法对象,它记住了dog这个对象,所以调用dog.info()时会自动传递self。

对象属性查找与self绑定

# 为什么对象可以动态添加属性

与编译型语言不同,Python对象在运行时可以添加、修改或删除属性。这是因为属性不是在类定义时固定的结构,而是存在对象的__dict__里:

class Empty:
    pass

obj = Empty()
# 可以随时添加属性
obj.x = 10
obj.y = 20
print(obj.__dict__)  # {'x': 10, 'y': 20}

# 不同的对象可以有不同的属性
obj2 = Empty()
obj2.name = "test"
print(obj2.__dict__)  # {'name': 'test'}
1
2
3
4
5
6
7
8
9
10
11
12
13

这种灵活性很有用,但也容易出错。如果你期望对象有某个属性却没有,会抛异常。

# 知识拓展

Q1:为什么一定要在__init__里初始化属性?

你不一定非得这样做。Python允许在任何时候添加属性。但惯例是在__init__里初始化,这样别人读代码时能一眼看出对象有什么属性。如果属性分散在各个方法里添加,代码会很混乱。

Q2:如果类属性和实例属性同名会怎样?

实例属性会优先被找到。实例属性在对象的__dict__里,查找时先检查对象__dict__,再查类。

class Test:
    value = "class"

t = Test()
print(t.value)  # class,还没有实例属性
t.value = "instance"
print(t.value)  # instance,现在t.__dict__有value了
1
2
3
4
5
6
7

Q3:能不能在类定义外面直接改类属性?

可以。类也是对象,可以在运行时修改它的属性。但这样修改的是所有共享这个类的对象看到的值:

class Dog:
    species = "Canis"

print(Dog.species)  # Canis
Dog.species = "Canis familiaris"
print(Dog.species)  # Canis familiaris
1
2
3
4
5
6

Q4:__dict__里的内容可以直接修改吗?

可以,但不建议。直接操作__dict__会绕过属性访问协议(比如__getattr__、描述符等):

obj.__dict__['x'] = 100  # 直接写进字典
# vs
obj.x = 100  # 正常赋值,会触发property或descriptor
1
2
3

Q5:为什么方法的第一个参数是self而不是this?

这是Guido的设计选择。用self强调"这是方法要操作的对象",比this更明确。这样看代码时,self出现的每一个地方都能提醒你"现在在用当前对象的属性"。


下一篇:实例属性和类属性有什么区别?

Last Updated: 10/13/2026, 5:57:00 PM

← Python模块和包是什么?import是怎么工作的? 实例属性和类属性有什么区别? →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪