python的__call__、__str__、__repr__、__init__、__class__、__name___、__all__、__doc__、__del__等魔术方法的作用
python中,一切都是对象
在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”--魔术方法
1、__call__:作用是把类实例变成一个可调用对象
在Python中,函数其实是一个对象:
>>> f = abs
>>> f.__name__
'abs'
>>> f(-123)
123
由于 f 可以被调用,所以,f 被称为可调用对象。
所有的函数都是可调用对象。
所有的函数都默认实现了方法"__call__",所以所有的函数的都是可以被调用的
>>> def f():
... print 2
...
>>> f.__name__
'f'
>>> f.__call__
<method-wrapper '__call__' of function object at 0x10d0ec230>
>>>
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。
我们把 Person 类变成一个可调用对象:
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
现在可以对 Person 实例直接调用:
>>> p = Person('Bob', 'male')
>>> p('Tim')
My name is Bob...
My friend is Tim...
单看 p('Tim') 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著。
但是如果,你这样定义类,不实现__call__():
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
>>> p=Person('Bob','male')
>>> p
<__main__.Person object at 0x1081a5e90>
>>> p('Tim')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Person' object is not callable
2、__str__:作用是把一个类的实例变成 str,打印显示
__repr__:作用是调用对象的返回值,
举例见差别:
未定义__str__()函数的情况
>>> class Person(object): ... def __init__(self, name, gender): ... self.name = name ... self.gender = gender ... >>> p=Person('Bob','male') >>> p <__main__.Person object at 0x108210490> >>> print p <__main__.Person object at 0x108210490>
定义__str__()函数,但是未定义__repr__()的情况: >>> class Person(object): ... def __init__(self, name, gender): ... self.name = name ... self.gender = gender ... def __str__(self): ... return '(Person: %s, %s)' % (self.name, self.gender) ... >>> p = Person('Bob','male') >>> p <__main__.Person object at 0x1081a5e90> >>> print p (Person: Bob, male)
同时定义__str__和__repr__的情况: >>> class Person(object): ... def __init__(self, name, gender): ... self.name = name ... self.gender = gender ... def __str__(self): ... return '(Person: %s, %s)' % (self.name, self.gender) ... __repr__=__str__ ... >>> p = Person('Bob','male') >>> p (Person: Bob, male) >>> print p (Person: Bob, male) >>>
分别定义__str__和__repr__的情况:
>>> class Person(object):
... def __init__(self, name, gender):
... self.name = name
... self.gender = gender
... def __str__(self):
... return '(Person: %s, %s)' % (self.name, self.gender)
... def __repr__(self):
... return 'xxxx'
...
>>> p=Person('Bob','male')
>>> p
xxxx
>>> print p
(Person: Bob, male)
>>>
3、__init__:作用是class的初始化函数,类似于Java/C++里的构造函数
4、__class__:作用,class的实例直接调用就表示生成实例的类
>>> class A:
... def __init__(self,url):
... self.url = url
... def out(self):
... return self.url
...
>>>
>>> a = A('news.163.com')
>>> print a.out()
news.163.com
>>>
>>> b = a.__class__('www.bccn.net')
>>> print b.out()
www.bccn.net
>>>
>>>
>>> print A
__main__.A
>>> print a.__class__
__main__.A
>>>
还有一种用法:
>>> def foo():
... pass
...
>>> foo.__class__
<type 'function'>
>>> foo.__name__
'foo'
>>>
5、__name__:表示函数的名字
>>> def a(): ... print 2 ... >>> f=a >>> f.__name__ 'a' >>> f <function a at 0x103996320> >>> f() 2 >>> f=a() 2 >>> f >>> f.__name__ Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'NoneType' object has no attribute '__name__' >>>
6、__slots__:用来限制class的实例动态添加属性: https://eastlakeside.gitbooks.io/interpy-zh/content/slots_magic/
由于Python是动态语言,任何实例在运行期都可以动态地添加属性。
如果要限制添加的属性,例如,Student类只允许添加 name、gender和score 这3个属性,就可以利用Python的一个特殊的__slots__来实现。
顾名思义,__slots__是指一个类允许的属性列表:
class Student(object):
__slots__ = ('name', 'gender', 'score')
def __init__(self, name, gender, score):
self.name = name
self.gender = gender
self.score = score
现在,对实例进行操作:
>>> s = Student('Bob', 'male', 59)
>>> s.name = 'Tim' # OK
>>> s.score = 99 # OK
>>> s.grade = 'A'
Traceback (most recent call last):
...
AttributeError: 'Student' object has no attribute 'grade'
__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。
可以使用工具ipython_memory_usage验证__slots__在节省内存上的作用,这个工具可以计算出每一条命令行使用的内存大小。安装这个工具的时候,mac下建议使用virtualenv环境,减免冲突问题: https://github.com/ianozsvald/ipython_memory_usage
class Person(object):
__slots__ = ('name', 'gender')
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Student(Person):
__slots__ = ('score',)
def __init__(self,name,gender,score):
super(Student,self).__init__(name,gender)
self.score=score
s = Student('Bob', 'male', 59)
s.name = 'Tim'
s.score = 99
print s.score
7、__all__的作用参见http://www.cnblogs.com/shengulong/p/7425088.html,主要用例class向外暴露接口
8、__doc__该属性用于描述该对象的作用。
9、__del__:与__init__构造函数相反,它是一个析构函数。
创建对象后,python解释器默认调用__init__()方法。当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法。在python中,对于开发者来说很少会直接销毁对象(如果需要,应该使用del关键字销毁)。Python的内存管理机制能够很好的胜任这份工作。也就是说,不管是手动调用del还是由python自动回收都会触发__del__方法执行。
举例:__del__对象只要在这个对象真正被删除时才会被调用。
import time class Animal(object): # 初始化方法 # 创建完对象后会自动被调用 def __init__(self, name): print('__init__方法被调用') self.__name = name # 析构方法 # 当对象被删除时,会自动被调用 def __del__(self): print("__del__方法被调用") print("%s对象马上被干掉了..."%self.__name) # 创建对象 dog = Animal("哈皮狗") # 删除对象 del dog cat = Animal("波斯猫") cat2 = cat cat3 = cat print("---马上 删除cat对象") del cat print("---马上 删除cat2对象") del cat2 print("---马上 删除cat3对象") del cat3 # 这个时候,__del__对象才会被调用
http://python.jobbole.com/88367/
https://pycoders-weekly-chinese.readthedocs.io/en/latest/issue6/a-guide-to-pythons-magic-methods.html