python中函数和方法的区别

Python 中函数和方法的区别详解

1. 什么是函数和方法

1.1 函数(Function)的定义

函数是独立存在的代码块,它不属于任何类或对象。函数可以接收参数,执行特定任务,并返回结果。

特点

  • 独立定义,不依赖于类
  • 可以直接调用
  • 可以放在模块的任何位置
  • 通常用于执行通用操作

1.2 方法(Method)的定义

方法是定义在类内部的函数,它属于某个类或对象。方法需要通过类或对象来调用。

特点

  • 必须定义在类内部
  • 需要通过类或对象调用
  • 可以访问类的属性和其他方法
  • 通常用于操作对象的数据

1.3 核心区别总结

特性 函数(Function) 方法(Method)
定义位置 类外部 类内部
调用方式 直接调用 通过类或对象调用
第一个参数 普通参数 通常是 self(实例方法)
访问权限 无法直接访问类属性 可以访问类属性和实例属性
独立性 独立存在 依赖于类

2. 函数的详细讲解

2.1 函数的基本定义

函数使用 def 关键字定义,语法如下:

def 函数名(参数1, 参数2, ...):
    """函数文档字符串"""
    函数体
    return 返回值  # 可选

2.2 函数示例

示例 1:简单的函数

# 定义一个简单的函数
def greet(name):
    """向某人打招呼"""
    return f"Hello, {name}!"

# 直接调用函数
result = greet("Alice")
print(result)  # 输出: Hello, Alice!

示例 2:带多个参数的函数

# 定义计算两个数之和的函数
def add(a, b):
    """计算两个数的和"""
    return a + b

# 调用函数
result = add(3, 5)
print(result)  # 输出: 8

# 可以传入不同的参数
result2 = add(10, 20)
print(result2)  # 输出: 30

示例 3:无返回值的函数

# 函数不一定需要返回值
def print_info(name, age):
    """打印个人信息"""
    print(f"姓名: {name}")
    print(f"年龄: {age}")

# 调用函数
print_info("张三", 25)
# 输出:
# 姓名: 张三
# 年龄: 25

示例 4:带默认参数的函数

def greet(name, greeting="Hello"):
    """打招呼,可以自定义问候语"""
    return f"{greeting}, {name}!"

# 使用默认参数
result1 = greet("Alice")
print(result1)  # 输出: Hello, Alice!

# 自定义参数
result2 = greet("Bob", "Hi")
print(result2)  # 输出: Hi, Bob!

2.3 函数的调用方式

函数可以直接通过函数名调用,不需要任何前缀:

def calculate_area(length, width):
    """计算矩形面积"""
    return length * width

# 直接调用
area = calculate_area(5, 3)
print(area)  # 输出: 15

2.4 函数的作用域

函数内部定义的变量是局部变量,外部无法直接访问:

def my_function():
    local_var = "这是局部变量"
    print(local_var)

my_function()  # 输出: 这是局部变量
# print(local_var)  # 错误!无法访问局部变量

3. 方法的详细讲解

3.1 方法的基本定义

方法定义在类内部,语法如下:

class 类名:
    def 方法名(self, 参数1, 参数2, ...):
        """方法文档字符串"""
        方法体
        return 返回值  # 可选

重要:实例方法的第一个参数必须是 self(约定俗成,可以改成其他名字,但不推荐)。

3.2 实例方法(Instance Method)

实例方法是最常见的方法类型,需要通过对象实例来调用。

示例 1:简单的实例方法

class Person:
    def greet(self, name):
        """打招呼的方法"""
        return f"Hello, {name}! I am a person."

# 创建对象
person = Person()

# 通过对象调用方法
result = person.greet("Alice")
print(result)  # 输出: Hello, Alice! I am a person.

注意:虽然方法定义时第一个参数是 self,但调用时不需要传入 self,Python 会自动传入。

示例 2:访问实例属性

class Person:
    def __init__(self, name, age):
        """初始化方法(构造方法)"""
        self.name = name  # 实例属性
        self.age = age     # 实例属性

    def introduce(self):
        """自我介绍的方法"""
        return f"我是 {self.name},今年 {self.age} 岁。"

# 创建对象
person = Person("张三", 25)

# 调用方法
info = person.introduce()
print(info)  # 输出: 我是 张三,今年 25 岁。

示例 3:方法修改实例属性

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        """存款方法"""
        self.balance += amount
        return f"存款 {amount} 元,当前余额: {self.balance} 元"

    def withdraw(self, amount):
        """取款方法"""
        if amount <= self.balance:
            self.balance -= amount
            return f"取款 {amount} 元,当前余额: {self.balance} 元"
        else:
            return "余额不足!"

# 创建账户
account = BankAccount("Alice", 1000)

# 调用方法
print(account.deposit(500))   # 输出: 存款 500 元,当前余额: 1500 元
print(account.withdraw(200))   # 输出: 取款 200 元,当前余额: 1300 元
print(account.withdraw(2000)) # 输出: 余额不足!

3.3 类方法(Class Method)

类方法使用 @classmethod 装饰器,第一个参数是 cls(代表类本身)。

class Person:
    count = 0  # 类属性

    def __init__(self, name):
        self.name = name
        Person.count += 1

    @classmethod
    def get_count(cls):
        """类方法:获取创建的对象数量"""
        return cls.count

    @classmethod
    def create_from_string(cls, info):
        """类方法:从字符串创建对象"""
        name = info.split(",")[0]
        return cls(name)

# 使用类方法
print(Person.get_count())  # 输出: 0

person1 = Person("Alice")
person2 = Person("Bob")

print(Person.get_count())  # 输出: 2

# 通过类方法创建对象
person3 = Person.create_from_string("Charlie,25")
print(person3.name)  # 输出: Charlie

3.4 静态方法(Static Method)

静态方法使用 @staticmethod 装饰器,不需要 selfcls 参数。

class MathUtils:
    @staticmethod
    def add(a, b):
        """静态方法:加法"""
        return a + b

    @staticmethod
    def multiply(a, b):
        """静态方法:乘法"""
        return a * b

# 可以通过类调用
result1 = MathUtils.add(3, 5)
print(result1)  # 输出: 8

# 也可以通过对象调用
utils = MathUtils()
result2 = utils.multiply(4, 6)
print(result2)  # 输出: 24

3.5 方法的调用方式

方法必须通过类或对象来调用:

class Calculator:
    def add(self, a, b):
        return a + b

# 方式1:通过对象调用(推荐)
calc = Calculator()
result = calc.add(3, 5)
print(result)  # 输出: 8

# 方式2:通过类调用(需要手动传入self)
result2 = Calculator.add(calc, 3, 5)
print(result2)  # 输出: 8

4. 函数和方法的详细对比

4.1 定义位置对比

函数:定义在类外部

# 函数定义在类外部
def calculate_area(length, width):
    """计算面积的函数"""
    return length * width

class Rectangle:
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def get_area(self):
        """获取面积的方法"""
        # 可以在方法内部调用函数
        return calculate_area(self.length, self.width)

# 函数可以直接调用
area = calculate_area(5, 3)
print(area)  # 输出: 15

# 方法需要通过对象调用
rect = Rectangle(5, 3)
area2 = rect.get_area()
print(area2)  # 输出: 15

方法:定义在类内部

class Calculator:
    # 方法定义在类内部
    def add(self, a, b):
        """加法方法"""
        return a + b

    def subtract(self, a, b):
        """减法方法"""
        return a - b

# 方法必须通过对象调用
calc = Calculator()
result = calc.add(10, 5)
print(result)  # 输出: 15

4.2 参数对比

函数:普通参数

# 函数的参数就是普通参数
def greet(name, age):
    return f"Hello, {name}! You are {age} years old."

# 调用时直接传入参数
result = greet("Alice", 25)
print(result)  # 输出: Hello, Alice! You are 25 years old.

方法:第一个参数是 self

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

    # 方法的第一个参数是 self
    def greet(self, other_name):
        return f"Hello, {other_name}! I am {self.name}, {self.age} years old."

# 创建对象
person = Person("Bob", 30)

# 调用方法时,不需要传入 self
# Python 会自动将 person 对象作为 self 传入
result = person.greet("Alice")
print(result)  # 输出: Hello, Alice! I am Bob, 30 years old.

4.3 访问属性对比

函数:无法直接访问类属性

# 函数无法直接访问类的属性
class Person:
    species = "Homo sapiens"  # 类属性

    def __init__(self, name):
        self.name = name

# 函数无法直接访问 Person 的属性
def get_species():
    # return Person.species  # 可以,但需要明确指定类名
    # return self.species     # 错误!函数没有 self
    pass

# 函数需要接收对象作为参数
def get_person_name(person):
    """函数需要接收对象才能访问属性"""
    return person.name

person = Person("Alice")
name = get_person_name(person)
print(name)  # 输出: Alice

方法:可以直接访问类属性和实例属性

class Person:
    species = "Homo sapiens"  # 类属性

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

    def introduce(self):
        """方法可以直接访问类属性和实例属性"""
        return f"我是 {self.name},属于 {self.species}"

person = Person("Bob")
info = person.introduce()
print(info)  # 输出: 我是 Bob,属于 Homo sapiens

4.4 完整对比示例

# ========== 函数示例 ==========
def calculate_total(price, quantity):
    """计算总价的函数"""
    return price * quantity

# 函数可以直接调用
total = calculate_total(10, 5)
print(f"总价: {total}")  # 输出: 总价: 50

# ========== 方法示例 ==========
class ShoppingCart:
    def __init__(self):
        self.items = []

    def add_item(self, name, price, quantity):
        """添加商品的方法"""
        item = {
            'name': name,
            'price': price,
            'quantity': quantity
        }
        self.items.append(item)

    def calculate_total(self):
        """计算购物车总价的方法"""
        total = 0
        for item in self.items:
            # 方法可以访问 self.items
            total += item['price'] * item['quantity']
        return total

# 方法需要通过对象调用
cart = ShoppingCart()
cart.add_item("苹果", 5, 3)
cart.add_item("香蕉", 3, 2)

total = cart.calculate_total()
print(f"购物车总价: {total}")  # 输出: 购物车总价: 21

5. self 参数详解

5.1 什么是 self

self 是实例方法的第一个参数,它代表当前对象的引用。当你通过对象调用方法时,Python 会自动将对象本身作为第一个参数传入。

5.2 self 的作用

作用 1:访问实例属性

class Person:
    def __init__(self, name, age):
        self.name = name  # 使用 self 定义实例属性
        self.age = age

    def get_info(self):
        # 使用 self 访问实例属性
        return f"姓名: {self.name}, 年龄: {self.age}"

person = Person("Alice", 25)
info = person.get_info()
print(info)  # 输出: 姓名: Alice, 年龄: 25

作用 2:调用其他方法

class Calculator:
    def __init__(self):
        self.result = 0

    def add(self, value):
        """加法方法"""
        self.result += value
        return self

    def multiply(self, value):
        """乘法方法"""
        self.result *= value
        return self

    def get_result(self):
        """获取结果方法"""
        return self.result

    def reset(self):
        """重置方法,调用其他方法"""
        self.result = 0
        # 可以通过 self 调用其他方法
        return self.get_result()

calc = Calculator()
calc.add(5).multiply(3)
print(calc.get_result())  # 输出: 15
print(calc.reset())       # 输出: 0

作用 3:区分不同对象的属性

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner      # 每个对象的 owner 不同
        self.balance = balance  # 每个对象的 balance 不同

    def deposit(self, amount):
        """存款"""
        self.balance += amount
        return f"{self.owner} 的账户存入 {amount} 元,余额: {self.balance} 元"

# 创建两个不同的账户
account1 = BankAccount("Alice", 1000)
account2 = BankAccount("Bob", 500)

# self 确保每个对象操作自己的属性
print(account1.deposit(200))  # 输出: Alice 的账户存入 200 元,余额: 1200 元
print(account2.deposit(100))  # 输出: Bob 的账户存入 100 元,余额: 600 元

5.3 self 的命名规则

虽然可以使用其他名称(如 thisme 等),但强烈建议使用 self,这是 Python 的约定。

class Person:
    def __init__(this, name):  # 可以使用其他名字,但不推荐
        this.name = name

    def greet(this):  # 可以使用其他名字,但不推荐
        return f"Hello, {this.name}!"

# 虽然可以工作,但不推荐
person = Person("Alice")
print(person.greet())  # 输出: Hello, Alice!

# 推荐写法
class Person:
    def __init__(self, name):  # 使用 self
        self.name = name

    def greet(self):  # 使用 self
        return f"Hello, {self.name}!"

5.4 self 的调用机制

class Example:
    def method(self, value):
        print(f"self 是: {self}")
        print(f"value 是: {value}")

obj = Example()

# 方式1:通过对象调用(推荐)
# Python 会自动将 obj 作为 self 传入
obj.method("test")
# 输出:
# self 是: <__main__.Example object at 0x...>
# value 是: test

# 方式2:通过类调用(不推荐,但可以)
# 需要手动传入 self(即 obj)
Example.method(obj, "test")
# 输出相同

6. 实际应用场景

6.1 何时使用函数

函数适合用于:

  • 通用工具函数:不依赖于特定对象
  • 独立的功能:可以独立完成的任务
  • 数据处理:对数据进行转换、计算等

示例:工具函数

# 工具函数:格式化日期
def format_date(year, month, day):
    """格式化日期为字符串"""
    return f"{year}-{month:02d}-{day:02d}"

# 工具函数:验证邮箱格式
def is_valid_email(email):
    """验证邮箱格式"""
    return "@" in email and "." in email.split("@")[1]

# 工具函数:计算平均值
def calculate_average(numbers):
    """计算数字列表的平均值"""
    if not numbers:
        return 0
    return sum(numbers) / len(numbers)

# 使用函数
date_str = format_date(2024, 3, 15)
print(date_str)  # 输出: 2024-03-15

print(is_valid_email("test@example.com"))  # 输出: True
print(is_valid_email("invalid"))           # 输出: False

avg = calculate_average([1, 2, 3, 4, 5])
print(avg)  # 输出: 3.0

6.2 何时使用方法

方法适合用于:

  • 对象的行为:操作对象的数据
  • 封装:将数据和操作数据的方法放在一起
  • 状态管理:维护对象的状态

示例:对象方法

class Email:
    def __init__(self, sender, recipient, subject, body):
        self.sender = sender
        self.recipient = recipient
        self.subject = subject
        self.body = body
        self.sent = False

    def send(self):
        """发送邮件的方法"""
        if not self.sent:
            self.sent = True
            return f"邮件已发送:从 {self.sender} 到 {self.recipient}"
        else:
            return "邮件已经发送过了"

    def get_info(self):
        """获取邮件信息的方法"""
        status = "已发送" if self.sent else "未发送"
        return f"主题: {self.subject}, 状态: {status}"

# 使用方法
email = Email("alice@example.com", "bob@example.com", "问候", "你好!")
print(email.get_info())  # 输出: 主题: 问候, 状态: 未发送
print(email.send())      # 输出: 邮件已发送:从 alice@example.com 到 bob@example.com
print(email.get_info())  # 输出: 主题: 问候, 状态: 已发送

6.3 函数和方法结合使用

在实际项目中,函数和方法经常结合使用:

# ========== 函数:通用工具 ==========
def validate_email(email):
    """验证邮箱格式的函数"""
    return "@" in email and "." in email.split("@")[1]

def format_message(sender, recipient, content):
    """格式化消息的函数"""
    return f"From: {sender}nTo: {recipient}nContent: {content}"

# ========== 类和方法:对象操作 ==========
class User:
    def __init__(self, name, email):
        if not validate_email(email):  # 使用函数验证
            raise ValueError("无效的邮箱格式")
        self.name = name
        self.email = email
        self.messages = []

    def send_message(self, recipient, content):
        """发送消息的方法"""
        if not validate_email(recipient.email):  # 使用函数验证
            return "收件人邮箱无效"

        # 使用函数格式化消息
        message = format_message(self.email, recipient.email, content)
        recipient.messages.append(message)
        return "消息已发送"

    def get_message_count(self):
        """获取消息数量的方法"""
        return len(self.messages)

# 使用
user1 = User("Alice", "alice@example.com")
user2 = User("Bob", "bob@example.com")

user1.send_message(user2, "你好!")
print(user2.get_message_count())  # 输出: 1

7. 常见混淆点和误区

7.1 误区 1:认为函数和方法是一样的

错误理解

# 有人认为这样定义的就是方法
def my_function():
    pass

class MyClass:
    def my_function(self):
        pass

正确理解

  • my_function()函数,可以直接调用
  • MyClass.my_function()方法,需要通过对象调用

示例

# 函数
def add(a, b):
    return a + b

# 方法
class Calculator:
    def add(self, a, b):
        return a + b

# 函数调用
result1 = add(3, 5)  # 直接调用
print(result1)  # 输出: 8

# 方法调用
calc = Calculator()
result2 = calc.add(3, 5)  # 通过对象调用
print(result2)  # 输出: 8

7.2 误区 2:不理解 self 的作用

错误理解

class Person:
    def __init__(self, name):
        name = name  # 错误!没有使用 self

person = Person("Alice")
print(person.name)  # 错误!AttributeError

正确理解

class Person:
    def __init__(self, name):
        self.name = name  # 正确!使用 self 保存为实例属性

person = Person("Alice")
print(person.name)  # 正确!输出: Alice

详细示例

class Counter:
    def __init__(self):
        count = 0  # 错误!这是局部变量,不是实例属性

    def increment(self):
        count += 1  # 错误!无法访问 count
        return count

# 正确写法
class Counter:
    def __init__(self):
        self.count = 0  # 正确!使用 self 创建实例属性

    def increment(self):
        self.count += 1  # 正确!使用 self 访问实例属性
        return self.count

counter = Counter()
print(counter.increment())  # 输出: 1
print(counter.increment())  # 输出: 2

7.3 误区 3:在函数中尝试使用 self

错误示例

def my_function(self, value):  # 错误!函数不应该有 self 参数
    return self.value + value

正确示例

# 如果需要在函数中操作对象,应该将对象作为参数传入
def process_value(obj, value):
    """函数接收对象作为参数"""
    return obj.value + value

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

    def add(self, other_value):
        """方法可以直接使用 self"""
        return self.value + other_value

obj = MyClass(10)
result1 = process_value(obj, 5)  # 函数调用
result2 = obj.add(5)              # 方法调用
print(result1, result2)  # 输出: 15 15

7.4 误区 4:混淆类方法和实例方法

错误理解

class Person:
    name = "Default"  # 类属性

    def get_name(self):
        return self.name  # 这访问的是实例属性,不是类属性

person = Person()
person.name = "Alice"  # 创建了实例属性
print(person.get_name())  # 输出: Alice
print(Person.name)        # 输出: Default

正确理解

class Person:
    species = "Homo sapiens"  # 类属性

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

    def get_name(self):
        """实例方法:访问实例属性"""
        return self.name

    def get_species(self):
        """实例方法:访问类属性"""
        return self.species  # 或 Person.species

    @classmethod
    def get_species_class(cls):
        """类方法:访问类属性"""
        return cls.species

person = Person("Alice")
print(person.get_name())           # 输出: Alice(实例属性)
print(person.get_species())         # 输出: Homo sapiens(类属性)
print(Person.get_species_class())   # 输出: Homo sapiens(类方法)

7.5 误区 5:认为所有类中的函数都是方法

错误理解

class MyClass:
    def regular_function():  # 缺少 self,这不是方法
        return "This is not a method"

正确理解

class MyClass:
    # 这是静态方法,不是实例方法
    @staticmethod
    def static_method():
        return "This is a static method"

    # 这是实例方法
    def instance_method(self):
        return "This is an instance method"

# 静态方法可以通过类或对象调用
result1 = MyClass.static_method()
obj = MyClass()
result2 = obj.static_method()

# 实例方法必须通过对象调用
result3 = obj.instance_method()

8. 深入理解:函数和方法的本质

8.1 函数是对象

在 Python 中,函数也是对象,可以赋值、传递:

def greet(name):
    return f"Hello, {name}!"

# 函数可以赋值给变量
my_function = greet
print(my_function("Alice"))  # 输出: Hello, Alice!

# 函数可以作为参数传递
def apply_function(func, value):
    return func(value)

result = apply_function(greet, "Bob")
print(result)  # 输出: Hello, Bob!

8.2 方法也是函数

方法本质上也是函数,只是绑定到了对象上:

class Person:
    def greet(self, name):
        return f"Hello, {name}!"

person = Person()

# 方法也是函数对象
print(type(person.greet))  # 输出: <class 'method'>

# 可以获取原始函数
print(type(Person.greet))  # 输出: <class 'function'>

# 通过类访问得到的是函数
func = Person.greet
result = func(person, "Alice")  # 需要手动传入 self
print(result)  # 输出: Hello, Alice!

8.3 绑定方法(Bound Method)

class Calculator:
    def add(self, a, b):
        return a + b

calc = Calculator()

# 通过对象访问得到的是绑定方法
bound_method = calc.add
print(bound_method)  # 输出: <bound method Calculator.add of <__main__.Calculator object at ...>>

# 绑定方法已经绑定了 self,调用时不需要再传入
result = bound_method(3, 5)
print(result)  # 输出: 8

# 通过类访问得到的是未绑定方法(函数)
unbound_method = Calculator.add
print(unbound_method)  # 输出: <function Calculator.add at ...>

# 未绑定方法需要手动传入 self
result2 = unbound_method(calc, 3, 5)
print(result2)  # 输出: 8

9. 实际项目示例

9.1 完整的用户管理系统

这个示例展示了函数和方法在实际项目中的使用:

# ========== 工具函数 ==========
def validate_email(email):
    """验证邮箱格式的函数"""
    return "@" in email and "." in email.split("@")[1]

def hash_password(password):
    """加密密码的函数(简化版)"""
    return f"hashed_{password}"

def format_user_info(user):
    """格式化用户信息的函数"""
    return f"用户: {user.name} ({user.email})"

# ========== 用户类 ==========
class User:
    def __init__(self, name, email, password):
        if not validate_email(email):  # 使用函数验证
            raise ValueError("无效的邮箱格式")

        self.name = name
        self.email = email
        self.password_hash = hash_password(password)  # 使用函数加密
        self.is_active = True

    def change_password(self, old_password, new_password):
        """修改密码的方法"""
        if hash_password(old_password) != self.password_hash:
            return "原密码错误"

        self.password_hash = hash_password(new_password)
        return "密码修改成功"

    def deactivate(self):
        """停用账户的方法"""
        self.is_active = False
        return "账户已停用"

    def activate(self):
        """激活账户的方法"""
        self.is_active = True
        return "账户已激活"

    def get_info(self):
        """获取用户信息的方法"""
        status = "活跃" if self.is_active else "停用"
        return f"{self.name} ({self.email}) - 状态: {status}"

# ========== 用户管理类 ==========
class UserManager:
    def __init__(self):
        self.users = []

    def register(self, name, email, password):
        """注册用户的方法"""
        # 使用函数验证
        if not validate_email(email):
            return "邮箱格式无效"

        # 检查邮箱是否已存在
        for user in self.users:
            if user.email == email:
                return "邮箱已被注册"

        # 创建用户
        user = User(name, email, password)
        self.users.append(user)
        return "注册成功"

    def find_user(self, email):
        """查找用户的方法"""
        for user in self.users:
            if user.email == email:
                return user
        return None

    def list_all_users(self):
        """列出所有用户的方法"""
        if not self.users:
            return "暂无用户"

        # 使用函数格式化
        user_list = [format_user_info(user) for user in self.users]
        return "n".join(user_list)

# ========== 使用示例 ==========
manager = UserManager()

# 注册用户
print(manager.register("Alice", "alice@example.com", "password123"))
print(manager.register("Bob", "bob@example.com", "password456"))

# 列出所有用户
print("n所有用户:")
print(manager.list_all_users())

# 查找并操作用户
user = manager.find_user("alice@example.com")
if user:
    print(f"n{user.get_info()}")
    print(user.deactivate())
    print(user.get_info())

9.2 购物车系统

# ========== 工具函数 ==========
def calculate_discount(price, discount_rate):
    """计算折扣后的价格"""
    return price * (1 - discount_rate)

def format_currency(amount):
    """格式化货币"""
    return f"¥{amount:.2f}"

# ========== 商品类 ==========
class Product:
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock

    def apply_discount(self, discount_rate):
        """应用折扣的方法"""
        self.price = calculate_discount(self.price, discount_rate)
        return f"{self.name} 已应用 {discount_rate*100}% 折扣"

    def get_info(self):
        """获取商品信息的方法"""
        return f"{self.name} - {format_currency(self.price)} (库存: {self.stock})"

# ========== 购物车类 ==========
class ShoppingCart:
    def __init__(self):
        self.items = {}  # {商品对象: 数量}

    def add_item(self, product, quantity):
        """添加商品到购物车的方法"""
        if product.stock < quantity:
            return f"库存不足,当前库存: {product.stock}"

        if product in self.items:
            self.items[product] += quantity
        else:
            self.items[product] = quantity

        return f"已添加 {quantity} 个 {product.name}"

    def remove_item(self, product):
        """从购物车移除商品的方法"""
        if product in self.items:
            del self.items[product]
            return f"已移除 {product.name}"
        return "商品不在购物车中"

    def get_total(self):
        """计算购物车总价的方法"""
        total = 0
        for product, quantity in self.items.items():
            total += product.price * quantity
        return total

    def checkout(self):
        """结账的方法"""
        total = self.get_total()
        # 使用函数格式化
        return f"结账成功!总价: {format_currency(total)}"

# ========== 使用示例 ==========
# 创建商品
product1 = Product("苹果", 5.0, 100)
product2 = Product("香蕉", 3.0, 50)

# 应用折扣
print(product1.apply_discount(0.1))  # 10% 折扣
print(product1.get_info())

# 创建购物车
cart = ShoppingCart()
cart.add_item(product1, 3)
cart.add_item(product2, 2)

print(cart.checkout())

10. 最佳实践建议

10.1 何时使用函数

使用函数的场景

  1. 通用工具函数:不依赖于特定对象的功能
  2. 数据处理:对数据进行转换、验证、格式化
  3. 算法实现:独立的计算逻辑
  4. 辅助功能:支持多个类使用的功能

示例

# ✅ 好的函数设计
def validate_phone(phone):
    """验证手机号格式"""
    return len(phone) == 11 and phone.isdigit()

def format_date(date):
    """格式化日期"""
    return date.strftime("%Y-%m-%d")

def calculate_tax(amount, rate):
    """计算税费"""
    return amount * rate

10.2 何时使用方法

使用方法的场景

  1. 对象行为:操作对象的数据
  2. 状态管理:修改或查询对象状态
  3. 封装:将相关数据和操作组织在一起
  4. 对象交互:对象之间的交互

示例

# ✅ 好的方法设计
class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance

    def deposit(self, amount):
        """存款方法:修改对象状态"""
        self.balance += amount

    def withdraw(self, amount):
        """取款方法:修改对象状态"""
        if amount <= self.balance:
            self.balance -= amount
            return True
        return False

    def get_balance(self):
        """查询余额方法:查询对象状态"""
        return self.balance

10.3 命名规范

函数命名

  • 使用小写字母和下划线
  • 动词开头,描述功能
  • 示例:calculate_total(), validate_email(), format_date()

方法命名

  • 使用小写字母和下划线
  • 动词开头,描述行为
  • 示例:get_name(), set_age(), send_message()

对比示例

# 函数命名
def calculate_total(items):
    pass

def validate_user_input(data):
    pass

# 方法命名
class ShoppingCart:
    def calculate_total(self):
        pass

    def add_item(self, item):
        pass

    def remove_item(self, item):
        pass

10.4 代码组织建议

建议 1:将通用函数放在模块顶层

# utils.py - 工具函数模块
def validate_email(email):
    pass

def format_currency(amount):
    pass

# user.py - 用户类模块
from utils import validate_email, format_currency

class User:
    def __init__(self, email):
        if not validate_email(email):
            raise ValueError("Invalid email")
        self.email = email

建议 2:将相关方法组织在类中

class FileManager:
    def __init__(self, filename):
        self.filename = filename

    def read(self):
        """读取文件的方法"""
        pass

    def write(self, content):
        """写入文件的方法"""
        pass

    def delete(self):
        """删除文件的方法"""
        pass

10.5 避免常见错误

错误 1:在函数中使用 self

# ❌ 错误
def my_function(self, value):
    return self.value + value

# ✅ 正确
def my_function(obj, value):
    return obj.value + value

错误 2:在方法中忘记使用 self

class Person:
    def __init__(self, name):
        name = name  # ❌ 错误:应该是 self.name = name

    def get_name(self):
        return name  # ❌ 错误:应该是 return self.name

错误 3:混淆函数和方法的作用

# ❌ 不好的设计:将应该作为方法的功能写成函数
def update_user_balance(user, amount):
    user.balance += amount

# ✅ 好的设计:将功能作为方法
class User:
    def update_balance(self, amount):
        self.balance += amount

11. 总结

11.1 核心区别回顾

特性 函数(Function) 方法(Method)
定义位置 类外部 类内部
第一个参数 普通参数 self(实例方法)
调用方式 函数名() 对象.方法名()
访问属性 需要接收对象作为参数 可以直接访问 self.属性
独立性 独立存在 依赖于类
使用场景 通用工具、数据处理 对象行为、状态管理

11.2 记忆要点

  1. 函数 = 独立的代码块,可以直接调用
  2. 方法 = 类中的函数,需要通过对象调用
  3. self = 方法的第一个参数,代表当前对象
  4. 函数用于通用功能,方法用于对象操作

11.3 快速判断方法

判断是函数还是方法

  • 如果定义在类外部函数
  • 如果定义在类内部方法
  • 如果第一个参数是 self实例方法
  • 如果有 @classmethod类方法
  • 如果有 @staticmethod静态方法(本质上是函数)

11.4 学习建议

  1. 多练习:通过实际编码加深理解
  2. 多对比:对比函数和方法的异同
  3. 理解 self:理解 self 的作用是理解方法的关键
  4. 实际应用:在实际项目中体会何时使用函数,何时使用方法

附录:快速参考

函数定义模板

def 函数名(参数1, 参数2, ...):
    """函数文档"""
    函数体
    return 返回值

方法定义模板

class 类名:
    def 方法名(self, 参数1, 参数2, ...):
        """方法文档"""
        方法体
        return 返回值

调用方式对比

# 函数调用
result = 函数名(参数1, 参数2)

# 方法调用
对象 = 类名()
result = 对象.方法名(参数1, 参数2)

通过本文档的学习,你应该已经全面理解了 Python 中函数和方法的区别。记住:函数是独立的,方法是属于类的。在实际编程中,根据具体需求选择合适的工具,会让你的代码更加清晰和高效!

祝你编程愉快!🎉

发表评论