类和对象

类(class):相当于一张蓝图或模板

对象(object):根据蓝图造出来的具体实物

类:

定义:class(#关键字#) 类名称:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BlogPost:
# 1. 构造方法(初始化函数):当创建具体文章时,自动调用
def __init__(self, title, date, content=""):
self.title = title # 属性:标题
self.date = date # 属性:日期
self.content = content # 属性:内容
self.is_published = False # 属性:是否发布(默认 False)

# 2. 方法(函数):文章能做什么事情
def publish(self):
self.is_published = True
print(f"✅ 文章《{self.title}》已发布!")

def show_info(self):
print(f"📄 标题:{self.title}")
print(f"📅 日期:{self.date}")
print(f"📌 状态:{'已发布' if self.is_published else '草稿'}")

对象(实例化):

定义:对象名称 = 类名称(属性1,属性2….)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建第一篇具体文章
post1 = BlogPost("Python基础温习", "2026-07-11", "今天学习了 Git 重命名...")
# 创建第二篇具体文章
post2 = BlogPost("Hexo部署心得", "2026-07-10")

# 调用对象的方法
post1.show_info()
# 输出:📄 标题:Python基础温习 | 📅 日期:2026-07-11 | 📌 状态:草稿

post1.publish()
# 输出:✅ 文章《Python基础温习》已发布!

post2.show_info()
# 输出:📄 标题:Hexo部署心得 | 📅 日期:2026-07-10 | 📌 状态:草稿

类的核心三大特性:

1.封装:把数据和操作数据的方法打包在一起,藏在内部细节。只需调用,无需关心内部如何修改。

2.继承:子类可以继承父类的遗产。

1
2
3
4
5
6
7
8
9
10
class DiaryPost(BlogPost):  # 继承 BlogPost
def __init__(self, title, date, mood): # 子类可以新增属性
super().__init__(title, date) # 调用父类初始化
self.mood = mood # 新增“心情”属性

def show_mood(self):
print(f"今天心情:{self.mood}")

diary = DiaryPost("今日复盘", "2026-07-11", "😊 开心")
diary.publish() # 可以直接使用父类的方法

3.多态:不同类可以有同名的方法。子类可以重写(覆盖)自己的方法,程序会自动调用正确的那个。

self:它是实例自身的引用。

__init__:不是构造方法,它是“初始化方法”,对象已经创建好内存后才调用它来赋值。

类名建议大写

属性定义

1,单下划线开头_(“保护”属性/约定俗成)

​ 写法:

1
self._name

含义:这是一个约定内部使用的属性,请不要在类外部直接访问

本质:Python解释器不会做任何修改,外部依然可以强行访问到它。

1
2
3
4
5
6
7
class BlogPost:
def __init__(self, title):
self._title = title # 约定为内部使用
self._draft = True

post = BlogPost("Python基础")
print(post._title) # 可以访问,输出:Python基础(但编辑器可能会提示警告)

建议:如果你只是不想让外部随便改,用_就够了,它主要起提醒作用。

2.双下划线开头——(真正的”私有”/名称修饰)

写法:

1
self.__name

含义:Python会强制把属性名称改成(下划线)类名(下划线)属性名,这叫名称修饰,目的防止子类意外覆盖父类的属性。

本质:外部无法直接通过原名访问,但如果知道修饰后的名字,依然能强行调用(所以也不算绝对安全,只是“防君子不防小人”)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BlogPost:
def __init__(self, title):
self.__title = title # 私有属性
self.__content = ""

def publish(self):
print(f"发布:{self.__title}") # 类内部可以正常访问

post = BlogPost("Python基础")

# 直接访问会报错 AttributeError
# print(post.__title)

# 但可以这样强行访问(知道改名规则后)
print(post._BlogPost__title) # 输出:Python基础

3.双下划线开头和结尾(双下划线)XXX(双下划线)(魔法方法/特殊属性)

写法:

1
self.__dict__,__init__

含义:这是Python内置的特殊方法或属性,不是私有属性。

建议:千万不要自定义这种名字的属性,这是Python内部保留的命名空间。

最佳结合@property控制访问权限:

在实际开发中,最标准的做法是:把属性定为“私有”(用开头(单下划线)或(双下划线)),然后通过@property装饰器提供自读访问,通过@属性名.setter提供可控修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class BlogPost:
def __init__(self, title):
self.__title = title # 私有属性

# 1. 提供一个只读的 getter(像访问普通属性一样)
@property
def title(self):
return self.__title

# 2. 提供一个可选的 setter(如果允许修改)
@title.setter
def title(self, new_title):
if len(new_title) > 0:
self.__title = new_title
else:
print("❌ 标题不能为空")

# 使用示例
post = BlogPost("Git入门")
print(post.title) # 输出:Git入门(像属性一样访问,不需要加括号)

post.title = "Git进阶" # 调用 setter
print(post.title) # 输出:Git进阶

post.title = "" # 输出:❌ 标题不能为空(setter 拦截了非法操作)

对比表:

写法 外部访问情况 用途 推荐程度
self.name 直接完全公开 普通公有属性 不涉及隐私时使用
self._name 可以访问(但会被 IDE 警告) 约定内部使用,子类可用 常用,大多数场景够用
self.__name 无法直接访问(会报错) 强制防止子类意外覆盖 防止继承冲突时使用
@property 像属性一样调用,但经过方法处理 对私有属性做读取/写入拦截 最推荐,既安全又优雅

现代python语法糖:

@dataclass(数据类):不用写冗长的init和repr,自动帮你生成。

1
2
3
4
5
6
7
8
9
10
from dataclasses import dataclass

@dataclass
class BlogPost:
title: str
content: str = "" # 默认值
is_published: bool = False

p = BlogPost("Git入门") # 自动有了 __init__
print(p) # 自动有了好看的 __repr__

slots(内存优化):默认每个对象有个dict字典存属性,费内存。用slots固定属性名,能省大量内存(适合创建成千上万个对象)。

1
2
class BlogPost:
__slots__ = ('title', 'content') # 只允许这两个属性,省内存