使用slots
如果想要限制实例的属性,如只允许对Student实例添加
name
和age
属性;Python允许在定义class的时候,定义一个特殊的__slots__
变量来限制该class实例能添加的属性class Student(object):
__slots__ = ('name', 'age') #用tuple定义允许绑定的属性名称
使用
__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的除非在子类中也定义
__slots__
,这样子类实例允许定义的属性就是自身的__slots__
加上父类的__slots__
使用@property
Python内置的
@property
装饰器就是负责把一个方法变成属性调用的class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
把一个getter方法变成属性,只需要加上
@property
就可以,@property
本身又创建了另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值属性的方法名不要和实例变量重名,否则会造成无限递归,最终导致栈溢出报错
多重继承
Python允许使用多重继承,
Mixln
就是一种常见的设计定义出肉食动物
CarnivorousMixIn
和植事动物HerbivoresMixIn
,让某个动物同时拥有好几个MixIn
class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
pass
定制类
str
打印出来的实例能够容易看出内部重要的数据
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
#__repr__()是为调试服务的,加上下面这句第8行就可以不写print也能看到打印内容
__repr__ = __str__
print(Student('Michael')) #Student object (name: Michael)
iter
iter()方法返回一个迭代对象,for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到
StopIteration
错误时退出循环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 # 返回下一个值
getitem
上面的Fib实例虽然能作用于for循环,但不能把它当成list来使用;若需要能够按照下标取出元素,需要实现
__getitem__()
class Fib(object):
def __getitem__(self, n):
if isinstance(n, int): # n是索引
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
与之对应还有
__setitem__()
,把对象视作list或dict来对集合赋值。还有一个__delitem__()
方法用于删除某个元素getattr
只有在没有找到属性的情况下,才调用
__getattr__
,只有在没有找到属性的情况下才调用__getattr__
,已有的属性不会在__getattr__
中查找任意的调用如
s.abc
都会返回None
,因为__getattr__
默认返回就是None
;要让class只相应特定的几个属性,那么就要抛出AttributeError
call
任何类都可以通过定义一个
__call__()
方法以对实例进行调用能够被调用的对象就是一个
Callable
对象,比如函数和带有__call__()
的类实例 ```python class Chain(object):def init(self, path=’’):
self._path = path
def getattr(self, path):
return Chain('%s/%s' % (self._path, path))
def str(self):
return self._path
repr = str
Chain().status.user.timeline.list #’/status/user/timeline/list’
<a name="QEnBI"></a>
### 使用枚举类
- Python提供了`Enum`来为枚举类型定义一个class类型,每个常量都是class的一个唯一实例;`value`属性则是自动赋给成员的`int`常量,默认从`1`开始计数;如果需要更精确地控制枚举类型,可以从`Enum`派生出自定义类,`@unique`装饰器可以检查保证没有重复值
```python
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
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()
函数允许动态创建出类来,动态语言本身支持运行期动态创建类;一个class的类型就是type
,而一个实例的类型是classtype()
函数既可以返回一个对象的类型,又可以创建出新的类型,譬如可以通过type()
函数创建出Hello
类,而无需通过class Hello(object)...
定义def fn(self, name='world'): # 先定义函数
print('Hello, %s.' % name)
Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
metaclass
比较难,暂时先不管