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

1 区域

2 公有属性

3 受保护属性

4 私有属性

注意:

1 - Python并没有真正的私有化支持,但是, 可以使用下划线完成伪私有的效果

2 - 类属性(方法)和实例属性(方法)遵循相同的规则

伪私有:即还是可以通过其他(如:_类名__属性名)方式进行访问或修改

1 各种区域的划分及理解

c7f6ecf07fbc

各种区域

2 公有属性访问权限

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

c7f6ecf07fbc

访问权限

类内部、子类内部、模块内部测试

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:一个下划线修饰的,受保护属性

c7f6ecf07fbc

类内部、子类内部、模块内部测试

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:两个下划线修饰的,私有属性

c7f6ecf07fbc

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__)

使用私有属性目的:

防止外界直接访问

防止被子类同名称属性覆盖

私有属性的应用场景

通过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

上述例子解决了

让所有实例都具有一个有默认值的"属性"(只能通过方法访问)

对赋值数据进行了过滤操作

实践小提示:

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

5 添加下划线的规范

xx_ :"变量名_" 这个格式是为了与系统属性作区分

__xx__ :"两端带__" 一般为系统内置属性或方法, 所以以后命名注意避免

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值