21.Python编程:访问权限

作者: TensorFlow开发者 | 来源:发表于2018-04-22 00:06 被阅读24次

前面一节重点学习了Python3中的面向对象最基础的类和对象的知识:类的定义、对象、构造方法、属性和方法等,在类中定义好的属性,就可以赋值、取值等一系列操作了。

例如:定义一个SmartPhone类,源码如下:

# 定义一个SmartPhone类
class SmartPhone(object):
    os = ""  # 系统
    type = ""  # 品牌
    memory = "4GB"  # 内存大小 默认单位GB

    # 构造方法
    def __init__(self, os, type, memory):
        self.os = os
        self.type = type
        self.memory = memory

    # 定义一个打印智能手机属性的方法
    def print_phone_info(self):
        print('os:', self.os, '\n品牌:', self.type, '\n内存大小:', self.memory)

创建一个SmartPhone对象,打印调用打印信息方法print_phone_info()后,再修改属性的值。但是,从前面SmartPhone类的定义来看,外部代码还是可以自由地修改一个实例的type 、memory 、os等属性的。如下:

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('---------------------')

# 修改phone1指向的对象的属性:品牌、内存
phone1.type = "MeiZu 7Pro"
phone1.memory = '8GB'
phone1.print_phone_info()

运行结果如下:

os: Android 
品牌: Galaxy 
内存大小: 6GB
---------------------
os: Android 
品牌: MeiZu 7Pro 
内存大小: 8GB

Java中是通过关键字:私有的private、公开的public、默认受保护的protected等来限制属性、方法的访问权限的。如果在Python中,想要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,即:__

私有属性

在Python中规定:实例的变量名如果以__开头,就变成了一个私有变量(private),只有类内部可以访问,类外部不能访问。

所以,我们把SmartPhone类的定义做一下修改:

# 定义一个SmartPhone类
class SmartPhone(object):
    __os = ""  # 私有属性:系统
    __type = ""  # 私有属性:品牌
    __memory = "4GB"  # 私有属性:内存大小 默认单位GB

    # 构造方法
    def __init__(self, os, type, memory):
        self.__os = os
        self.__type = type
        self.__memory = memory

    def print_phone_info(self):
        print('os:', self.__os, '\n品牌:', self.__type, '\n内存大小:', self.__memory)

创建一个SmartPhone对象,打印调用打印信息方法print_phone_info()后,再访问私有属性,会报错:AttributeError,如下:

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

# 在类的外部访问私有属性__type,会报错:AttributeError
phone1.__type

运行结果:

Traceback (most recent call last):
os: Android 
  File "F:/python_projects/oop/23SmartPhone.py", line 21, in <module>
品牌: Galaxy 
    phone1.__type
内存大小: 6GB
AttributeError: 'SmartPhone' object has no attribute '__type'

可以看到运行结果报错了,AttributeError: 'SmartPhone' object has no attribute '__type'意思是:属性错误:SmartPhone的对象没有__type属性。

这是因为我们在type属性前加了__,使__type变成了私有属性,只有类内部可以访问,类外部不能访问。

假如,我们在类的外部还想访问、修改类里面的私有属性怎么办?可能你已经想到了:给类添加访问、修改私有属性的方法!没错,修改如下:

# 定义一个SmartPhone类
class SmartPhone(object):
    __os = ""  # 私有属性:系统
    __type = ""  # 私有属性:品牌
    __memory = "4GB"  # 私有属性:内存大小 默认单位GB

    # 构造方法
    def __init__(self, os, type, memory):
        self.__os = os
        self.__type = type
        self.__memory = memory

    def print_phone_info(self):
        print('os:', self.__os, '\n品牌:', self.__type, '\n内存大小:', self.__memory)

    #  对外界提供获取__os的值的方法
    def get_os(self):
        return self.__os

    #  对外界提供设置__os的值的方法
    def set_os(self, os):
        self.__os = os

    #  对外界提供获取__type的值的方法
    def get_type(self):
        return self.__type

    #  对外界提供设置__type的值的方法
    def set_type(self, types):
        self.__type = types

    #  对外界提供获取__memory的值的方法
    def get_memory(self):
        return self.__memory

    #  对外界提供设置__memory的值的方法
    def set_memory(self, memory):
        self.__memory = memory

创建对象,在外界获取和设置属性的值如下:

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('-------------------')

# 通过提供的set方法在类的外部访问私有属性
phone1.set_type("MeiZu 7Pro")
phone1.set_memory("8GB")

# 通过提供的get方法在类的外部访问私有属性
print('外部访问:\n', phone1.get_os(), '\n', phone1.get_type(), '\n', phone1.get_memory())

运行结果:

os: Android 
品牌: Galaxy 
内存大小: 6GB
-------------------
外部访问:
 Android 
 MeiZu 7Pro 
 8GB

可以看到运行结果,在类的外部成功地获取、修改私有属性的值了。这样做,不是自找麻烦吗?那么,为什么要这样多此一举呢?这么做的意义非常大:在修改类中的属性前,可以对外界传入的数据做检查。例如:外界传入的品牌不是字符串,而是随意传入了一个整数:

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('-------------------')

phone1.set_type(2)
print(phone1.get_type())

运行结果:

os: Android 
品牌: Galaxy 
内存大小: 6GB
-------------------
2

这是未做检查的运行结果。在set_type()方法中做了数据检查,其他代码不变,更新的部分如下:

#  对外界提供设置__type的值的方法
    def set_type(self, types):
        if isinstance(types, str):
            self.__type = types
        else:
            raise ValueError(" SmartPhone type should be str!")

重新运行,运行结果:

os: Android 
Traceback (most recent call last):
品牌: Galaxy 
  File "F:/python_projects/oop/23SmartPhone.py", line 51, in <module>
内存大小: 6GB
    phone1.set_type(2)
-------------------
  File "F:/python_projects/oop/23SmartPhone.py", line 33, in set_type
    raise ValueError(" SmartPhone type should be str!")

起到了对传入的无效数据检查的作用。关于Python中异常的处理后面会学习,此处先拿来用下。raise:表示抛出异常,抛出一个ValueError的异常,并提示用户:SmartPhone type should be str!

私有方法

Python中规定,私有方法同样以两个下划线开头,声明该方法为私有方法,只能在类的内部调用,不能在类地外部调用,形如:self.__method_name

在上面的SmartPhone类中添加一个私有方法__test(),代码如下:

# 上接SmartPhone类,添加一个私有方法

    # 添加一个私有方法
    def __test(self):
        print("__test()是私有方法")

创建一个SmartPhone类型的对象,


# 创建一个SmartPhone类型的对象,并在外部调用该私有方法,
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('-------------------')
# 在外部调用该私有方法,
phone1.__test()

运行结果:

os: Android 
Traceback (most recent call last):
品牌: Galaxy 
  File "F:/python_projects/oop/23SmartPhone.py", line 55, in <module>
内存大小: 6GB
    phone1.__test()
-------------------
AttributeError: 'SmartPhone' object has no attribute '__test'

报错AttributeError: 'SmartPhone' object has no attribute '__test',意思是:属性错误:SmartPhone的对象没有__test属性

提示

需要特别注意的是,在Python中,变量名类似__xxxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量。而特殊变量是可以直接访问的,并不是私有的变量,所以我们自己在定义类中的私有属性时,千万不能用__xxxx__这样的变量名,以免混淆。

有些时候,你会看到以一个下划线开头的实例变量名,比如_xxxx,这样的实例变量外部也是可以访问的。但是,按照Python约定俗成的规定,好的习惯是,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

注意:
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。

上面例子中,不能直接访问__type是因为Python解释器对外把__type变量改成了_SmartPhone__type,所以,仍然可以通过_SmartPhone__type来访问__type变量。例如:

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('-------------------')

print(phone1._SmartPhone__os)
print(phone1._SmartPhone__type)
print(phone1._SmartPhone__memory)

运行结果:

os: Android 
品牌: Galaxy 
内存大小: 6GB
-------------------
Android
Galaxy
6GB

但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__xxxx改成不同的变量名,不一定总是_类名__xxxx

易错点举例

# 上接SmartPhone类定义

# 创建一个SmartPhone类型的对象
phone1 = SmartPhone('Android', 'Galaxy', '6GB')
phone1.print_phone_info()

print('-------------------')

# 修改phone1指向的对象的内存为"8GB"
phone1.__memory = "8GB"
print('__memory :', phone1.__memory)

print('get_memory() :', phone1.get_memory())
print('_SmartPhone__memory :', phone1._SmartPhone__memory)

从表面上看,我们在外部代码中“成功”地把"8GB"设置了__memory 变量,但实际上这个__memory变量和class内部的__memory变量不是一个变量!内部的__memory变量已经被Python解释器自动改成了_SmartPhone__memory,而外部代码给phone1新增了一个__memory变量。

运行结果:

os: Android 
品牌: Galaxy 
内存大小: 6GB
-------------------
__memory : 8GB
get_memory() : 6GB
_SmartPhone__memory : 6GB

运行结果印证了上面的话,这是一个易忽略点,要留意。

说明

类中还预定义了一些方法,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类,我们会在以后一一详细学习。

类的专有方法:
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__div__: 除运算
__mod__: 求余运算
__pow__: 乘方

小结

本文主要通过几个简单的例子来学习类中私有属性和方法,以及它们之间的区别,要熟练掌握。

如果你观察的足够仔细,你会发现,例子中我们属性只有3个,增加了3对get\set方法,也就是6个。那么,如果属性非常多时,我们上面的做法又会显得非常麻烦,这有没有好的解决方案呢?答案是有的。python中给我们提供了一些关键词@property,专门帮我们解决上面的问题,我们会在后面详细学习这些知识。


更多了解,可关注公众号:人人懂编程


微信公众号:人人懂编程

相关文章

  • 21.Python编程:访问权限

    前面一节重点学习了Python3中的面向对象最基础的类和对象的知识:类的定义、对象、构造方法、属性和方法等,在类中...

  • 2-Java访问权限

    Java访问权限 1.类的访问权限 2.抽象方法的访问权限 3.构造方法访问权限

  • Spring Aop(一)

    AOP:aspect oriented program,面向切面编程主要应用:打印日志、事务管理、权限控制、访问控...

  • Java-OOP5【摘自PPT分析篇】

    Java初级编程-面向对象编程(二)本章目标:打包,package关键字导包,import关键字继承访问权限继承中...

  • Android网络编程

    Android网络编程 访问网络需要申请权限。 请求网络并显示网页源码 布局文件 MainActivity 还有一...

  • Permission denied

    拒绝访问查看权限用户的权限 访问文件所需的权限

  • iOS 一些权限开启字段

    访问相机权限 2.访问相册权限 保存图片到相册的权限 地理位置权限 访问通讯录权限 6.麦克风权限

  • iOS权限配置

    访问相应的功能时,要在plist配置相应的权限 摄像头(相机)权限 相册权限 蓝牙权限 日历权限 访问通讯录 访问...

  • iOS各种访问权限总结

    麦克风访问(AVAudioSession) 权限查看 权限请求 相机访问(AVCaptureDevice) 权限查...

  • 6、访问权限控制(封装)

    访问权限限制等级,从大到小依次为:public, protected, 包访问权限, private访问权限的控制...

网友评论

本文标题:21.Python编程:访问权限

本文链接:https://www.haomeiwen.com/subject/sonokftx.html