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
r = Rectangle()
r.set_size((100, 50))
r.get_size()
(100, 50)
使用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.set_size((100, 50))
r.size
(100, 50)
静态方法和类方法
'''
静态方法
和类方法是这样创建的:将它们分别包装在 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)
# 通过类调用
MyClass.smeth()
# 通过对象调用
my = MyClass()
my.smeth()
This is a static method
This is a static method
装饰器
# 上述类中封装静态方法的过程有点繁琐
# Python 中引入了装饰器的 概念
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()
# 通过对象调用
my = MyClass()
my.smeth()
This is a static method
This is a static method
迭代器
__ iter __ ,它是迭代器协议的基础。
注意到这个迭代器实现了方法 iter ,而这个方法返回迭代器本身。在很多情况下,都在另一个对象中实现返回迭代器的方法 iter ,并在 for 循环中使用这个对象。但推荐在迭代器中也实现方法 iter (并像刚才那样让它返回 self ),这样迭代器就可直接用于 for 循环中。
- 迭代器完成斐波那切数列
# 斐波那契数列 迭代器
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 > 1000:
print(f)
break
- 从迭代器创建序列
class TestIter:
value = 0
def __next__(self):
self.value += 1
if self.value > 8: raise StopIteration
return self.value
def __iter__(self):
return self
it = TestIter()
list(it)
生成器
这个函数的大部分代码都很简单。它首先迭代所提供嵌套列表中的所有子列表,然后按顺序迭代每个子列表的元素。倘若最后一行为 print(element) ,这个函数将容易理解得多,不是吗?在这里,包含 yield 语句的函数都被称为生成器。这可不仅仅是名称上的差别,生成器的行为与普通函数截然不同。差别在于,生成器不是使用 return 返回一个值,而是可以生成多个值,每次一个。每次使用 yield 生成一个值后,函数都将冻结,即在此停止执行,等待被重新唤醒。被重新唤醒后,函数将从停止的地方开始继续执行。
nested = [[1, 2], [3, 4], [5]]
def flatten(nested):
for sublist in nested:
for element in sublist:
yield element
flatten(nested)
for num in flatten(nested):
print(num)
list(flatten(nested))
1
2
3
4
5
[1, 2, 3, 4, 5]
设计的生成器只能处理两层的嵌套列表,这是使用两个 for 循环来实现的。如果要处理任意层嵌套的列表,该如何办呢?例如,你可能使用这样的列表来表示树结构(也可以使用特定的树类,但策略是相同的)。对于每层嵌套,都需要一个 for 循环,但由于不知道有多少层嵌套,你必须修改解决方案,使其更灵活。该求助于递归了。
def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested
print(list(flatten([[[1], 2], 3, 4, [5, [6, 7]], 8])))
print(list(flatten(['foo', ['bar', ['baz']]])))
上述代码运行结果
[1, 2, 3, 4, 5, 6, 7, 8]
---------------------------------------------------------------------------
RecursionError Traceback (most recent call last)
<ipython-input-156-1fba010c4321> in <module>
16 print(list(flatten([[[1], 2], 3, 4, [5, [6, 7]], 8])))
17
---> 18 print(list(flatten(['foo', ['bar', ['baz']]])))
<ipython-input-156-1fba010c4321> in flatten(nested)
9 try:
10 for sublist in nested:
---> 11 for element in flatten(sublist):
12 yield element
13 except TypeError:
... last 1 frames repeated, from the frame below ...
<ipython-input-156-1fba010c4321> in flatten(nested)
9 try:
10 for sublist in nested:
---> 11 for element in flatten(sublist):
12 yield element
13 except TypeError:
RecursionError: maximum recursion depth exceeded
请注意,这里没有执行类型检查:我没有检查 nested 是否是字符串,而只是检查其行为是否类似于字符串,即能否与字符串拼接。对于这种检查,一种更自然的替代方案是,使用 isinstance以及字符串和类似于字符串的对象的一些抽象超类,但遗憾的是没有这样的标准类。另外,即便是对 UserString 来说,也无法检查其类型是否为 str 。
修改上述代码
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, 4, [5, [6, 7]], 8])))
print(list(flatten(['foo', ['bar', ['baz']]])))
[1, 2, 3, 4, 5, 6, 7, 8]
['foo', 'bar', 'baz']
参考资料
Python基础编程(第三版)