夜间模式暗黑模式
字体
阴影
滤镜
圆角
主题色
Python学习笔记8-特性与迭代器与生成器

特性(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
暂无评论

发送评论


				
上一篇
下一篇