10. 方法、属性和迭代器

基于网络课程《Python全栈开发专题》 记录笔记,请支持正版课程

构造方法

class Person:
    def __init__(self, name='Bill'):
        print('构造方法已经被调用')
        self.name = name
    def getName(self):
        return self.name
    def setName(self, name):
        self.name = name

p1 = Person()
print(p1.getName())

p2 = Person(name='二狗')
print(p2.getName())

重写普通方法和构造方法

super().__init__()调用父类构造器

'''
在Python中重写只看方法名,不看参数
'''
class Bird:
    def __init__(self):
        print('Bird构造器')
        self.hungry = True
    def eat(self):
        if self.hungry:
            print('吃包子……………………………………')
            self.hungry = False
        else:
            print('吃过了')

class SongBird(Bird):
    def __init__(self):
        super().__init__()
        print('SongBird构造器')
        self.sound = '唱歌'
    def sing(self):
        print(self.sound)
    def eat(self, thing):
        print('吃', thing)

b = Bird()
b.eat()
b.eat()

s = SongBird()
s.sing()
s.sing()
s.eat('鸡腿')

super(),调用其他类的构造器

class MyClass1:
    def __init__(self):
        print('MyClass1')
class MyClass2(MyClass1):
    def __init__(self):
        print('MyClass2')
class MyClass3(MyClass2):
    def __init__(self):
        # super().__init__()
        # super(MyClass3, self).__init__()  # 这种写法和上面是等效的
        super(MyClass2, self).__init__()    # 调用MyClass2的父类构造器
        print('MyClass3')

m = MyClass3()

自定义序列

  • __init__,构造方法,你懂的
  • __getitem__,获取value
  • __setitem__,设置键值
  • __delitem__,删除值
  • __len__,长度
class FactorialDict():
    def __init__(self):
        self.numDict = {}
    def factorial(self, n):
        if n == 0 or n == 1:
            return 1
        else:
            return n * self.factorial(n - 1)
    def __getitem__(self, key):
        print('__getitem__方法被调用了, key = {}'.format(key))
        if key in self.numDict:
            return self.factorial(self.numDict[key])
        else:
            return 0
    def __setitem__(self, key, value):
        print('__setitem__方法:key = {}'.format(key))
        self.numDict[key] = int(value)
    def __delitem__(self, key):
        print('__delitem__方法:key = {}'.format(key))
        del self.numDict[key]
    def __len__(self):
        print('__len__方法:')
        return len(self.numDict)


d = FactorialDict()
d['4!'] = 4
d['7!'] = '7'
d['12!'] = 12

print('4! = {}'.format(d['4!']))
print('长度:{}'.format(len(d)))
del d['7!']

从内建列表、字典和字符串继承

  1. 继承内建类list。__getitem__()方法
class ConterList(list):
    def __init__(self, *args):
        super().__init__(*args)
        self.counter = 0
    def __getitem__(self, index):
        self.counter += 1
        return super().__getitem__(index)

    
c = ConterList(range(10))
print(c)
c.reverse()
print(c)
del c[3]

print(c.counter)
print(c[1] * c[3])
print(c.counter)
  1. 继承内建类dict
class CounterDict(dict):
    def __init__(self, *args):
        super().__init__(*args)
        self.counter = 0
    def __getitem__(self, key):
        self.counter += 1
        return dict.__getitem__(self, key)
    
d = CounterDict({'name': '二狗'})
print(d['name'])
print(d.get('age'))
# print(d['age'])  # 如果使用 [] ,键不存在时会报错
print(d.counter)
  1. 继承内建类str
class MultiString(str):
    def __new__(self, *args, sep=' '):
        s = ''
        for arg in args:
            s += arg + sep  # 把 arg 和分隔符拼接起来
        # 如果sep不为空,需要把最后一个sep截取掉
        index = -len(sep)
        if index == 0:
            index = len(s)
        return super().__new__(self, s[:index])
    def __init__(self, *args, sep=' '):
        pass
    
s1 = MultiString('a', 'b', 'c')
print(s1)
s2 = MultiString('a', 'b', 'c', sep = '')
print(s2)
s3 = MultiString('a', 'b', 'c', sep = '*')
print(s3)

属性与property() 函数

class Rectangle:
    def __init__(self):
        self.left = 0
        self.top = 0
    def setLeft(self, left):
        self.left = left
    def setPosition(self, position):
        print('setPosition 方法')
        self.left, self.top = position   # 用元组直接赋多个值
    def getPosition(self):
        print('getPosition 方法')
        return self.left, self.top   # 直接返回一个元组,java程序员看哭了
    def deletePosition(self):
        print('position 属性已经被删除')
        self.left = 0
        self.top = 0
    # 用 property() 函数绑定get/set/del方法 !!!
    position = property(getPosition, setPosition, deletePosition)

r = Rectangle()
r.left = 100
print(r.left)  # 100

r.setPosition([400, 500])
print(r.getPosition())
'''
setPosition 方法
getPosition 方法
(400, 500)
'''

r.position = 123, 456
print(r.position)
'''
setPosition 方法
getPosition 方法
(123, 456)
'''

del r.position
print(r.position)
'''
position 属性已经被删除
getPosition 方法
(0, 0)
'''

监控对象中的所有属性

'''
__getattr__(): 用来监控所有属性的读操作
__setattr__(): 用来监控所有属性的写操作
__delattr__(): 用来监控所有属性的删除操作
'''

class Rectangle:
    def __init__(self):
        self.width = 0
        self.height = 0
        self.left = 0
        self.top = 0
    def __setattr__(self, name, value):
        print('{} 被设置, 新的值为: {} '.format(name, value))
        if name == 'size':
            self.width, self.height = value
        elif name == 'position':
            self.left, self.top = value
        else:
            self.__dict__[name] = value
    def __getattr__(self, name):
        print('{} 被获取'.format(name))
        if name == 'size':
            return self.width, self.height
        elif name == 'position':
            return self.left, self.top
    def __delattr__(self, name):
        print('{} 属性将被删除'.format(name))
        if name == 'size':
            self.width, self.height = 0, 0
        elif name == 'position':
            self.left, self.top = 0, 0
            
r = Rectangle()
r.size = 100, 200
'''
width 被设置, 新的值为: 0 
height 被设置, 新的值为: 0 
left 被设置, 新的值为: 0 
top 被设置, 新的值为: 0 
size 被设置, 新的值为: (100, 200) 
width 被设置, 新的值为: 100 
height 被设置, 新的值为: 200 
'''

print(r.size)
print(r.position)
'''
size 被获取
(100, 200)
position 被获取
(0, 0)
'''

del r.size, r.position
print(r.size, r.position)
'''
size 属性将被删除
width 被设置, 新的值为: 0 
height 被设置, 新的值为: 0 
position 属性将被删除
left 被设置, 新的值为: 0 
top 被设置, 新的值为: 0 
size 被获取
position 被获取
(0, 0) (0, 0)
'''
class MyClass:
    def __setattr__(self, name, value):
        if name == 'value':
            if value > 0:
                self.__dict__[name] = value
            else:
                print('{}的属性值必须大于0!'.format(name))
        else:
            self.__dict__[name] = value
            
c = MyClass()
c.value = 20
print(c.value)

c.value = -1
print(c.value)  # 设置不成功,还是20

静态方法和类方法

'''
在实例方法中,可以调用静态方法和类方法,反之不成立!
'''
class MyClass:
    name = '二狗'
    def __init__(self):
        print('MyClass的构造器')
        self.value = 20
        
    # 定义静态方法
    @staticmethod
    def run():
        print(MyClass.name, 'MyClass的静态方法被调用')
    
    # 定义类方法
    @classmethod
    def do(cls):
        print(cls)  # 
        print('[{}]'.format(cls.name))
        cls.run()   # 类方法中可以调用静态方法

    def do1(self):
        print(self)  # <__main__.MyClass object at 0x0000022BED0640B8>
        print(self.value)
        print('< {} >'.format(self.name))
        self.do()   # 实例方法中可以调用静态方法和类方法
        self.run()
        
# 调用静态方法
MyClass.run()

c = MyClass()
c.do()
c.do1()
c.run()

MyClass.do()

自定义可迭代的类

__iter__(), __next()__

class RightTriangle:
    def __init__(self):
        self.n = 0
    def __iter__(self):
        return self
    def __next__(self):
        self.n += 1
        return '*' * (2 * self.n -1)

rt = RightTriangle()
for e in rt:
    if len(e) > 20:
        break
    print(e)

自定义可迭代类版本的斐波那契数列

class Fibonacci:
    def __init__(self):
        self.a = 0
        self.b = 1
    def __iter__(self):
        return self
    def __next__(self):
        result = self.a
        self.a, self.b = self.b, self.a + self.b
        return result

fibs = Fibonacci()
for fib in fibs:
    print(fib, end=' ')
    if fib > 1000: break

将迭代器转换为列表

设置条件,抛出StopIteration异常,中断迭代!

class Fibonacci:
    def __init__(self):
        self.a = 0
        self.b = 1
    def __iter__(self):
        return self
    def __next__(self):
        result = self.a
        self.a, self.b = self.b, self.a + self.b
        # 设置条件,抛出StopIteration异常,中断迭代!
        if result > 1000: raise StopIteration
        return result
    
fibs = Fibonacci()
print(list(fibs))

生成器(Generator)

yield关键字

from sqlalchemy.util.compat import nested
def myGenerator():
    numList = [1, 2, 3, 4, 5, 6, 7, 8]
    for num in numList:
        yield num
        
for num in myGenerator():
    print(num, end = ' ')

print()
#######################################

nestedList = [[1, 2, 3], [4, 5, 6], [7, 8]]
def enumList(nestedList):
    for subList in nestedList:
        for element in subList:
            yield element

for num in enumList(nestedList):
    print(num, end = ' ')

print()
    
print(list(enumList(nestedList)))

另一个例子

nestedList = [[1, 2, 3], [4, 5], 20, [6, 7], [8, 9, 10]]

def enumList(nestedList):
    try:
        for subList in nestedList:
            for element in enumList(subList):
                yield element
    except TypeError:
        # 本例中,循环到20时会抛出TypeError, 此时的nestedList就是20
        yield nestedList
        
for num in enumList(nestedList):
    print(num, end = ' ')

防止字符串也被迭代

nestedList = [[1, 2, 3], [4, 5], 'abc', [6, 7], [8, 9, 10]]

def enumList(nestedList):
    try:
        
        # python 里面,字符串和数字不能直接相加,如果是字符串,会报错。
        # 这个步骤防止字符串被迭代
        try:nestedList + ''
        except:
            pass
        else:
            raise TypeError
        
        for subList in nestedList:
            for element in enumList(subList):
                yield element
    except TypeError:
        yield nestedList

for num in enumList(nestedList):
    print(num, end = ' ')

练习1:用类的迭代,做一个阶乘计算器

class Factorial:
    def __init__(self):
        self.result = 1 # 当前的阶乘结果
        self.n = 0      # 迭代的次数
    def __iter__(self):
        return self
    def __next__(self):
        self.n += 1
        # print('debug >>>>> {} * {}'.format(self.result, self.n))
        self.result = self.result * self.n
        return self.n, self.result
    
factorial = Factorial()
print('阶乘计算器')
for n, result in factorial:
    print('{}! = {}'.format(n, result))
    if n >= 10: break

练习2:阶乘计算器2.0

加入StopIteration,可以直接用list()方法返回列表了。

class Factorial:
    def __init__(self, max = 10):
        self.result = 1 # 当前的阶乘结果
        self.n = 0      # 迭代的次数
        self.max = max  # 最大迭代到几的阶乘
    def __iter__(self):
        return self
    def __next__(self):
        self.n += 1
        # print('debug >>>>> {} * {}'.format(self.result, self.n))
        self.result = self.result * self.n
        if self.n > self.max:
            raise StopIteration
        return self.n, self.result
    def reset(self):
        self.__init__();
    
factorial = Factorial()
print(list(factorial))

# 阶乘计算器使用之后,需要调用reset()方法,清空,否则就不能迭代2
print(list(factorial))
factorial.reset()

print(list(factorial))

f = Factorial(max = 5)
print(list(f))

练习3:Fibonacci数列

def fibonacci(n):
    '''
生成器
    '''
    if n < 1: raise Exception('请输入一个大于0的正整数')
    a, b = 1, 1    # a,前两项;b, 前一项
    for i in range(n):
        i += 1
        if i > n: raise StopIteration  # 终止
        if i == 1 or i == 2: 
            yield 1  # 前两项都是1
        else:
            result = a + b
            a, b = b, result
            yield result
        
for f in fibonacci(10):
    print(f, end = ' ')
print()  
    
class Fibonacci:
    '''
 迭代类
    '''
    def __init__(self, max = 10):
        self.a, self.b = 1, 1
        self.max = max    # 最大迭代到数列的第几个
        self.counter = 0  # 第几次迭代
    def __iter__(self):
        return self
    def __next__(self):
        self.counter += 1
        if self.counter > self.max: raise StopIteration
        if self.counter == 1 or self.counter == 2:
            return 1
        else:
            result = self.a + self.b
            self.a, self.b = self.b, result
            return result
        
f = Fibonacci()
print(list(f))

def fibonaccr2(n):
    '''
用迭代类做一个生成器
    '''
    fibs = Fibonacci(max = n)
    for fib in fibs:
        yield fib
        
for f in fibonaccr2(20):
    print(f, end = ' ')

你可能感兴趣的:(10. 方法、属性和迭代器)