python魔法_Python魔法

一、什么是Python魔法

Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradigm),你不仅可以使用面向对象的方式来编写程序,还可以用面向过程的方式来编写相同功能的程序(还有函数式、声明式等)。Python的多范式依赖于Python对象中的特殊方法(special method)。

特殊方法名的前后各有两个下划线。特殊方法又被称为魔法方法(magic method)。定义了许多Python语法和表达方式,正如我们在下面的例子中将要看到的。当对象中定义了特殊方法的时候,Python也会对它们有“特殊优待”。比如定义了__init__()方法的类,会在创建对象的时候自动执行__init__()方法中的操作。

可以通过dir()来查看对象所拥有的特殊方法,比如dir(1)。

运算符

Python的运算符是通过调用对象的特殊方法实现的。比如:

'abc' + 'xyz'     # 连接字符串

实际进行了如下操作:

'abc'.__add__('xyz')

所以,在Python中,两个对象是否能进行加法运算,首先就要看相应的对象是否有__add__()方法。一旦相应的对象有__add__()方法,即使这个对象从数学上不可加,我们都可以用加法的形式,来表达obj.__add__()所定义的操作。在Python中,运算符起到简化书写的功能,但它依靠特殊方法实现。

Python不强制用户使用面向对象的编程方法。用户可以选择自己喜欢的使用方式(比如选择使用+符号,还是使用更加面向对象的__add__()方法)。特殊方法写起来总是要更费事一点。

内置函数

与运算符类似,许多内置函数也都是调用对象的特殊方法。比如:

len([1,2,3])      # 返回表中元素的总数

实际上做的是

[1,2,3].__len__()

相对与__len__(),内置函数len()也起到了简化书写的作用。

对于内置的对象来说(比如整数、表、字符串等),它们所需要的特殊方法都已经在Python中准备好了。而用户自己定义的对象也可以通过增加特殊方法,来实现自定义的语法。特殊方法比较靠近Python的底层,许多Python功能的实现都要依赖于特殊方法。

二、一些常用的特殊方法

1、__doc__

表示类的常用信息

classFoo:"""描述类信息,这是用于看片的神奇"""

deffunc(self):pass

print(Foo.__doc__)#输出类的描述信息

__doc__

2. __module__ 和  __class__

__module__ 表示当前操作的对象在那个模块

__class__     表示当前操作的对象的类是什么

#!/usr/bin/env python#-*- coding:utf-8 -*-

classC:def __init__(self):

self.name= 'wupeiqi'

day6/aa.py

from lib.aa importC

obj=C()print obj.__module__ #输出 lib.aa,即:输出模块

print obj.__class__ #输出 lib.aa.C,即:输出类

index.py

3. __init__

构造方法,通过类创建对象时,自动触发执行。

classFoo:def __init__(self, name):

self.name=name

self.age= 18obj= Foo('wupeiqi') #自动执行类中的 __init__ 方法

print(obj.name, obj.age)

View Code

4. __del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

classFoo:def __del__(self):pass

View Code

5. __call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

classFoo:def __init__(self):pass

def __call__(self, *args, **kwargs):print '__call__'obj= Foo() #执行 __init__

obj() #执行 __call__

View Code

6. __dict__

Python中,一切皆对象,这些对象是由一个类型实例化而来;那么说,这些对象就有属性和方法,属性可以存储一些值。而从直观上来看,任何可以存储东西的事物,我们都可以说它有一个空间(只有有空间,才能存储东西嘛),而在编程中,我们一般使用术语“名字空间”或“命名空间”(namespace)来称呼它。这样,我们就得出,每个对象都有一个名字空间。而在Python中,我们使用对象的__dict__属性来保存该对象的名字空间中的东西,__dict__是一个字典(“键-值”对,一般“键”就是属性名或方法名,“值”就是属性的值或方法名所指向的真正的方法实体对象)。

classProvince:

country= 'China'

def __init__(self, name, count):

self.name=name

self.count=countdef func(self, *args, **kwargs):print('func')#获取类的成员,即:静态字段、方法、

print(Province.__dict__)#输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}

obj1= Province('HeBei',10000)print(obj1.__dict__)#获取 对象obj1 的成员#输出:{'count': 10000, 'name': 'HeBei'}

obj2= Province('HeNan', 3888)print(obj2.__dict__)#获取 对象obj1 的成员#输出:{'count': 3888, 'name': 'HeNan'}

View Code

7. __str__

如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

classFoo:def __str__(self):return 'flash'obj=Foo()print(obj)#输出:flash

View Code

8、__getitem__、__setitem__、__delitem__、__getattribute__

在Python中,重载__getattr__、__setattr__、__delattr__和__getattribute__方法可以用来管理一个自定义类中的属性访问。其中,__getattr__方法将拦截所有未定义的属性获取(即,当要访问的属性已经定义时,该方法不会被调用,至于定义不定义,是由Python能否查找到该属性来决定的);__getattribute__方法将拦截所有属性的获取(不管该属性是否已经定义,只要获取它的值,该方法都会调用),由于此情况,所以,当一个类中同时重载了__getattr__和__getattribute__方法,那么__getattr__永远不会被调用,另外,__getattribute__方法仅仅存在于Python2.6的新式类和Python3的所有类中;__setattr__方法将拦截所有的属性赋值;__delattr__方法将拦截所有的属性删除。说明:在Python中,一个类或类实例中的属性是动态的(因为Python是动态的),也就是说,你可以往一个类或类实例中添加或删除一个属性。

#!/usr/bin/env python#-*- coding:utf-8 -*-

classFoo(object):def __getitem__(self, key):print '__getitem__',keydef __setitem__(self, key, value):print '__setitem__',key,valuedef __delitem__(self, key):print '__delitem__',key

obj=Foo()

result= obj['k1'] #自动触发执行 __getitem__

obj['k2'] = 'wupeiqi' #自动触发执行 __setitem__

del obj['k1'] #自动触发执行 __delitem__

View Code

10. __iter__

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

#!/usr/bin/env python#-*- coding:utf-8 -*-

obj= iter([11,22,33,44])for i inobj:print(i)

11. __new__ 和 __metaclass__

阅读以下代码:

class Foo(object):

def __init__(self):

pass

obj = Foo() # obj是通过Foo类实例化的对象

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

print(type(obj)) # 输出: 表示,obj 对象由Foo类创建

print(type(Foo)) # 输出: 表示,Foo类对象由 type 类创建

所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

那么,创建类就可以有两种方式:

a) 普通方式

class Foo(object):

def func(self):

print 'hello flash'

b) 特殊方式

def func(self):

print 'hello flash'

Foo = type('Foo',(object,), {'func': func})

#type第一个参数:类名

#type第二个参数:当前类的基类

#type第三个参数:类的成员

obj = Foo()

obj.func()

#输出结果:hello flash

==》 类 是由 type 类实例化产生

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

1 classMyType(type):2

3 def __init__(self, what, bases=None, dict=None):4 super(MyType, self).__init__(what, bases, dict)5

6 def __call__(self, *args, **kwargs):7 obj = self.__new__(self, *args, **kwargs)8

9 self.__init__(obj)10

11 classFoo(object):12

13 __metaclass__ =MyType14

15 def __init__(self, name):16 self.name =name17

18 def __new__(cls, *args, **kwargs):19 return object.__new__(cls, *args, **kwargs)20

21 #第一阶段:解释器从上到下执行代码创建Foo类

22 #第二阶段:通过Foo类创建obj对象

23 obj = Foo()

View Code

三、反射

python中的反射功能由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 deffunc(self):7 return 'func'

8

9 obj =Foo()10

11 ##### 检查是否含有成员 ####

12 print(hasattr(obj, 'name'))13 print(hasattr(obj, 'func'))

hasattr

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 deffunc(self):7 return 'func'

8

9 obj =Foo()10

11

12 ##### 获取成员 ####

13 print(getattr(obj, 'name'))14 print(getattr(obj, 'func'))

getattr

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 defage(self):7 return '18'

8

9 obj =Foo()10

11 ##### 设置成员 ####

12 setattr(obj, 'name', 'tony')13 print(obj.name)

setattr

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 obj =Foo()7

8 ##### 删除成员 ####

9 delattr(obj, 'name')10 print(hasattr(obj, 'name'))11

12

13 #输出结果:False

delattr

需求:代码如下,使用其他方式获取obj对象中的name变量指向内存中的值 “flash”

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 #不允许使用 obj.name

7 obj = Foo()

有以下两种方式:

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 #不允许使用 obj.name

7 obj =Foo()8

9 print(obj.__dict__['name'])

方法一

1 classFoo(object):2

3 def __init__(self):4 self.name = 'flash'

5

6 #不允许使用 obj.name

7 obj =Foo()8

9 print(getattr(obj, 'name'))

方法二

附录:如何调用魔术方法

一些魔术方法直接和内建函数相对,在这种情况下,调用他们的方法很简单,但是,如果是另外一种不是特别明显的调用方法,这个附录介绍了很多并不是很明显的魔术方法的调用形式。

参考:

http://www.cnblogs.com/vamei/archive/2012/11/19/2772441.html

http://www.cnblogs.com/wupeiqi/articles/5017742.html

http://pycoders-weekly-chinese.readthedocs.io/en/latest/issue6/a-guide-to-pythons-magic-methods.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值