Python学习笔记之魔法方法

魔法方法(特殊方法):名称以双下划线和双下划线结尾的方法。

这些方法会在特殊情况下被Python直接调用,几乎没有直接调用的必要。

__init__():构造函数

__del__():析构函数

在其他语言中对象可能被要求属于某一个类,或被要求实现接口,但在Python中只是简单的要求它遵守几个给定的规则。

如一个序列类,为了实现规则,则需要实现以下魔法方法:

__len__(self):返回集合中所含项目的数量

__getitem__(self,key):返回与所给键对应的值

__setitem__(self,key,value):修改

__delitem__(self,key):在使用del语句时调用

#创建一个无穷序列

def checkIndex(key):
    if not isinstance(key,int):
        print('it\'s not a num')
        raise TypeError
    if key<0:
        raise ValueError
class ArithmeticSequence(object):
    """docstring for ArithmeticSequence"""
    def __init__(self, start = 0,step = 1):
        self.start = start
        self.step = step
        self.changed = {}

    def __getitem__(self,key):
        checkIndex(key)
        try:
            return self.changed[key]
        except KeyError:
            return self.start + key*self.step

    def __setitem__(self,key,value):
        checkIndex(key)
        self.changed[key] = value


s = ArithmeticSequence(1,2)
print(s[4])
s[4] = 2
print(s[4])
print(s['four'])

#运行结果
Traceback (most recent call last):
it's not a num
  File "F:\Python_Program\input.py", line 32, in <module>
    print(s['four'])
  File "F:\Python_Program\input.py", line 17, in __getitem__
    checkIndex(key)
  File "F:\Python_Program\input.py", line 6, in checkIndex
    raise TypeError
TypeError

对于这些特殊方法的实现可以直接通过继承列表等类。

 

property函数:

class  rectangle(object):
    """docstring for  rectangle"""
    def __init__(self):
        self.width = 0
        self.length = 0
    def set_size(self,size):
        self.width,self.length = size

    def getSzie(self):
        return self.width,self.length
    size = property(getSzie,set_size)

r = rectangle()
r.width = 5
r.length = 10
print(r.size)

property函数将size变成一个真正的特性,在使用property函数之前只可以通过访问器set_size和getSize来访问。

 

为了在访问特性时可以执行代码,必须使用以下魔法方法:

  • __getattribute__(self,name):当特性name被访问时自动调用
  • __getattr__(self,name):当特性name被访问且对象没有相应的的特性时自动调用
  • __setattr__(self,name,value):试图给特性name赋值时自动调用
  • __delattr__(self,name):试图删除特性时调用
class  rectangle(object):
    """docstring for  rectangle"""
    def __init__(self):
        self.width = 0
        self.length = 0
    def __setattr__(self,name,value):
        if name == 'size':
            self.width,self.length = value
        else:
            self.__dict__[name] = value
    def __getattr__(self,name):
        if name == 'size':
            return self.width,self.length
        else:
            raise AttributeError
    #size = property(getSzie,set_size)

r = rectangle()
r.width = 5
r.length = 10
print(r.size)

 

迭代器:

__iter__:迭代器规则的基础,会返回一个迭代器,迭代器就是一个具有__next__方法的对象,调用__next__方法时,迭代器会返回它的下一个值

class Fibs(object):
    """docstring for 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 s in fibs:
    if s > 1000:
        print(s)
        break
        

内建函数iter可以从可迭代对象中获得迭代器

class Fibs(object):
    """docstring for 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()
x = iter(fibs)
print(x.__next__())

#运行结果
1
[Finished in 0.9s]

 

生成器:一种用普通函数语法定义的迭代器,会返回一个迭代器。

以下举例说明生成器

对于一个嵌套列表的列表,打印列表中的数字

def flatten(nested):
    for sublist in nested:
        for i in sublist:
            yield i

nested = [[1,2,3],[2,3],[1]]
for num in (flatten(nested)):
    print(num)

1
2
3
2
3
1
[Finished in 0.1s]

任何包含yield的函数称为生成器,它每次产生多个值,每产生一个值函数就被冻结,函数被重新唤醒后就从停止那里开始执行。

如果要对内嵌类型不明的列表进行迭代

def flatten(nested):
    try:
        try:
            nested + ' '
        except TypeError:
            pass
        else:
            raise TypeError
        for sublist in nested:
            for i in flatten(sublist):
                yield i
    except TypeError:
        yield nested



nested = [[1,2,3],[2,3],1,'abc']
for num in (flatten(nested)):
    print(num)

 

posted @ 2017-08-26 12:54  HHello_World  阅读(309)  评论(0编辑  收藏  举报