前面一节重点学习了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
,专门帮我们解决上面的问题,我们会在后面详细学习这些知识。
更多了解,可关注公众号:人人懂编程
微信公众号:人人懂编程
网友评论