数据封装、继承和多态只是面向对象程序设计中最基础的3个概
使用slots和@property
slots限制实例的绑定属性
想要限制实例的属性,例如只允许对Student实例添加name和age属性:Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class实例能添加的属性
代码语言:python代码运行次数:0复制class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
就会发现类的实例属性score属性不能绑定了,slots定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
@property
能检查参数,又可以用类似属性这样简单的方式来访问类的变量
代码语言:python代码运行次数:0复制class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来
代码语言:python代码运行次数:0复制#要特别注意:属性的方法名不要和实例变量重名
#错误案例
class Student(object):
# 方法名称和实例变量均为birth:
@property
def birth(self):
return self.birth
多重继承
代码语言:python代码运行次数:0复制class Dog(Mammal, Runnable): #同时获得多个父类的所有功能
pass
这样额外的功能加入设计也称为MixIn,如Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixIn和ThreadingMixIn提供。
`
定制类
返回字符
这样打印出来的实例,不但好看,而且容易看出实例内部重要的数据
代码语言:python代码运行次数:0复制class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
#__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串
迭代返回
代码语言:python代码运行次数:0复制class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
>>> for n in Fib():
... print(n)
...
1
1
2
3
5
...
46368
75025
元素处理
getitem/setitem()/delitem()
像list那样按照下标取出元素,需要实现getitem()方法
代码语言:python代码运行次数:0复制class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a b
return a
属性获取
要避免这个错误,除了可以加上一个score属性外,Python还有另一个机制,那就是写一个getattr()方法,动态返回一个属性
只有在没有找到属性的情况下,才调用getattr,已有的属性,比如name,不会在getattr中查找
完全动态调用的特性非常灵活
调用实例方法
调用实例方法时,我们用instance.method()来调用,也可以直接对实例进行调用
callable()函数,我们就可以判断一个对象是否是“可调用”对象
枚举类
Enum可以使得每个常量都是class的一个唯一实例
代码语言:python代码运行次数:0复制# 1
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
- Enum的第一个参数是枚举的类名,第二个参数是一个包含枚举成员名称的元组
- 遍历Month枚举类中的所有成员。枚举成员和它们的名称都存储在特殊的members属性中,这是一个字典;Month.members.items()会返回一个包含(成员名称, 成员)对的迭代器
- 这行代码在循环中打印每个成员的名称和值,member.value是自动分配给枚举成员的一个唯一值,默认从1开始递增
输出结果为:
Jan => Month.Jan , 1 Feb => Month.Feb , 2
Mar => Month.Mar , 3 Apr => Month.Apr , 4
May => Month.May , 5 Jun => Month.Jun , 6
Jul => Month.Jul , 7 Aug => Month.Aug , 8
Sep => Month.Sep , 9 Oct => Month.Oct , 10
Nov => Month.Nov , 11 Dec => Month.Dec , 12
也可以写成
代码语言:python代码运行次数:0复制from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
元类(后面再来补充)
type()动态创建类
type()函数可以查看一个类型或变量的类型,Hello是一个class,它的类型就是type,而h是一个实例,它的类型就是class Hello
metaclass控制类的创建行为
代码语言:python代码运行次数:0复制# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)