python基础投资

Python--魔法方法学习

2017-11-16  本文已影响38人  Bling_ll

1、什么叫魔法方法?

2、__init__(self[,...])(构造器,注意前后都是双下划线)

3、__new__(cls[, ...])

4、__del__(self[, ...])

5、算术运算魔法方法

6、属性访问控制

7、描述符(property的原理)

描述符就是将某种特殊类型的类(类里含有下述魔法方法之一)的实例指派给另一个类的属性。

1、__get__(self, instance, owner):用于访问属性,它返回属性的值

2、__set__(self, instance, value):将在属性分配操作中调用,不返回任何内容

3、__delete__(self, instance):控制删除操作,不返回任何内容

class MyDecriptor:#称为描述符类
    def __get__(self,instance,owner):
        print("geting...",self,instance,owner)
    def __set__(self,instance,value):
        print("seting...",self,instance,value)
    def __delete__(self,instance):
        print("deleting...",self,instance)      
class Test:
    x = MyDecriptor() #此处说明MyDecriptor就是x的描述符,类似property使用
>>> test = Test()
>>> test.x #调用__get__方法
geting... <__main__.MyDecriptor object at 0x0000000003570FD0> <__main__.Test object at 0x0000000003570F98> <class '__main__.Test'>
#此处self:描述符类本身的一个实例 <__main__.MyDecriptor object at 0x0000000003570FD0>
#instance:拥有者类的实例 <__main__.Test object at 0x0000000003570F98>
#owner:拥有者类本身 <class '__main__.Test'>
>>> test.x ='哈哈哈' #调用__set__方法
seting... <__main__.MyDecriptor object at 0x0000000003570FD0> <__main__.Test object at 0x0000000003570F98> 哈哈哈
>>> del test.x #调用__delete__方法
deleting... <__main__.MyDecriptor object at 0x0000000003570FD0> <__main__.Test object at 0x0000000003570F98>

------------------------------------------------------------------------------------------------
#定义一个自己的property类
class MyProperty:#称为描述符类
    def __init__(self,fget=None,fset=None,fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
    def __get__(self,instance,owner):
        return self.fget(instance)
    def __set__(self,instance,value):
        self.fset(instance,value)
    def __delete__(self,instance):
        self.fdel(instance) 
class C:
    def __init__(self):
        self._x = None
    def getX(self):
        return self._x
    def setX(self,value):
        self._x = value
    def delX(self):
        del self._x
    x = MyProperty(getX,setX,delX)
>>> c = C()
>>> c.x = '哈哈' #直接以访问属性形式调用描述类MyProperty
>>> c.x
'哈哈'
>>> c._x
'哈哈'
>>> del c.x
>>> c._x
Traceback (most recent call last):
  File "<pyshell#125>", line 1, in <module>
    c._x
AttributeError: 'C' object has no attribute '_x'

8、容器类型-魔法方法

1、容器是对数据的封装

2、python的容器类型分为可变类型(如list、dict)和不可变类型(如string、tuple)。可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。

魔法方法 定义 备注
__len__(self) 求容器的大小(注意与capacity的区别) 可变和不可变容器均具备 __len____getitem__
__getitem__(self, key) 获取容器中指定元素的行为
__setitem__(self, key, value) 设置容器中指定元素的行为 只有可变容器拥有 __setitem____delitem__
__delitem__(self, key) 删除容器中指定元素的行为
__iter__(self) 定义迭代器中元素的行为
__reversed__(self) 当调用reversed()函数时 仅当序列可以是有序的时候实现它,例如对于列表或者元组。
__contains__(self, item) 成员运算符in/ not in的行为
class FunctionalList:
    ''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take'''
    def __init__(self, values=None):
        if values is None:
            self.values = []
        else:
            self.values = values
    def __len__(self):
        return len(self.values)
    def __getitem__(self, key):
        return self.values[key]
    def __setitem__(self, key, value):
        self.values[key] = value
    def __delitem__(self, key):
        del self.values[key]
    def __iter__(self):
        return iter(self.values)
    def __reversed__(self):
        return FunctionalList(reversed(self.values))
    def append(self, value):
        self.values.append(value)
    def head(self):
        # 获取第一个元素
        return self.values[0]
    def tail(self):
        # 获取第一个元素之后的所有元素
        return self.values[1:]
    def init(self):
        # 获取最后一个元素之前的所有元素
        return self.values[:-1]
    def last(self):
        # 获取最后一个元素
        return self.values[-1]
    def drop(self, n):
        # 获取所有元素,除了前N个
        return self.values[n:]
    def take(self, n):
        # 获取前N个元素
        return self.values[:n]
>>> a = FunctionalList([1,2,7,10,3])
>>> a.head()
1
>>> a.take(2)
[1, 2]
>>> a.init()
[1, 2, 7, 10]
>>> a.tail()
[2, 7, 10, 3]
>>> b = iter(a) #调用迭代器行为
>>> for i in b:
        print(i)    
1
2
7
10
3
>>> from collections import Iterator #可以使用isinstance()判断一个对象是否是Iterator对象
>>> isinstance(b, Iterator)
True

9、迭代器--魔法方法

1、可迭代对象Iterable:可以直接作用于for循环的对象统称为可迭代对象,使用isinstance()判断一个对象是否是Iterable对象。

>>> from collections import Iterable
>>> isinstance({}, Iterable)
True
>>> isinstance('hhh', Iterable)
True
>>> isinstance(10, Iterable)
False

2、迭代器Iterator:可以被next()函数调用并不断返回下一个值的对象称为迭代器,使用isinstance()判断一个对象是否是Iterator对象。

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
#生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
#把list、dict、str等Iterable变成Iterator可以使用iter()函数
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
>>> string = 'abcd'
>>> it = iter(string)
#每次调用next(it),就计算出it的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
>>> next(it) 
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
'd'
>>> next(it)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    next(it)
StopIteration
--------------------------------------------------------------------------------------------
#定义一个斐波那契迭代器
class Fibs:
    def __init__(self,n=10):
        self.a = 0
        self.b = 1
        self.n = n
    def __iter__(self):
        return self #返回迭代器本身
    def __next__(self):
        self.a,self.b = self.b,self.a+self.b
        if self.a > self.n:#控制迭代数量
            raise StopIteration
        else:
            return self.a       
>>> fibs = Fibs()
>>> for each in fibs:
    print(each) 
1
1
2
3
5
8

10、__call__(self,name)

任何类,只需要定义一个__call__()方法,就可以直接对实例(对象)进行调用。

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender
    def __call__(self, friend):
        print('My name is %s...' % self.name)
        print('My friend is %s...' % friend)        
>>> p = Person('Bob', 'male')
>>> p('Tim') #直接对实例进行调用,即是把这个类型的对象当作函数来使用
My name is Bob...
My friend is Tim...
#对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象。

如何判断一个变量是对象还是函数?(即判断一个对象是否能被调用,能被调用的对象就是一个Callable对象)

#用callabel()函数判断
>>> callable(Person('Bob', 'male'))
True
>>> callable(max)
True
>>> callable([1, 2, 3])
False

11、__str____repr__

__str__()返回用户看到的字符串,__repr__()返回程序开发者看到的字符串,即__repr__()是为调试服务的。

 class Animal(object):
    def __init__(self,name):
        self.name = name
>>> print(Animal('Cat')) #打印出来不好看
<__main__.Animal object at 0x0000000003558978>
#改进
class Animal(object):
    def __init__(self,name):
        self.name = name
    def __str__(self): #定义一个__str__()方法,返回一个好看的字符串
        return 'Animal object (name: %s)' % self.name   
>>> print(Animal('Cat'))
Animal object (name: Cat)
#但若不用print,打印出来的仍是不好看,因为直接显示变量调用的不是__str__(),而是__repr__()
>>> a = Animal('Cat')
>>> a
<__main__.Animal object at 0x0000000003558C18>
#解决:再定义一个__repr__()。但是通常__str__()和__repr__()代码都是一样的
class Animal(object):
    def __init__(self,name):
        self.name = name
    def __str__(self): 
        return 'Animal object (name: %s)' % self.name
    __repr__ = __str__ 
>>> print(Animal('Cat'))
Animal object (name: Cat)
>>> a = Animal('Cat')
>>> a
Animal object (name: Cat)
上一篇下一篇

猜你喜欢

热点阅读