特性(P153)
通过函数property(fget, fset, fdel, doc)
可以创建特性, 特性外在表现和普通属性类似, 但是读写和删除会是通过get, gset, fel
这三个方法控制的
class Rectangle:
def __init__(self):
self.width, self.height = 0, 0
def set_size(self, size):
self.width, self.height = size
def get_size(self):
return self.width, self.height
size = property(get_size, set_size)
r = Rectangle()
r.size = 1, 2
print(r.size)
# (1, 2)
静态方法和类方法(P155)
python中最一般的方法是实例方法, 其第一个参数是调用方法的实例
还有两类方法, 一类是静态方法, 与C++中的静态方法类似
另一类是类方法, 类方法第一个参数类似于self, 但会自动关联到类而不是对象
可以通过装饰器定义静态方法和类方法(也可以自己手动包装_, 调用时可以通过类或者对象调用:
# 装饰器语法
class myClass:
@staticmethod
def smeth(): print("staticmethod")
@classmethod
def cmeth(cls): print("classmethod", cls)
x = myClass()
x.smeth()
x.cmeth()
myClass.smeth()
myClass.cmeth()
# 输出
staticmethod
classmethod <class '__main__.myClass'>
staticmethod
classmethod <class '__main__.myClass'>
# 手动包装
class myClass:
def smeth(): print("staticmethod")
smeth = staticmethod(smeth)
def cmeth(cls): print("classmethod", cls)
cmeth = classmethod(cmeth)
__getattr__, __setattr__等方法(P156)
可以通过以下方法拦截对属性的所有访问企图, 达到类似特性的功能
__getattribute__(self, name)
: 在属性被访问的时候调用,name为被范文的属性名字它拦截对所有属性的范文, 包括__dcit__
的访问, 所以在本函数中如果要访问当前实例的属性时候, 如果直接访问, 将会再次调用本函数, 导致无限循环, 安全的访问方式是使用超类的方法(使用super函数)__getattr__(self, name)
: 在属性被访问且不存在这个属性时候调用__setattr__(self, name, value)
: 在给属性赋值时调用, 在此函数内如果直接给属性赋值会再次调用本函数, 导致无限循环, 需要使用__dict__[name] = value
这样的方式, 通过访问__dict__
赋值__delattr__(self, name)
: 删除属性是调用
迭代器(P157)
可迭代对象要求对象实现方法__iter__
, 它返回一个迭代器, 而迭代器是一个实现了方法__next__
的对象, 调用__next__
时候应该返回下一个值, 当没有下一个值的时候引发StopIteration
异常, 内置函数next(it)
与it.__next__()
等效
实现了方法__iter__
的对象是可迭代的, 实现了方法__next__
的对象是迭代器, 推荐在迭代器中实现方法__iter__
, 这样迭代器可以直接用于for循环中
class TestIterator:
value = 0
def __next__(self):
self.value += 1
if self.value > 10: raise StopIteration
return self.value
def __iter__(self):
return self
ti = TestIterator()
print(list(ti))
# 输出
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成器(P160)
生成器定义和定义函数一样, 但通过yield语句生成多个值, 生成一个值后停止执行, 等待被重新唤醒, 唤醒后从原来停止的地方继续执行, 可对生成器进行迭代(即生成器返回一个迭代器)
# 使用生成器, 将任意层次嵌套的列表完全展开
def flatten(nested):
try:
# 字符串可以展开成一串由单个字符构成的字符串("abc"->"a", "b", "c")
# 这样会导致无限循环递归, 所以需要特判字符串, 让字符串不展开
try: nested + ''
except TypeError: pass # 不是字符串, 接着执行
else: raise TypeError # 字符串, 抛异常
for sublist in nested: # 如果nested不能迭代(已经是最小元素), 抛异常
for element in flatten(sublist):
yield element
except TypeError: # 字符串或基本元素
yield nested
x = [[1, 2, [3, 4], [5], ["678"]], [9, 10]]
print(list(flatten(x)))
# 输出
[1, 2, 3, 4, 5, '678', 9, 10]
sent方法
生成器开始运行后, 可以通过生成器的sent
方法, 向生成器发送一个值, 当生成器重新运行时, yield将返回这个值, 如果使用next, yield返回None
throw方法
在生成器yield中引发一个异常
close方法
关闭生成器(在yield处引发一个GeneratorExit异常)
生成器解决八皇后问题
居然异常的优雅…
def queens(num=8, state=()): # 棋盘大小为num, num[x]=y表示第x行的皇后在第y列处
def conflict(state, nextX): # 冲突返回True
nextY = len(state)
for i in range(nextY):
if abs(state[i]-nextX) in (0, nextY-i): return True
return False
for pos in range(num):
if not conflict(state, pos):
if len(state) == num-1: yield (pos, ) # 最后一行
else :
for result in queens(num, state+(pos, )):
yield (pos, )+result
>>> len(list(queens()))
92