1、私有成员变量介绍

(1)私有成员变量概念

在Python面向对象中,把类的某些属性,如果在使用的过程中,不希望被外界直接访问,就可以将该属性设置为私有的,即只有当前类持有,然后暴露给外界一个访问的函数,来实现间接的访问对象属性,这就是类中数据的封装。

如果类中的属性不想被外界直接访问,则可以在属性的前面添加两个下划线__,此时称该属性为私有属性,即私有成员变量。

封装的本质:就是属性的私有化。

(2)私有成员变量特点

只能在类的内部被直接访问,在外界不能直接访问。

(3)私有成员变量体验

1)属性不被私有化情况:

# 1.属性不私有化的时候
class Student():
def __init__(self, name, age):
self.name = name
self.age = age def tellMe(self):
print(f"大家好,我是{self.name},年龄{self.age}") # 创建对象
stu = Student("孙悟空", 18) # 通过对象.成员函数,调用函数并访问对象中的成员变量
stu.tellMe() # 通过对象.属性,直接访问对象中的属性
print(f"大家好,我是{stu.name},年龄{stu.age}") # 通过对象直接访问对象的属性,并给属性赋值
stu.name = "齐天大圣"
print(stu.name) # 齐天大圣 """
输出结果:
大家好,我是孙悟空,年龄18
大家好,我是孙悟空,年龄18
齐天大圣 可以看到都可以访问到。
"""

2)属性被私有化情况:

# 2.属性私有化的时候
class Student():
def __init__(self, name, age):
self.name = name
# 私有化age属性
self.__age = age def tellMe(self):
print(f"大家好,我是{self.name},年龄{self.__age}") # 创建对象
stu = Student("孙悟空", 18) # 通过对象.成员函数,调用函数并访问对象中的成员变量
# 可以访问当对象中的私有成员变量
# 输出:大家好,我是孙悟空,年龄18
stu.tellMe() # 通过对象.属性,直接访问对象中的属性
# 报错:
# AttributeError: 'Student' object has no attribute '__age'
# print(f"大家好,我是{stu.name},年龄{stu.__age}") # 直接通过对象.属性,修改成员变量属性值
# 可以
stu.name = "齐天大圣"
print(stu.name) # 齐天大圣
# 结果:大家好,我是齐天大圣,年龄18
stu.tellMe() # 直接通过对象.属性,修改私有成员变量属性值
# 输出了结果
stu.__age = 30
print(stu.__age) # 30
# 结果:大家好,我是齐天大圣,年龄18
# 但是通过调用对象中的方法,查看对象的私有属性
# 结果并没有变化,还是18
stu.tellMe() """
但是我们通过__dict__属性查看stu对象的所有成员:
{'name': '齐天大圣', '_Student__age': 18, '__age': 30}
可以看到我们并没有修改原有的属性'_Student__age': 18,
而是给stu对象新添加了一个属性 '__age': 30。
所以说我们并没有对私有成员变量age重新赋值成功。
只有 '_Student__age': 18为什么指的是私有变量的age,
我们下面的私有成员原理就会讲解。
"""
print(stu.__dict__)

说明:双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问

2、属性私有化工作原理

class Student():
def __init__(self, name, age):
self.name = name
# 私有化成员属性
self.__age = age def tellMe(self):
print(f"大家好,我是{self.name},年龄{self.__age}") """
其实隐藏(私有化)属性只不过是Python自动为属性改了一个名字
实际上是将名字修改为了,_类名__属性名
比如 __age -> _Student__name,
也就是在原有的变量名前边加上了 _类名。
""" # 创建对象
stu = Student("孙悟空", 18)
# 结果:大家好,我是孙悟空,年龄18
stu.tellMe() # 直接通过对象.属性,修改对象的私有成员变量
# 通过下面的打印结果可以看到,修改成功了
stu._Student__age = 30
# 结果:大家好,我是孙悟空,年龄30
stu.tellMe()

总结:

Python中,并没有 真正意义私有,实际是对成员变量的名称做了一些特殊处理,使得外界无法访问到。

所以定义为双下划线__开头的属性,实际上依然可以在外部访问。

但平时我们不建议这么访问私有属性。

3、定义成员变量的标识符规范

  • xxx:普通变量。
  • _xxx:使用_开头的属性为受保护的变量,没有特殊需要不要修改。
  • __xxx:使用双_开头的属性私有变量,在外界不能直接被访问。
  • __xxx__:系统的内置变量。
  • xx_:单后置下划线,用于避免与Python关键词的冲突。

示例:

class Student():
def __init__(self, name, age, gender):
# 在变量的前面添加一个下划线,属于特殊变量,则认为该变量受保护的
self._name = name # 在变量的前添加双下划线。表示定义私有变量。
# 特点:对象不能直接使用
self.__age = age # 在变量的前后各添加两个下划线,属于特殊变量,一般认为这种变量都是系统的内置变量或者内置函数
# 特点:在类的外面也可以直接访问,但不建议使用
self.__gender__ = gender stu = Student("唐僧", 66, "男")
print(stu._name) # 唐僧
print(stu.__gender__) # 男

4、私有成员变量的获取和设置方式

(1)方式:

如何获取(修改)对象中的私有属性?

需要提供一个getter()setter()方法使外部可以访问到属性。

  • getter()方法用来获取对象中的指定属性。

    getter()方法的规范命名为get_属性名

  • setter()方法用来设置对象中的指定属性。

    setter()方法的规范命名为set_属性名

(2)格式:

getter()方法:会有一个返回值。

    def get_xxx(self):
return self.属性名

setter()方法:没有返回值,但是方法多一个参数。

def set_xxx(self, 形参名称):
self.属性名 = 形参名称的值

(3)示例:

class Student():
def __init__(self, name, age):
# 普通变量
self.name = name
# 私有变量
self.__age = age def tellMe(self):
print(f"大家好,我是{self.name},年龄{self.__age}") def get_name(self):
"""
get_name()用来获取对象的name属性
"""
return self.name def set_name(self, name):
"""
set_name()用来设置对象的name属性
"""
self.name = name def get_age(self):
return self.__age def set_age(self, age):
if age > 0:
self.__age = age # 创建对象
stu = Student("孙悟空", 18)
# 输出结果:大家好,我是孙悟空,年龄18
stu.tellMe() # 修改属性值
stu.set_name("齐天大圣")
stu.set_age(30) # 打印属性值
# 结果都是:大家好,我是齐天大圣,年龄30
stu.tellMe()
print(f"大家好,我是{stu.get_name()},年龄{stu.get_age()}") """
私有属性只能在类内部使用,对象不能直接使用,但是我们可以通过在类内部定义公有方法对私有属性进行调用或修改,然后对象在调用这个公有方法使用
"""

(4)总结:

  • 不管是普通方法和私有方法都可以使用getter()方法和setter()方法来获取或设置属性值,我们日常开发中也经常是这么编程的。
  • 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性。
  • 增加了getter()方法和setter()方法,很好的控制的属性是否是只读的,

    如果希望属性是只读的,则可以直接去掉setter()方法,

    如果希望属性不能被外部访问,则可以直接去掉getter()方法。
  • 使用setter()方法设置属性,可以增加数据的验证,确保数据的值是正确的,如:
        def set_age(self, age):
    if age > 0:
    self.__age = age
  • 同理使用getter()方法获取属性时,或者使用setter()方法设置属性时,可以在读取属性和修改属性的同时,对数据做一些其他的处理。

『无为则无心』Python面向对象 — 51、私有成员变量(类中数据的封装)的更多相关文章

  1. 『无为则无心』Python面向对象 — 55、多层继承和继承中的私有成员

    目录 1.Python支持多层继承 (1)多层继承实现 (2)多层继承和多重继承区别 2.继承中的私有成员 (1)继承中父类私有属性和私有方法 (2)获取和修改私有属性值 1.Python支持多层继承 ...

  2. 『无为则无心』Python面向对象 — 45、面向对象编程

    目录 1.面向对象编程的概念 2.面向对象编程和面向过程编程的区别 (1)面向过程编程 (2)面向对象编程 3.举例理解面向对象 4.Python的面向对象编程 5.面向对象的几大核心特性 1.面向对 ...

  3. 『无为则无心』Python面向对象 — 46、类和对象

    目录 1.理解类和对象 2.类 3.对象 4.Python中的对象 5.类和对象的定义 (1)定义类 (2)创建对象 (3)练习 6.拓展:isinstance() 函数 1.理解类和对象 (1)类和 ...

  4. 『无为则无心』Python面向对象 — 52、私有成员方法(类中行为的封装)

    Python对于类的成员没有严格的访问控制限制,这与其他面向对象的编程语言是有所区别的. 关于私有方法其实和私有属性差不多,有如下要点: 1.通常我们约定,两个下划线开头的方法是私有方法. 2.类内部 ...

  5. 『无为则无心』Python面向对象 — 53、对Python中封装的介绍

    目录 1.继承的概念 2.继承的好处 3.继承体验 4.单继承 5.多继承 1.继承的概念 在Python中,如果两个类存在父子级别的继承关系,子类中即便没有任何属性和方法,此时创建一个子类对象,那么 ...

  6. 『无为则无心』Python面向对象 — 47、Python中的self详解

    目录 1.self的作用 2.self的使用注意事项 (1)self代表类的实例,而非类 (2)self不必非写成self,只是一种规范. (3)类中方法的形参中一定要写self,包括内置函数 (4) ...

  7. 『无为则无心』Python面向对象 — 54、重写和super()函数

    目录 1.重写 2.super()函数 方式一 方式二 __mro__内置类属性说明 1.重写 在子类中如果有和父类同名的方法,则通过子类实例去调用该方法时,会调用子类中的该方法而不是父类的方法,这个 ...

  8. 『无为则无心』Python面向对象 — 58、类方法和静态方法

    目录 1.实例方法 2.类方法 (1)类方法特点 (2)类方法使用场景 3.静态方法 (1)静态方法特点 (2)静态方法使用场景 1.实例方法 实例方法既可以调用静态方法也可以调用类方法. # 定义一 ...

  9. 『无为则无心』Python面向对象 — 59、魔法方法

    目录 1.魔法方法__new__() 2.魔法方法__init__() 3.魔法方法__del__() 4.魔法方法__str__()和__repr__() 5.魔法方法__call__() 6.魔法 ...

随机推荐

  1. CSS命名规范整理

    基于网易NEC修改后,整理的命名规范 单行写完一个选择器定义 便于选择器的寻找和阅读,也便于插入新选择器和编辑,便于模块等的识别.去除多余空格,使代码紧凑减少换行. 如果有嵌套定义,可以采取内部单行的 ...

  2. HTTP协议层面绕过WAF

    最近也是在一直看过waf相关的资料,本次主要是想写写HTTP协议层面过WAF的一些技巧,来与大家一同探讨 原理 给服务器发送payload数据包,使得waf无法识别出payload,当apache,t ...

  3. Python 为什么不设计 do-while 循环结构?

    在某些编程语言中,例如 C/C++.C#.PHP.Java.JavaScript 等等,do-while 是一种基本的循环结构. 它的核心语义是:先执行一遍循环体代码,然后执行一遍条件语句,若条件语句 ...

  4. LaTex 中圆圈序号及一些特殊字符的输入

    众所周知,LATEX 提供了 \textcircled 命令用以给字符加圈,但效果却不怎么好: 实际上,加圈并不是一个平凡的变换,它会涉及到圈内字符形状的微调,而这是几乎无法在 TEX 宏层面解决的. ...

  5. GeoServer课程规划

    "凡事豫则立,不豫则废." --西汉·戴圣<礼记·中庸> 为了做好GeoServer课程培训,需要拟定一个课程目录,对整个课程做一个宏观上的规划.有了这个规划,就有了目 ...

  6. Android开发----Button组件的使用与练习

    Button 学习目标: 文字大小.颜色 自定义背景形状 自定义按压效果 点击事件 创建一个新的Activity以增加控件 1.文字大小.颜色 直接在xml文件中定义即可 <Button and ...

  7. 题解 - 「MLOI」小兔叽

    小兔叽 \(\texttt{Link}\) 简单题意 有 \(n\) 个小木桩排成一行,第 \(i\) 个小木桩的高度为 \(h_i\),分数为 \(c_i\). 如果一只小兔叽在第 \(i\) 个小 ...

  8. NOIP PJ/CSP-J 题目选做

    1. luoguP7074 [CSP-J2020] 方格取数 2. luoguP5662 [CSP-J2019] 纪念品 3. luoguP2671 [NOIP2015 普及组] 求和 4. luog ...

  9. 微信小程序之多选功能

    思路:把向得到的数组中添加一个布尔值,默认都为false,然后通过数组的映射功能把选中的布尔值,存储到数组中,在组件属性中,用三元运算符做判断即可 data:{ sampleArray: [{ id: ...

  10. KMP 入门

    再次学习 \(\rm KMP\) 后不一样的理解. 一些概念 定义字符串 \(S\) 的真 前/后 缀为非自身的 前/后 缀. 定义字符串 \(S\) 的 \(border\) 为 \(S\) 的公共 ...