卡码笔记-最强八股文
首页
计算机基础
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的实例方法、类方法和静态方法有什么区别?"

多数人会说"一个用self,一个用cls,一个什么都不用",但没说清楚为什么要这样设计。真正要讲清楚的是:实例方法需要访问对象的属性,类方法需要访问类本身(常用于工厂模式),静态方法不需要访问对象或类(只是把函数放在类的命名空间里)。 装饰器@classmethod和@staticmethod改变了方法的绑定行为。

# 简要回答

实例方法的第一个参数是self,指向调用它的对象。 定义时不加装饰器,调用时通过obj.method(),Python自动传递obj作为self。实例方法可以访问对象的实例属性和类属性。

类方法的第一个参数是cls,指向类本身。 定义时用@classmethod装饰,调用时通过Class.method()或obj.method(),Python自动传递类作为cls。类方法常用于工厂函数,根据不同参数创建对象。

静态方法没有隐式的第一个参数。 定义时用@staticmethod装饰,调用时像普通函数一样传参。静态方法不能访问实例属性或类属性,只是逻辑上属于这个类的工具函数。

# 详细回答

# 实例方法

最常见的方法,通过对象调用,自动传递对象作为self:

class Dog:
    def __init__(self, name):
        self.name = name
    
    def bark(self):  # 实例方法
        return f"{self.name} says: Woof!"

dog = Dog("Buddy")
print(dog.bark())  # Buddy says: Woof!
1
2
3
4
5
6
7
8
9

bark是实例方法,dog.bark()会被转换成Dog.bark(dog),所以self接收到dog对象。

实例方法可以访问实例属性(self.name)和类属性(self.__class__或Dog.species)。

# 类方法

通过@classmethod装饰,第一个参数是类本身:

class Person:
    population = 0
    
    def __init__(self, name):
        self.name = name
        Person.population += 1
    
    @classmethod
    def get_population(cls):  # 类方法
        return f"Total population: {cls.population}"
    
    @classmethod
    def from_birth_year(cls, name, birth_year):  # 工厂方法
        age = 2025 - birth_year
        return cls(name)  # 创建并返回对象

print(Person.get_population())  # Total population: 0
p1 = Person("Alice")
print(Person.get_population())  # Total population: 1

# 通过类方法创建对象
p2 = Person.from_birth_year("Bob", 1990)
print(p2.name)  # Bob
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

@classmethod装饰器让方法接收类作为第一个参数。调用Person.get_population()时,cls就是Person。

类方法常用于工厂模式:根据不同的输入格式创建对象,而不是只靠__init__。比如from_birth_year接收出生年份,内部计算年龄再调用cls(name)创建对象。

# 静态方法

通过@staticmethod装饰,没有隐式参数:

class MathUtils:
    @staticmethod
    def add(a, b):  # 静态方法
        return a + b
    
    @staticmethod
    def is_even(n):
        return n % 2 == 0

# 通过类调用
print(MathUtils.add(3, 5))      # 8
print(MathUtils.is_even(4))     # True

# 也可以通过对象调用,但没有意义
obj = MathUtils()
print(obj.add(1, 2))  # 3,但不会传递obj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

静态方法像普通函数,只是放在类的命名空间里。它不能访问self或cls,只能使用传入的参数。

静态方法适合工具函数,逻辑上属于这个类,但不需要访问对象或类的状态。

实例方法、类方法、静态方法的参数绑定

# 三种方法的对比

方法类型 装饰器 第一个参数 能访问 常见用途
实例方法 无 self(对象) 实例属性、类属性 操作对象状态
类方法 @classmethod cls(类) 类属性 工厂函数、类级别操作
静态方法 @staticmethod 无 无(只能用参数) 工具函数、辅助逻辑

# 为什么类方法用于工厂模式

类方法接收cls,所以可以调用cls(...)创建对象。这样做的好处是:如果有子类继承了这个类,子类调用类方法时,cls会是子类本身,返回的也是子类的对象:

class Animal:
    def __init__(self, name):
        self.name = name
    
    @classmethod
    def create(cls, name):
        return cls(name)

class Dog(Animal):
    pass

dog = Dog.create("Buddy")  # cls是Dog,返回Dog对象
print(type(dog))  # <class '__main__.Dog'>
1
2
3
4
5
6
7
8
9
10
11
12
13

如果用普通函数或静态方法,就无法自动适配子类。

# 为什么静态方法还要放在类里

静态方法不访问对象或类,为什么不直接写成模块级函数?

主要是命名空间和逻辑分组。如果有一堆跟Person相关的工具函数,放在Person类里能让代码更清晰:

class Person:
    @staticmethod
    def is_valid_age(age):
        return 0 < age < 150
    
    def __init__(self, name, age):
        if not Person.is_valid_age(age):
            raise ValueError("Invalid age")
        self.name = name
        self.age = age
1
2
3
4
5
6
7
8
9
10

is_valid_age不需要对象或类,但逻辑上属于Person的验证规则,放在类里更合理。

# 知识拓展

Q1:实例方法能通过类调用吗?

可以,但必须手动传递对象:

class Dog:
    def bark(self):
        print("Woof!")

dog = Dog()
Dog.bark(dog)  # 等价于 dog.bark()
1
2
3
4
5
6

类方法和静态方法也能通过对象调用,但没有额外好处。

Q2:类方法能访问实例属性吗?

不能直接访问。类方法的cls是类,不是对象。如果要访问实例属性,必须先创建或接收一个对象:

class Person:
    @classmethod
    def greet(cls, person):
        return f"Hello, {person.name}"

p = Person()
p.name = "Alice"
print(Person.greet(p))  # Hello, Alice
1
2
3
4
5
6
7
8

Q3:能在静态方法里调用实例方法吗?

不能直接调用,因为静态方法没有self或cls。如果需要,必须先创建对象:

class Test:
    def instance_method(self):
        return "instance"
    
    @staticmethod
    def static_method():
        obj = Test()
        return obj.instance_method()
1
2
3
4
5
6
7
8

Q4:@classmethod和@staticmethod的实现原理是什么?

它们是描述符。装饰器返回一个特殊对象,这个对象实现了__get__方法,能在属性访问时返回绑定了cls或不绑定任何参数的可调用对象。这是Python描述符协议的应用。

Q5:什么时候该用类方法而不是__init__?

当你需要多种初始化方式时。__init__只有一个签名,如果想支持"从字典创建""从JSON创建""从出生年份创建",可以用多个类方法:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    @classmethod
    def from_dict(cls, data):
        return cls(data['name'], data['age'])
    
    @classmethod
    def from_birth_year(cls, name, birth_year):
        return cls(name, 2025 - birth_year)
1
2
3
4
5
6
7
8
9
10
11
12

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

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

← 实例属性和类属性有什么区别? __new__和__init__有什么区别? →

评论

验证登录状态...

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