Skip to content

类与对象

函数把一段逻辑收起来,类把一组数据和操作这些数据的函数收在一起。比如"文章"有标题、作者、内容这些数据,还有发布、撤回、统计字数这些操作——用类把它们打包成一个整体,比散在变量和函数里更清晰。

类是模板,对象是根据模板造出来的实例。Article 是类,article1 article2 是两个具体的对象。

一、定义类

python
class Article:
    """文章类。"""

    def __init__(self, title, author):
        """初始化方法,创建对象时自动调用。"""
        self.title = title   # 实例属性
        self.author = author
        self.status = "草稿"  # 默认值

    def publish(self):
        """发布文章。"""
        if self.status == "草稿":
            self.status = "已发布"
            print(f"{self.title} 已发布")
        else:
            print(f"{self.title} 已经是 {self.status},无法重复发布")

    def withdraw(self):
        """撤回文章。"""
        if self.status == "已发布":
            self.status = "草稿"
            print(f"{self.title} 已撤回")
        else:
            print(f"{self.title} 当前状态是 {self.status},无法撤回")

class Article: 定义一个类,名字用驼峰命名(每个单词首字母大写)。__init__ 是初始化方法,创建对象时自动调用——self.title = title 把传入的 title 存到对象的属性里。

self 是对象自己self.title 是这个对象自己的 title 属性,self.publish() 是调用这个对象自己的 publish 方法。这个概念一开始容易绕:self 不是 Python 关键字,是约定俗成的参数名,表示"当前对象"。

二、创建对象

python
article1 = Article("Python 入门", "张三")
article2 = Article("Go 并发", "李四")

print(article1.title)    # Python 入门
print(article2.status)    # 草稿

article1.publish()        # Python 入门 已发布
article1.publish()        # Python 入门 已经是 已发布,无法重复发布

article2.withdraw()       # Go 并发 当前状态是 草稿,无法撤回

Article("Python 入门", "张三") 创建一个对象,__init__ 被调用,titleauthor 存进对象。article1.publish() 调用这个对象的 publish 方法,方法里 self.status 就是 article1 自己的 status 属性。

每个对象有自己的一套属性——article1.statusarticle2.status 互不影响,改一个不会影响另一个。

三、属性

属性就是存在对象上的变量。实例属性是每个对象各自独立的一份:

python
class Contact:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone


c1 = Contact("张三", "13800138000")
c2 = Contact("李四", "13900139000")

print(c1.name)  # 张三
print(c2.name)  # 李四

c1.namec2.name 是两个不同的值,各改各的。

还有一类类属性——所有对象共享,定义在类里、方法外:

python
class Contact:
    # 类属性
    default_country = "中国"

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


c1 = Contact("张三", "13800138000")
c2 = Contact("李四", "13900139000")

print(c1.default_country)  # 中国
print(c2.default_country)  # 中国

# 改类属性会影响所有对象
Contact.default_country = "美国"
print(c1.default_country)  # 美国
print(c2.default_country)  # 美国

类属性用得不多,但要知道有这个概念——大部分数据还是放实例属性,因为每个对象自己管自己的数据更清晰。

四、方法

定义在类里的函数叫方法。实例方法第一个参数是 self,能访问对象的属性和其他方法:

python
class Article:
    def __init__(self, title, author, content=""):
        self.title = title
        self.author = author
        self.content = content
        self.status = "草稿"

    def word_count(self):
        """统计文章字数。"""
        return len(self.content)

    def preview(self, max_length=50):
        """生成文章预览。"""
        if len(self.content) <= max_length:
            return self.content
        return self.content[:max_length] + "..."


article = Article("Python 入门", "张三", "Python 是一门很好学的编程语言...")
print(article.word_count())  # 14
print(article.preview(10))   # Python 是一门很...

word_countpreview 都是实例方法,第一个参数是 self,调用时不用传——article.word_count() 自动把 article 作为 self 传进去。

还有一种类方法,用 @classmethod 装饰,第一个参数是 cls(类本身):

python
class Article:
    # 类属性
    article_count = 0

    def __init__(self, title, author):
        self.title = title
        self.author = author
        self.status = "草稿"
        Article.article_count += 1  # 每创建一个对象,计数加 1

    @classmethod
    def get_count(cls):
        """返回已创建的文章总数。"""
        return cls.article_count


a1 = Article("Python 入门", "张三")
a2 = Article("Go 并发", "李四")

print(Article.get_count())  # 2

类方法用得少,主要用在"创建对象总数的统计""工厂方法"这类场景——日常写类,99% 都是实例方法

五、私有属性

有些属性不希望外部直接访问或修改,可以用两个下划线开头:

python
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner
        self.__balance = balance  # 私有属性

    def deposit(self, amount):
        """存款。"""
        if amount > 0:
            self.__balance += amount
            print(f"存入 {amount},余额 {self.__balance}")

    def get_balance(self):
        """查询余额。"""
        return self.__balance


account = BankAccount("张三", 1000)
account.deposit(500)  # 存入 500,余额 1500

# 直接访问私有属性会报错
# print(account.__balance)  # AttributeError
print(account.get_balance())  # 1500

__balance 是私有属性,类外部无法直接访问 account.__balance,只能通过 depositget_balance 操作。

这个私有是"约定上的私有",不是真正的禁止访问——Python 里没有真正的私有属性,account._BankAccount__balance 还是能绕过去。但两个下划线是一个信号:告诉使用者"别直接碰这个属性,用我提供的方法来操作"。

六、组合

对象可以包含其他对象,这叫组合

python
class Author:
    def __init__(self, name, email):
        self.name = name
        self.email = email


class Article:
    def __init__(self, title, author):
        self.title = title
        self.author = author  # author 是一个 Author 对象

    def show_author(self):
        print(f"作者:{self.author.name}{self.author.email})")


author = Author("张三", "zhangsan@example.com")
article = Article("Python 入门", author)
article.show_author()  # 作者:张三(zhangsan@example.com)

Articleauthor 属性是一个 Author 对象。组合比继承更常用——"文章有作者"用组合,"作者是人"才用继承。

类什么时候用?当数据和方法有天然的一对多关系时。比如文章有标题、作者、内容、状态这些数据,还有发布、撤回、统计字数这些操作——数据和操作明显绑定在一起,用类就很自然。如果只是几个零散函数,不一定要硬套类。