【Python-11】特性(property/静态方法和类方法/装饰器/迭代器/生成器)

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基础编程(第三版)

发布了134 篇原创文章 · 获赞 119 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/jobbofhe/article/details/90112728