欢迎光临
我们一直在努力

python基础:opp的结构+公私接口+property与getter方法详解

一、opp的结构

对于一个来说,他有的结构是:

属性:类属性和实习属性

方法:实例方法、类方法、静态方法、特殊方法

class man:
# 类属性
# 类属性是所有实例共享的属性,定义在类中,方法外
# 类属性可以通过类名或实例名访问
# 类属性可以在类中直接访问,也可以在方法中通过self访问
# 类属性可以在类中直接修改,也可以在方法中通过self修改
# 类属性可以在类中直接删除,也可以在方法中通过self删除
# 类属性可以在类中直接查看,也可以在方法中通过self查看
# 类属性可以在类中直接赋值,也可以在方法中通过self赋值
# 类属性可以在类中直接调用,也可以在方法中通过self调用
# 类属性可以在类中直接定义,也可以在方法中通过self定义
# 类属性可以在类中直接初始化,也可以在方法中通过self初始化
# 类属性可以在类中直接访问,也可以在方法中通过self访问
# 类属性可以在类中直接修改,也可以在方法中通过self修改
sex="男"
id=0

#创建类对象时,自动调用__init__方法(需要上传name,age值)(实例属性)
def __init__(self,name,age):
self.name=name
self.age=age

#实例方法
# 实例方法是定义在类中的方法,第一个参数必须为 self
# 实例方法可以通过实例名调用,也可以通过类名调用
# 实例方法可以访问类属性,也可以访问实例属性
# 实例方法可以修改类属性,也可以修改实例属性
def change_name(self,a,b):
self.name=a+b
return self.name

# 特殊方法

# 特殊的方法,打印后会输出它(魔术方法)
def __str__(self):
return f"姓名:{self.name},年龄:{self.age},性别:{self.sex},ID:{self.id}"

#类方法
# 类方法是定义在类中的方法,第一个参数必须为 cls
# 类方法可以通过类名调用,也可以通过实例名调用
# 类方法可以访问类属性,也可以访问实例属性
# 类方法可以修改类属性,也可以修改实例属性
@classmethod
#classmethod
def change_sex(cls):
return cls.sex

# 类方法可以修改类属性,也可以修改实例属性
@classmethod
def change_id(cls,new_id):
cls.id=new_id
return cls.id

#静态方法
# 静态方法是定义在类中的方法,第一个参数必须为 cls
# 静态方法可以通过类名调用,也可以通过实例名调用
# 静态方法不能访问类属性,也不能访问实例属性
# 静态方法不能修改类属性,也不能修改实例属性
@staticmethod
def change_name(a,b):
return a+b

#私有方法
# 私有方法是定义在类中的方法,方法名以双下划线开头
# 私有方法只能在类中直接调用,不能在类外直接调用
# 私有方法可以访问类属性,也可以访问实例属性
# 私有方法可以修改类属性,也可以修改实例属性
def __change_name(self,a,b):
return a+b

zs=man("张三",18)
print(zs)
#输出姓名:张三,年龄:18,性别:男,ID:0
#这里起作用的是__str__方法

二、公私接口

1.概念总览

概念 定义方式 作用
公共接口 无下划线开头的方法/属性 对外提供的功能接口
私有接口 双下划线 __ 开头的方法/属性 类内部使用,不对外暴露

2.定义与命名约定

Python通过 命名约定 区分接口的访问权限:

命名形式 类型 访问权限 示例
name 公共属性/方法 类内外均可直接访问 person.name
_name 受保护属性/方法 建议仅类内部使用(可外部访问) person._name (不推荐)
__name 私有属性/方法 仅类内部可直接访问 person.__name (外部报错)
__name__ 特殊方法/属性 Python内置,类内外均可访问 person.__str__()

3.私有接口的实现原理

Python对双下划线开头的名称进行 名称修饰 (name mangling):

– 实际存储为: _类名__属性名
– 目的:避免子类与父类的私有属性命名冲突

class Person:
def __init__(self):
self.__age = 25 # 私有属性

# 内部实际存储为:_Person__age
p = Person()
# print(p.__age) # AttributeError
print(p._Person__age) # 输出:25(不推荐这样访问)

三、Getter方法的两种实现方式

1. 传统Getter方法(手动定义)

手动定义获取属性的方法,通常以 get_ 开头:

class Person:
def __init__(self, name, age):
self.__name = name # 私有属性
self.__age = age # 私有属性

# 公共接口:传统getter方法
def get_name(self):
"""获取姓名"""
return self.__name

def get_age(self):
"""获取年龄"""
return self.__age

# 公共接口:传统setter方法
def set_age(self, age):
"""设置年龄(带验证)"""
if age < 0 or age > 150:
#异常处理,如果年龄小于0大于150返回下放错误提示
raise ValueError("年龄必须在0-150之间")
self.__age = age

# 使用
p = Person("张三", 25)
print(p.get_name()) # 输出:张三
p.set_age(26)
print(p.get_age()) # 输出:26

 2. 使用@property装饰器(推荐)

将方法转换为 属性访问方式 (无需括号),更简洁直观:

class Person:
def __init__(self, name, age):
self._name = name # 受保护属性
self._age = age # 受保护属性

# 公共接口:property装饰器实现getter方法
@property
def name(self):
"""姓名属性(只读)"""
print("[GET] 获取姓名")
return self._name

@property
def age(self):
"""年龄属性(可读写)"""
print("[GET] 获取年龄")
return self._age

# 配套的setter方法(可选)
@age.setter
def age(self, value):
print("[SET] 设置年龄")
if value < 0 or value > 150:
raise ValueError("年龄必须在0-150之间")
self._age = value

# 使用
p = Person("张三", 25)
print(p.name) # 输出:[GET] 获取姓名 \\n 张三(无需括号)
p.age = 26 # 输出:[SET] 设置年龄
print(p.age) # 输出:[GET] 获取年龄 \\n 26

3.两者区别

特性 传统getter方法 @property 装饰器
调用方式 obj.get_name() obj.name (属性访问)
代码简洁性 较繁琐 更简洁直观
向后兼容性 需要修改调用代码 无需修改已有代码
只读属性实现 不定义setter方法 仅定义 @property ,不定义setter
类型提示友好度 一般 优秀(IDE可识别为属性)

作者有话说:首先我发现的不同,传统的与新的对比:

命名规则不同,新的接口更加明显,命名更加简单

四、实战案例:用户管理系统

 1. 需求分析

设计一个用户类,需要:

– 存储用户的姓名、邮箱、密码(加密)
– 提供安全的属性访问方式
– 实现密码加密存储
– 验证邮箱格式

2. 完整实现代码

import hashlib
import re

class User:
def __init__(self, username, email, password):
self._username = username # 受保护属性
self._email = email # 受保护属性
self._password = self._encrypt_password(password) # 私有属性,存储加密密码

# 私有方法:密码加密(内部使用)
def _encrypt_password(self, password):
"""对密码进行MD5加密"""
return hashlib.md5(password.encode()).hexdigest()

# 私有方法:邮箱验证(内部使用)
def _validate_email(self, email):
"""验证邮箱格式是否正确"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None

# 公共接口:用户名(只读)
@property
def username(self):
return self._username

# 公共接口:邮箱(可读写,带验证)
@property
def email(self):
return self._email

@email.setter
def email(self, value):
if not self._validate_email(value):
raise ValueError("邮箱格式不正确")
self._email = value

# 公共接口:密码(只写,带加密)
@property
def password(self):
"""密码属性(只写,不允许读取)"""
raise AttributeError("密码不允许直接读取")

@password.setter
def password(self, value):
self._password = self._encrypt_password(value)

# 公共方法:验证密码
def verify_password(self, password):
"""验证输入的密码是否正确"""
encrypted = self._encrypt_password(password)
return encrypted == self._password

# 字符串表示
def __str__(self):
return f"User(username='{self._username}', email='{self._email}')"

五、总结

1. 何时使用哪种方式?

– 简单属性 :直接使用公共属性(如 name )
– 需要控制访问的属性 :使用 @property 装饰器
– 内部辅助功能 :使用私有方法(如 _encrypt_password )
– 只读属性 :仅定义 @property ,不定义setter方法
– 需要验证的属性 :同时定义 @property 和 @xxx.setter

2. 注意事项

– 不要过度封装 :简单的属性无需使用 @property
– 遵循命名约定 :私有属性使用双下划线,受保护属性使用单下划线
– 提供清晰的文档字符串 :为 @property 装饰的方法添加文档,说明属性的用途和访问权限
– 避免在getter/setter中做耗时操作 :这些方法可能被频繁调用,会影响性能

3. 常见误区

– 误解 __name 的安全性 :它只是一种命名约定,不是真正的私有(仍可通过 _类名__name 访问)
– 滥用 @property :简单属性无需使用,会增加代码复杂度
– 忘记验证输入 :在setter方法中一定要验证输入数据的合法性

赞(0)
未经允许不得转载:171主机测评 » python基础:opp的结构+公私接口+property与getter方法详解
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址