《python基础教程》 --读书笔记(8)

魔法方法,属性,和迭代器

在python中有的名称会在前面和后面加上两个下划线,这些方法被称为魔法方法,这些方法会在特殊的情况下被python调用,而几乎没有直接调用他们的必要

构造方法

当一个对象被创建之后,会立刻调用构造方法。

# 构造方法
class Foobar:
    def __init__(self, value = 42):
        self.somevar = value
f = Foobar()
print(f.somevar) # 42

f1 = Foobar("test")
print(f1.somevar) # test
  • 重写一般方法和特殊的构造方法
class A:
    def hello(self):
        print("Hello I'm A")
class B(A):
    pass

a = A()
# B类的一个实例被调用,但在B类中没有找到该方法,就会去超类A中寻找
b = B()
a.hello() # Hello I'm A
b.hello() # Hello I'm A
# 重写一般方法
class B(A):
    def hello(self):
        print("Hello I'm B")

b = B()
b.hello() # Hello I'm B
# 重写构造方法
class Bird:
    def __init__(self):
        self.hungry = True
    def eat(self):
        if self.hungry:
            print("to eat...")
            self.hungry = False
        else:
            print("No, Thanks")
b = Bird()
b.eat() # to eat...
b.eat() # No, Thanks
# 定义子类 SongBird 添加唱歌行为
class SongBird(Bird):
    def __init__(self):
        self.sound = "lalalala..."
    def sing(self):
        print(self.sound)
sb = SongBird()
sb.sing() # lalalala...
# 继承eat方法  但是如果调用eat方法,就会出问题
# sb.eat()
  • 调用未绑定的超类构造方法
# 直接调用类的方法,那么就没有实例会被绑定,这样就可以自由的提供需要的self参数,这样的方法称为未绑定方法
class SongBird(Bird):
    def __init__(self):
        # 通过当前的实例self参数提供给未绑定方法,Songbrid就能够使用其超类构造方法的所有实现,设置hungry属性
        Bird.__init__(self)
        self.sound = "lalalala..."
    def sing(self):
        print(self.sound)
sb = SongBird()
sb.eat() # to eat...
sb.eat() # No, Thanks
  • 使用super函数
    super()只能在新式类中使用,super函数比在超类中直接调用未绑定方法更直观,即使类已经继承多个超类,他也只需要使用一次super函数,大多数情况下,使用新式类和super函数是比调用超类未绑定的构造方法更好的选择
__metaclass__ = type
# 使用super函数
class SongBird(Bird):
    def __init__(self):
        super().__init__()
        self.sound = "lalalala..."
    def sing(self):
        print(self.sound)
sb = SongBird()
sb.eat() # to eat...
sb.eat() # No, Thanks

成员访问

  • 基本序列和映射规则
  • 子类化列表,字典和字符串

属性

# 属性
class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def setSize(self, size):
        self.width, self.height = size
    def getSize(self):
        return self.width, self.height
r = Rectangle()
r.width = 5
r.height = 10
print(r.getSize())
r.setSize((10, 20))
print(r.width)
  • property函数
__metaclass__ = type

# 属性 使用property函数
class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
    def setSize(self, size):
        self.width, self.height = size
    def getSize(self):
        return self.width, self.height
    size = property(getSize, setSize)
r = Rectangle()
r.width = 5
r.height = 10
print(r.size) # (5, 10)
r.size = 20, 50
print(r.width) # 20
  • 静态方法和类成员方法
    静态方法和类方法分别在创建时分别被装入staticmethod类型和classmethod类型的对象中。静态方法的定义没有self参数,且能够被类本身直接调用。类方法在定义时需要名cls类似于self的参数,类成员方法可以直接用类的具体对象调用,但cls参数时自动被绑定到类的
__metaclass__ = type

# 静态方法和类成员方法
class MyClass:
    def smeth():
        print("this is a static method")
    smeth = staticmethod(smeth)

    def cmeth(cls):
        print("this is a class method of", cls)
    cmeth = classmethod(cmeth)

# 装饰器
class MyClass:
    @staticmethod
    def smeth():
        print("this is a static method")

    @classmethod
    def cmeth(cls):
        print("this is a class method of", cls)
MyClass.smeth() # this is a static method
MyClass.cmeth() # this is a class method of <class '__main__.MyClass'>
  • __getattr__、__settattr__和它的朋友们

迭代器

  • 迭代器规则
    迭代的意思是重复的做一些事情很多次,就像在循环中做的那样,到目前为止只在序列和字典进行过迭代啊,但实际也能对其它对象进行迭代,只要该对象实现了__iter__方法
    __itre__方法会返回一个迭代器,所谓的迭代器就是具有__next__方法的对象,在调用next方法时,迭代器就会返回它的下一个值
# 迭代对象
# 实现__iter__方法的对象是可迭代的,实现__next__方法的对象则是迭代器
class Fibs:
    def __init__(self):
        self.a = 0
        self.b = 1
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        return self.a
    def __iter__(self):
        return self
fibs = Fibs()
for f in fibs:
    if f >10:
        print(f)
        break
# 内建函数iter可以从可迭代的对象中获得迭代器
it = iter([1,2,3,4])
for i in it:
    print(i)
  • 从迭代器得到序列
# 从迭代器得到序列
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()
# 使用list构造方法显式地将迭代器转化为列表
print(list(ti))

生成器

任何包含yield语句的函数被称为生成器,yield不像return那样返回值,而是每次产生多个值,每次产生一个值(使用yield语句)函数就会被冻结,即函数停在那点等待被重新唤醒,函数被重新唤醒后就从停止的那点开始执行。生成器是一个返回迭代器的函数,只能用于迭代操作

  • 创建生成器
# 生成器
nested = [[1,2],[3,4],[5]]
def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element
for num in flatten(nested):
    print(num)
  • 递归生成器
# 递归生成器
""" 
当flatten被调用时,有两种情况:基本情况金和需要递归的情况
在基本情况中,函数被告知需要展开一个元素,for循环会引发异常,生成器会产生一个元素
如果展开的是一个列表,程序必须遍历所有子列表,并对它们调用flatten
"""
def flattrn(nested):
    try:
        # 不要迭代类似字符串的对象
        try: nested + ""
        except TypeError: pass
        else: raise TypeError
        for sublist in nested:
            for element in flattrn(sublist):
                yield element
    except TypeError:
        yield nested

print(list(flattrn([[1,2,3],4,[[5],[6,[7]]]])))

八皇后问题

  • 生成器和回溯
    生成器时逐渐产生结果的复杂递归算法的理想工具,没有生成器的话,算法就需要一个作为额外参数的半成品方案,这样递归调用就可以在这个方案上建立起来,如果使用生成器,那么所有的递归调用只需要创建自己的yield部分。
# 八皇后问题
# 判断是否会产生冲突
"""
参数nextX代表下一个皇后的水平位置(x坐标或列)
nextY代表垂直位置(y坐标或行)
如果下一个皇后和正在考虑的前一个皇后的列号之差为0(列相同)或者
列号之差等于行号之差就返回True
"""
def conflict(state, nextX):
    nextY = len(state)
    for i in range(nextY):
        if abs(state[i]-nextX) in (0, nextY-i):
            return True
    return False
# 迭代放置棋子
"""
num:棋子的个数,默认为8,当然数值也等于棋盘的行数或列数
state: 设置一个空队列,用于保存符合规则的棋子的信息
"""
def queens (num = 8, state = ()):
    # 遍历每一列
    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
# 总共有多少种解决方案
print(len(list(queens()))) # 92
# 对结果进行包装 传入某一个正确位置
import random
def prettyprint(solution):
    print(solution)
    def line(pos, length = len(solution)):
        return "." * (pos) + "x" + "." * (length - pos - 1)
    # 遍历每一行
    for pos in solution:
        print(line(pos))
prettyprint(random.choice(list(queens(4))))
# 执行结果
(2, 0, 3, 1)
..x.
x...
...x
.x..
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值