Python基础18-面向对象(属性限制-公有私有)

1 区域
2 公有属性
3 受保护属性
4 私有属性

  • 注意:
    1 - Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果
    2 - 类属性(方法)和实例属性(方法)遵循相同的规则
    伪私有:即还是可以通过其他(如:_类名__属性名)方式进行访问或修改

1 各种区域的划分及理解

各种区域

2 公有属性访问权限

x:没有下划线修饰的,公有属性

访问权限
  • 类内部、子类内部、模块内部测试
class Animal:
    x = 10
    def test(self):
        print(Animal.x)
        print(self.x)
    pass


class Dog(Animal):
    def test2(self):
        print(Dog.x)
        print(self.x)
    pass


# 测试在类的内部访问
a = Animal()
a.test()

# 测试在子类内部访问
d = Dog()
d.test2()

# 测试在模块内访问 - 类访问:通过父类(Animal) 或 派生类访问(Dog)
print(Animal.x)
print(Dog.x)

# 测试在模块内访问 - 实例访问:通过父类(a) 或 派生类访问(d)
print(a.x)
print(d.x)

  • 跨模块测试 (通过公有变量测试,而公有变量与公有属性的区别是是否有数组)
# 文件1.py 代码
a = 666

# 文件2.py 代码
import 1  # 通过这样的导入方式,需要使用 模块名.xx 来访问
print(1.a) # 666

或者

from 1 import *
pirnt(a) # 666

3 受保护属性访问权限

_x:一个下划线修饰的,受保护属性

  • 类内部、子类内部、模块内部测试
class Animal:
    _x = 10
    def test(self):
        print(Animal._x)
        print(self._x)
    pass


class Dog(Animal):
    def test2(self):
        print(Dog._x)
        print(self._x)
    pass


# 测试在类的内部访问
a = Animal()
a.test()

# 测试在子类内部访问
d = Dog()
d.test2()

# 测试在模块内访问 - 类访问:通过父类(Animal) 或 派生类访问(Dog)
print(Animal._x)
print(Dog._x)

# 测试在模块内访问 - 实例访问:通过父类(a) 或 派生类访问(d)
print(a._x)
print(d._x)

  • 跨模块测试 (通过公有变量测试,而公有变量与公有属性的区别是是否有数组)
# 文件1.py 代码
_a = 666

# 文件2.py 代码
import 1  # 通过这样的导入方式,需要使用 模块名.xx 来访问
print(1._a) # 666

或者

from 1 import *
pirnt(_a) # error

  • 注意,如果_a 被 __all__修饰的话,则通过 from 模块名 import *方式导入也是可以访问的。
# 文件1 中 模块内其他位置
__all__ = ["_a"]
_a = 666


# 文件2 模块内访问
from 1 import *
pirnt(_a) # 666

4 私有属性

  • __x:两个下划线修饰的,私有属性
class Animal:
   __x = 10
    def test(self):
        print(Animal.__x)
        print(self.__x)
    pass


class Dog(Animal):
    def test2(self):
        print(Dog.__x)
        print(self.__x)
    pass


# 测试在类的内部访问
a = Animal()
a.test()

# 测试在子类内部访问
d = Dog()
d.test2()

# 测试在模块内访问 - 类访问:通过父类(Animal) 或 派生类访问(Dog)
print(Animal.__x)
print(Dog.__x)

# 测试在模块内访问 - 实例访问:通过父类(a) 或 派生类访问(d)
print(a.__x)
print(d.__x)

  • 跨模块测试 (通过公有变量测试,而公有变量与公有属性的区别是是否有数组)
# 文件1.py 代码
__a = 666

# 文件2.py 代码
import 1  # 通过这样的导入方式,需要使用 模块名.xx 来访问
print(1.__a) # 666

或者

from 1 import *
pirnt(__a) # error

  • 注意,如果__a 被 __all__修饰的话,则通过 from 模块名 import *方式导入也是可以访问的。
# 文件1 中 模块内其他位置
__all__ = ["__a"]
__a = 666


# 文件2 模块内访问
from 1 import *
pirnt(__a) # 666

  • 私有属性的跨模块访问规则,参照单下划线开头变量的访问原则

私有属性的实现机制

  • 实际是通过:名字重整(Name Mangling),即重改 __x 为另外一个名称, 如
    _类名__x
# 可通过__dict__类属性查看
print(Animal.__dict__)
  • 使用私有属性目的:
    1. 防止外界直接访问
    2. 防止被子类同名称属性覆盖

私有属性的应用场景

  • 通过Person类实例化的对象都拥有一个 age属性,且具有一个默认值
class Person:
    # 主要作用, 当我们创建好一个实例对象之后, 会自动的调用这个方法, 来初始化这个对象
    def __init__(self):
        #此时的 age 是添加到对应的实例里面的,也就是 age 是类实例属性,Person 内没有 age 类属性
        self.age = 18

p1 = Person()
p2 = Person()
p3 = Person()

print(p1.age) # 18
print(p2.age) # 18
print(p3.age) # 18
  • 为避免将错误的数据赋值给实例.age
p1.age = -10
  • 我们需要将 age 属性保护 起来,让实例对象不能直接访问age属性。
# 通过私有实例属性保护age -> __age
class Person:
    def __init__(self):
        # 此时的 __age 会被编译器执行名字重整 name mangling,通过print(p1.__dict__) 打印结果是: {'_Person__age': 18}
        self.__age = 18

p1 = Person()
print(p1.age) # error,因为 age 已经被名字重整了,除非你通过 p1._Person__age进行访问,但这个访问方式不稳定,这是编译器特性
  • 通过实例方法对私有实例属性 age进行访问,同时对传入的数据进行数据过滤
class Person:
    def __init__(self):
        self.__age = 18

    def setAge(self, value):
        if isinstance(value, int) and 0 < value < 200:
            self.__age = value
        else:
            print("你输入的数据有问题, 请重新输入")

    def getAge(self):
        return self.__age # 这里能够通过__age访问是因为在类的内部

p1 = Person()
print(p1.getAge()) # 18

p1.setAge(10)
print(p1.getAge()) # 10

  • 上述例子解决了
  1. 让所有实例都具有一个有默认值的"属性"(只能通过方法访问)
  2. 对赋值数据进行了过滤操作

实践小提示:
在不明白属性所在位置或是否有name mangling时候,多通过__dict__进行打印查证

5 添加下划线的规范

xx_ :"变量名_" 这个格式是为了与系统属性作区分
__xx__ :"两端带__" 一般为系统内置属性或方法, 所以以后命名注意避免

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,215评论 4 16
  • “学习学习再学习!” 这是李笑来老师提出来的口号,也是他的一个公众号的名称。 把学习当成一件终身的事情。最重要的是...
    我的真谛阅读 472评论 0 0
  • 在刚刚过去的春节假期,国内电影票房再破纪录,春节档电影票房达67亿元,成为史上最“旺”春节档。其中三部电影票房破1...
    电影侃爷阅读 226评论 0 1
  • 作者的话:作者第一次写长篇,所以非常期待各位读者的评价和建议。整个故事还没有完结,所以可能会参照文章反响更改情节哦...
    ShellyGwendolyn阅读 144评论 0 0
  • 大家早上好!今天1月28日,星期日,农历腊月十二。 在我们的生活与工作中,不论结局,我们都应该学会感恩相遇。这些年...
    Kingofcool阅读 355评论 0 3