python-09 魔法方法、特性和迭代器

# 第九章 魔法方法、特性和迭代器
# 9.1 如果你使用的不是Python 3

# 9.2 构造函数
# __init__ 初始化
# __del__ 析构函数 在对象被销毁之前调用

# 9.2.1 重写普通方法和特殊的构造函数
class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print('Aaaah.....')
self.hungry = False
else:
print('No, thanks')

class SongBird(Bird):
def __init__(self):
#Bird.__init__(self) # 9.2.2 应该加的
super().__init__()
self.sound = 'Squawk!'
def sing(self):
print(self.sound)
sb = SongBird()
print(sb.sing())
print(sb.eat()) #'SongBird' object has no attribute 'hungry'
# 9.2.2 调用未关联的超类构造函数 #Bird.__init__(self)

# 9.2.3 使用函数 super # super().__init__()

# 9.3 元素访问
# 9.3.1 基本的序列和映射协议

def check_index(key):
'''
指定的键是否是可接受的索引?

键必须是非负整数, 才是可接受的。如果不是整数,将引发TypeError 异常; 如果是负数,将引发IndexError异常(因为这个序列的长度是无穷的)

'''
if not isinstance(key, int):
raise TypeError
if key < 0:
raise IndexError

class ArithmeticSequence:
def __init__(self, start = 0, step = 1):
'''
初始化这个算术序列

:param start: 序列中的第一个值
:param step: 两个相邻值得差
'''
self.start = start
self.step = step
self.changed = {}
def __getitem__(self, key):
'''
从算术序列中获取一个元素
'''
check_index(key)
try:
return self.changed[key]
except KeyError:
return self.start + key * self.step

def __setitem__(self, key, value):
'''
修改算术序列中的元素
'''

check_index(key)

self.changed[key] = value

a = ArithmeticSequence(5, 6)
print(a[5])

# 9.3.2 从list、dict 和 str 派生

class CounterList(list):
def __init__(self, *args):
super().__init__(*args)
self.counter = 0
def __getitem__(self, index):
self.counter += 1
return super(CounterList, self).__getitem__(index)

cl = CounterList(range(10))
print(cl)
print(cl.counter)
cl[4] + cl[2]
print(cl.counter)

# 9.4 其他魔法方法 # 如果需要学习更多请参考 Python Reference Manual”的Special method names一节。

# 9.5 特性 通过存取方法定义的属性通常称为特性
'''
class Rectangle:
def __init__(self):
self.width = 0
self.height = 0
def set_size(self, size):
self.width, self.height = size
def get_size(self):
return self.width, self.height

r = Rectangle()
r.width = 10
r.height = 5
print(r.get_size())
r.set_size((150, 100))
print(r.width)
'''
# 9.5.1 函数property
class Rectangle:
def __init__(self):
self.width = 0
self.height = 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.width = 10
r.height = 5
print(r.size)
r.size = 150, 100
print(r.width)
'''
调用函数property时,还可不指定参数、指定一个参数、指定三个参数或指定四个参数。
如果没有指定任何参数,创建的特性将既不可读也不可写。
果只指定一个参数(获取方法),创建的特性将是只读的。
第三个参数是可选的,指定用于删除属性的方法(这个方法不接受任何参数)。
第四个参数也是可选的,指定一个文档字符串。这些参数分别名为fget、fset、fdel和doc。
如果你要创建一个只可写且带文档字符串的特性,可使用它们作为关键字参数来实现。
Descriptor HowTo Guide(https://docs.python.org/3/howto/descriptor.html
'''
# 9.5.2 静态方法和类方法
#静态方法和类方法是这样创建的:将它们分别包装在staticmethod和classmethod类的对象中。
# 静态方法的定义中没有参数self,可直接通过类来调用。类
# 方法的定义中包含类似于self的参数,通常被命名为cls。对于类方法,也可通过对象直接调用,但参数cls将自动关联到类。
'''
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)

print(MyClass.smeth())
print(MyClass.cmeth())

# * 9.5.3 __getattr__、__setattr__等方法
'''
1、__getattribute__(self, name):在属性被访问时自动调用(只适用于新式类)。
2、__getattr__(self, name):在属性被访问而对象没有这样的属性时自动调用。
3、__setattr__(self, name, value):试图给属性赋值时自动调用。
4、__delattr__(self, name):试图删除属性时自动调用。
'''


# 9.6 迭代器 __iter__
# 9.6.1 迭代器协议 __iter__返回一个迭代器,它是包含方法__next__的对象 next(it)与 it.__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:
print(f)
if f > 1000:
break

# 9.6.2 从迭代器创建序列
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))

# 9.7 生成器 包含yield语句的函数都被称为生成器
# 9.7.1 创建生成器
'''
def flatten(nested):
for sublist in nested:
for element in sublist:
yield element
nested = [[1, 2], [3, 4], [5]]

print(list(flatten(nested)))
print(flatten(nested))
'''
# 9.7.2 * 递归式生成器
'''
def flatten(nested):
try:
# 不迭代类似于字符串的对象
try:
nested + ''
except TypeError:
pass
else:
raise TypeError
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested
print(list(flatten([[[1], 2], 3, 'as', 4, [5, [6, 7, 'sd']], 8])))
'''
# 9.7.3 通用生成器 生成器由两个单独的部分组成:生成器的函数和生成器的迭代器。
# 生成器的函数是由def语句定义的,其中包含yield。生成器的迭代器是这个函数返回的结果

# 9.7.4 生成器的方法
#外部世界:外部世界可访问生成器的方法send,这个方法类似于next,但接受一个参数(要发送的“消息”,可以是任何对象)。
#生成器:在挂起的生成器内部,yield可能用作表达式而不是语句。换而言之,当生成器重新运行时,
# yield返回一个值——通过send从外部世界发送的值。如果使用的是next,yield将返回None。
'''
方法throw:用于在生成器中(yield表达式处)引发异常,调用时可提供一个异常类型、一个可选值和一个traceback对象。
方法close:用于停止生成器,调用时无需提供任何参数。
'''

# 9.7.5 模拟生成器
def flatten(nested):
result = []
try:
# 不迭代类似于字符串的对象
try:
nested + ''
except TypeError:
pass
else:
raise TypeError
for sublist in nested:
for element in flatten(sublist):
result.append(element)
except TypeError:
result.append(nested)
return result
print(flatten([[[1], 2], 3, 'as', 4, [5, [6, 7, 'sd']], 8]))

# 9.8 八皇后问题



'''
序列和映射基本上是元素(item)的集合,要实现它们的基本行为(协议),不可变对象需要实现2个方法,而可变对象需要实现4个。
1、__len__(self):这个方法应返回集合包含的项数,对序列来说为元素个数,对映射来说为键-值对数。如果__len__返回零
(且没有实现覆盖这种行为的__nonzero__),对象在布尔上下文中将被视为假(就像空的列表、元组、字符串和字典一样)。
2、__getitem__(self, key):这个方法应返回与指定键相关联的值。对序列来说,键应该是0~n-1的整数(也可以是负数,这将在后面说明),
其中n为序列的长度。对映射来说,键可以是任何类型。
3、__setitem__(self, key, value):这个方法应以与键相关联的方式存储值,以便以后能够使用__getitem__来获取。当然,仅当对象可变时才需要实现这个方法。
4、__delitem__(self, key):这个方法在对对象的组成部分使用__del__语句时被调用,应删除与key相关联的值。同样,仅当对象可变(且允许其项被删除)时,
才需要实现这个方法。

 对于序列,如果键为负整数,应从末尾往前数。换而言之,x[-n]应与x[len(x)-n]等效。
 如果键的类型不合适(如对序列使用字符串键),可能引发TypeError异常。
 对于序列,如果索引的类型是正确的,但不在允许的范围内,应引发IndexError异常。
9.9 小结
 新式类和旧式类:Python类的工作方式在不断变化。较新的Python 2版本有两种类,其中旧式类正在快速退出舞台。
新式类是Python 2.2引入的,提供了一些额外的功能,如支持函数super和property,而旧式类不支持。要创建新式类,必须直接或间接地继承object或设置__metaclass__。
 魔法方法:Python中有很多特殊方法,其名称以两个下划线开头和结尾。这些方法的功能各不相同,但大都由Python在特定情况下自动调用。例如__init__是在对象创建后调用的。
 构造函数:很多面向对象语言中都有构造函数,对于你自己编写的每个类,都可能需要为它实现一个构造函数。构造函数名为__init__,在对象创建后被自动调用。
 重写:类可重写其超类中定义的方法(以及其他任何属性),为此只需实现这些方法即可。要调用被重写的版本,可直接通过超类调用未关联版本(旧式类),也可使用函数super来调用(新式类)。
 序列和映射:要创建自定义的序列或映射,必须实现序列和映射协议指定的所有方法,其中包括__getitem__和__setitem__等魔法方法。通过从list(或UserList)和dict(或UserDict)派生,可减少很多工作量。
 迭代器:简单地说,迭代器是包含方法__next__的对象,可用于迭代一组值。没有更多的值可供迭代时,方法__next__应引发StopIteration异常。可迭代对象包含方法__iter__,
它返回一个像序列一样可用于for循环中的迭代器。通常,迭代器也是可迭代的,即包含返回迭代器本身的方法__iter__。
 生成器:生成器的函数是包含关键字yield的函数,它在被调用时返回一个生成器,即一种特殊的迭代器。要与活动的生成器交互,可使用方法send、throw和close。
 八皇后问题:八皇后问题是个著名的计算机科学问题,使用生成器可轻松地解决它。这个问题要求在棋盘上放置8个皇后,并确保任何两个皇后都不能相互攻击。

iter(obj) 从可迭代对象创建一个迭代器
next(it) 让迭代器前进一步并返回下一个元素
property(fget, fset, fdel, doc) 返回一个特性;所有参数都是可选的
super(class, obj) 返回一个超类的关联实例
'''


猜你喜欢

转载自www.cnblogs.com/fuyouqiang/p/11844650.html