魔法方法,属性,和迭代器
在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..