动态添加属性和方法、访问私有属性、运算符重载
参考教程:
Python面向对象提升与收发邮件04
Python面向对象提升与收发邮件05
Python面向对象提升与收发邮件06
动态给实例添加属性和方法
- 体现了动态语言的特点(灵活)
- 给一个对象添加的属性和方法对其他对象无影响
- 动态添加属性
- 例如
class Person(object): # 创建类
pass
per = Person() # 实例化对象
# 动态添加属性
per.name = "Tom"
print(per.name)
结果为:
Tom
- 动态添加方法
- 需要导入types模块中的MethodType
from types import MethodType
class Person(object): # 创建类
pass
per = Person() # 实例化对象
# 动态添加方法
def say(self): # 要添加的方法
print("my name is", self.name)
per.speak = MethodType(say, per) # 相当于偏函数
per.speak() # 执行speak()函数
结果为:
my name is Tom
- 思考:如果我们想要限制实例动态添加的属性或方法怎么办?比如,只允许给对象添加name, age, height, weight属性和speak方法
解决:定义类的时候,定义一个特殊的属性__slots__
,可以限制动态添加的属性或方法。若动态添加了限制之外的属性或方法会报错
例如:
from types import MethodType
class Person(object): # 创建类
__slots__ = ("name", "speak") # 只允许动态添加name和speak
per = Person() # 实例化对象
# 动态添加属性
per.name = "Tom"
print(per.name)
# 动态添加方法
def say(self): # 要添加的方法
print("my name is", self.name)
per.speak = MethodType(say, per) # 相当于偏函数
per.speak() # 执行speak()函数
结果:
Tom
my name is Tom
私有属性
两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__属性名
属性直接对外暴露,不安全,没有数据的过滤,解决办法是限制它的访问,即是私有属性
访问私有属性是需要自己写get和set方法
例如:
- 方法一
使用get和set方法
class Person(object):
def __init__(self, age):
self.__age = age # 私有属性
def getAge(self): # 取出__age的值
return self.__age # 返回__age的值
def setAge(self, age): # 过滤数据,为__age赋值
if age < 0: # 过滤数据
age = 0
self.__age = age # 为__age赋值
per = Person(18) # 实例化对象
per.setAge(28) # 赋值
print(per.getAge()) # 调用getAge()方法并打印结果
结果:
28
- 方法二
使用@property函数做装饰器
class Person(object):
def __init__(self, age):
self.__age = age # 私有属性
@property # property 函数用作装饰器可以很方便的创建只读属性
# 方法名为受限制的变量去掉双下划线
def age(self): # 取出__age的值,相当于调用getAge
return self.__age # 返回__age的值
@age.setter # 去掉双下划线.setter,property 的setter方法同样可以用作装饰器
# 方法名为受限制的变量去掉双下划线
def age(self, age): # 过滤数据,为__age赋值,相当于调用setAge,不能放在age(self)函数之前,否则会报错
if age < 0: # 过滤数据
age = 0
self.__age = age # 为__age赋值
per = Person(18) # 实例化对象
per.age = 28 # 相当于调用setAge
print(per.age) # 相当于调用getAge
结果:
28
运算符的重载
可以对类的专有方法进行重载
类的专有方法:
__init__
: 构造函数,在生成对象时调用
__del__
: 析构函数,释放对象时使用
__repr__
: 打印,转换
__setitem__
: 按照索引赋值
__getitem__
: 按照索引获取值
__len__
: 获得长度
__cmp__
: 比较运算,在python3已经停用,但在python2中可用
可参考:operator — 标准运算符替代函数
__call__
: 函数调用
__add__
: 加运算
__sub__
: 减运算
__mul__
: 乘运算
__truediv__
: 除运算
__mod__
: 求余运算
__pow__
: 乘方方法
…
重载运算符:指的是在类中定义并实现一个与运算符对应的处理方法,这样当类对象在进行运算符操作时,系统就会调用类中相应的方法来处理。
常见重载运算符:
参考:
浅析Python运算符重载
也可参考:
什么是运算符重载,Python可重载运算符有哪些?
Python中类的运算符重载
实例一:
class Person(object):
def __init__(self, num, name):
self.num = num
self.name = name
def __add__(self, other):
return self.num + other.num
def __str__(self):
return "num = %d" % (self.num)
# return "num = " + str(self.num)
def __len__(self):
print("字符串长度为:", end="")
return len(self.name)
per1 = Person(1, "Tom")
per2 = Person(2, "Jerry")
print(per1 + per2) # 调用__add__,相当于print(per1.__add__(per2))
print(per1) # 调用__str__,相当于print(per1.__str__())
print(per2) # 调用__str__,相当于print(per2.__str__())
print(len(per1)) # 调用__len__,相当于print(per1.__len__())
结果:
3
num = 1
num = 2
字符串长度为:3
实例二:
class Student(object): # 创建学生类
def __init__(self, name, achievement): # 具有两个属性
self.name = name
self.achievement = achievement
def __pow__(self, power, modulo=None): # 乘方的重载运算符
print(self.name + "的成绩的" + str(power) + "次方为:", end="") # 打印结果
return (self.achievement) ** power # 返回学生成绩的power次方的计算结果
def __lt__(self, other): # “<” 的重载运算符
return self.achievement < other.achievement # 返回比较结果
student1 = Student("Tom", 86) # 实例化对象
student2 = Student("Linda", 60)
student3 = Student("Jack", 86)
student4 = Student("LiHua", 100)
print(pow(student1, 2)) # 计算学生成绩的平方
print(pow(student4, 2))
print(student1 < student2) # 引用__lt__重载运算符比较两学生成绩
print(student1 < student3)
print(student1 < student4)
结果:
Tom的成绩的2次方为:7396
LiHua的成绩的2次方为:10000
False
False
True