嗨玩手游网

Python 魔法方法与属性

python的魔法方法很奇特,有些地方也称他为特殊方法。其结构是由两个下划线(“”开始中间名称最后以两个下划线(“”)结束的特殊指定方法,这有点类似java中的接口和abstract,是python中定义的一种规则,一种玩法。

这也是python与java对于方法重写的一个较大的不同的地方.Java中我们可能会为了实现某种或某类相似的动作行为(action),从而使用接口式编程,抽象方法来抽象实现过程从而实现其多态性,而且子类(非抽象类)继承了抽象父亲或者实现了接口后,必须要是实现所继承父类或接口的抽象方法,可以明显发现Java中的多态是基于对象的(父类或接口),而python中的“接口实现方式”方式与其有很大的不同。

python中的多态是基于动作和特性的实现的,即操作动作决定方法实现,只要对象实现了对应的魔法方法就可使用python中的某些特殊操作方式对该对象进行操作,而一般这种”特殊操作“的本质是将其内到python的内建函数的操作中。而内建函数操作的本质是根据区分操作对象的数据结构进行调用的,所以木法方式的作用是通过重写类的魔法方法从而实现将类转化为某类数据结构类型的作用(常见的结构类型有:序列、映射、集合和特殊的结构类型迭代器等)。所以魔法方法的大部分内容是围绕如下几个部分的(类,方法,重写,内建函数,数据结构)来展开的。可以分为如下几个部分进行分段了解:

内建函数类的方法类的属性魔法方法的使用参考内建函数

python内建函数是一个比较重要的功能,内建函数在某些特定的情况下可以代码的复杂性和增强代码的可读性,内建函数是存在于python的’* builtins ‘模块的一些函数,相对于其他模块,存在于’ buildins‘模块的函数与变量并不需要我们通过import导入,属于python内置模块.内建函数的介绍链接Python 内建函数,也可以借助python本省来了解.可以通过dir(builtins)来获取* builtins 中的对象和函数:

print "all params of Built-in :\n"print dir(__builtins__),"\n"#显示__builtins__模块的所有信息#print "__builtins__ hep info:\n"#help(__builtins__) #显示内置函数的基本用法介绍#classmethod help doc#help(classmethod) #staticmethod help doc#help(staticmethod)#iter help doc#help(iter)help(next)

all params of Built-in :['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '__IPYTHON__', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'dreload', 'enumerate', 'eval', 'execfile', 'file', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] Help on built-in function next in module __builtin__:next(...) next(iterator[, default]) Return the next item from the iterator. If default is given and the iterator is exhausted, it is returned instead of raising StopIteration.

内置函数中有dir可以获取python中的模块信息,还有类似abs之类的数学计算的函数。如下,仅仅介绍几个和魔法方法y以及和类相关的内置函数:

classmethod(function)

将方法function封装成类的方法,被定义成装饰器(decorator),具体实现可以通过两种方式,一种是直接通过装饰器定义,被装饰器修饰的方默认被传入该方法,也可以直接通过方法调用实现,与其类似的有staticmethod函数示例如下:

class A: #装饰器 @classmethod def methodA(cls,args): '''method body''' def classB(cls): print "this is class method" #使用方法调用. classB=classmethod(classB)staticmethod

用法和classmethod基本一致,如下:

class A: #装饰器 @staticmethod def methodA(args): '''method body''' def methodB(): print "this is static method" #使用方法调用. methodB=classmethod(methodB)iter(source, sentinel=None)

对于iter的介绍,在文档的介绍和python官方文档还是有些区别的,官方doc中的介绍如下:

iter(…)iter(collection) -> iteratoriter(callable, sentinel) -> iterator

Get an iterator from an object. In the first form, the argument mustsupply its own iterator, or be a sequence.In the second form, the callable is called until it returns the sentinel.

对于iter中的第一个参数定位为一个iterator or a sequence,但是在官方doc中有不同的介绍:

The first argument is interpreted very differently depending on the presence of the second argument. Without a second argument, o must be a collection object which supports the iteration protocol (the iter() method), or it must support the sequence protocol (the getitem() method with integer arguments starting at 0). If it does not support either of those protocols, TypeError is raised. If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

为此,我进行了一个测试:

class B(object): passclass A(): def __call__(self, *args, **kwargs): print "[call,her,2]"a1=iter(A(),"a")print a1.next()b=B() a=iter(b,"2")print a.next()

[call,her,2]None---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-18-6e1b318bdd62> in <module>() 9 print a1.next() 10 b=B()---> 11 a=iter(b,"2") 12 print a.next()TypeError: iter(v, w): v must be callable

如上,可以发现,iter(…)的要求和python官方的doc 要求一致,文档并不能完全介绍完全。当第二参数非空时,需要要求第一参数为实现类迭代功能的对象,如下会介绍(当类实现iter方法),当第二参数存在时,第一个参数必须为可调用对象(实现了call方法)。

len(s)

返回一个对象的长度,传入对象可以是list、string、tuple等,也可以是一个类实现了一个魔法方法(len).

next(…)

返回一个iterator的下一个元素,传入的对象位一个实现了_next_方法的对象

next(…)next(iterator[, default])

Return the next item from the iterator. If default is given and the iteratoris exhausted, it is returned instead of raising StopIteration.类的方法

类的方法分为类的创建方法(_new_),类的初始化方法(_init_),类的方法(classmethod),类的静态方法(staticmethod),类的方法,类的销毁方法(_del_),和类的魔法方法(之后介绍)如下通过一个示例介绍各个类型方法.

class Base(object): 'a basic class demo' def __new__(cls, *args, **kwargs): print "__new__" return object.__new__(cls,*args, **kwargs) def __init__(self): print "__init__" def __del__(self): print "__del__" @classmethod def A(cls): print "class method" @staticmethod def B(): print "static method" def C(self): print "this is self" def __str__(self): return "build-in str(o) return " def __del__(self): print "__del__"if __name__=="__main__": a=Base() print str(a) try: print "Begin transfer-----------------------------call by instance." #call the class method a.A() #call static method a.B() #call the instance method a.C() print "Begin transfer------------------------------call by Class" # call the class method Base.A() # call static method Base.B() #call instance method Base.C(Base()) #call instance method Base.C() pring except Exception as e: print e del(a)

__new____init__build-in str(o) return Begin transfer-----------------------------call by instance.class methodstatic methodthis is selfBegin transfer------------------------------call by Classclass methodstatic method__new____init__this is self__del__unbound method C() must be called with Base instance as first argument (got nothing instead)__del___new_ 方法_new_ 方法是一个静态方法(同时也是一种魔法方法),用于创建一个类的实例,返回一个类的实例对象用于传入初始化方法_ init_ 中,一般并不需要对其进行声明和重写。若是重写的话,需要注意返回一个有效的类的实例对象,如上实例通过object父类调用类的实例化方法,用于返回一个对象实例。若是不返回一个类的实例对象,会导致类的 _ init_ 方法不会被调用,当然实例(self为空)也不会被成功创建。_init_ 方法_init_ 是类创建过程中用的比较多的魔法方法,其是类对象创建后调用的初始化方法,紧跟者new 调用后调用,主要用于实例的变量的初始化操作,和传递类创建传入的变量,init 方法可以理解为一个类的实例的构造器,其方法的特点是不会返回任何对象或者值,若返回则会抛出 TypeError 异常。_del_ 方法同样属于魔法方法一种。如上,可以发现当我们调用del(a)来销毁实例对象时,会调用该方法,其该属类的实例的析构函数,del内建函数并不会主动调用del方法,只有当类的实例对象的引用计数为0时才会被调用,要我们主动显示的调用 del 方法完成实例的销毁操作.因此,一般不建议重写del 方法。_str方法用于返回对象的string 字段信息,重写该魔法方法的实例可以通过调用内建函数 str(o) 来回调 _str 方法。如上示例有所演示。classmethod 方法类的方法,类的方法调用层级归属类级别,其方法定义需要使用 @classmethod 装饰或者调用classmethod内建方法来实现,类的方法的第一个参数默认为类的对象,使用cls 固定表示,如上的 B方法,类的方法和静态方法一样可以通过类的实例对象调用,也可以直接通过类来调用.staticmethod方法静态方法,通过装饰器@staticmethod 或者内建函数声明使用,静态方法的方法定义部分python的一般函数定义并无不同,页不需要如同classmethod或实例方法一样传入类的对象或实例的对象,其调用和classmethod类似,可以直接通过类调用或者类的实例对象调用。实例 方法实例方法是归属与创建的实例对象所私有,定义如上def C(self): 其方法需要传入一个实例对象self,且位置为第一个参数,该方法只能由类的实例来调用,不可以通过类直接调用(无参数),若需要通过类直接调用可以通过绑定式的方式将类的实例对象传入该方法中:* Base.C(Base()) * 。类的属性

类的属性部分主要分为两个小部分进行介绍:归属类或实例对象的自定义属性,归属行为特征所共有定义的魔法属性,给出一个简单的例子,根据案例说明。

class Base(object): CLASS_NAME="Base" instanceCount=0 __instance=12 _aa=1234 def __init__(self,name,value): BasestanceCount+=1 self=name self.value=value def __str__(self): return "CLASS_NAME:%s,instanceCount:%s,self:%s,self.value:%s \n" % (Base.CLASS_NAME,BasestanceCount,self,self.value)a=Base("a",10)print "a:[%s}\n" % str(a)b=Base("b",12)print "b:[%s}\n"% str(b)print b.__dict__,"\n"print Base.__dict__,"\n"print Base._instance

a:[CLASS_NAME:Base,instanceCount:1,self:a,self.value:10 }b:[CLASS_NAME:Base,instanceCount:2,self:b,self.value:12 }{'name': 'b', 'value': 12} {'__dict__': <attribute '__dict__' of 'Base' objects>, '__module__': '__main__', 'instanceCount': 2, '_Base__instance': 12, '_aa': 1234, 'CLASS_NAME': 'Base', '__str__': <function __str__ at 0x7f7a142256e0>, '__weakref__': <attribute '__weakref__' of 'Base' objects>, '__doc__': None, '__init__': <function __init__ at 0x7f7a14190ed8>} ---------------------------------------------------------------------------AttributeError Traceback (most recent call last)<ipython-input-26-25ca76d45fc7> in <module>() 21 print b.__dict__,"\n" 22 print Base.__dict__,"\n"---> 23 print Base._instanceAttributeError: type object 'Base' has no attribute '_instance'类的属性如上,类的属性也可以认为是静态属性,可以直接通过类来调用,CLASS_NAME和instanceCount就是这样的属性.实例属性实例属性是归属于实例对象本身的,需要直接使用实例对象来调用,如上的self和self.value“私有属性“python中并不存在只能从内部访问的私有变量类型,但python代码都遵守的公约规定:带有下划线(‘‘)前缀开头的变量或方法被示为飞公开API的一部分,其有两种情况,一种是前面至少有两个下划线(‘‘)开头,后面之多有一个下划线(‘‘)结束,python对其使用name mangling机制做了一个简单的支持,会将其标识符替换成_className__name,如上__instance ,另一种是以一个”“开始的变量在被作为一个module导入时,使用 from module import * 后并不可以直接使用其直接使用,还是需要通过类或者实例变量配合使用.魔法属性python中的魔法属性是对类或实例的一些数据的描述整合.如上的”dict“位一个字典映射对象,存储一个类或者实例的可读属性。类似的魔法属性还包括:class_、*_bases、name、mro、subclasses等。魔法方法的使用

如上,已经说了不少有关魔法方法的使用,如new、init、del等特定的类生命周期相关的魔法方法,也有功能性的如str等,如下,就是对于魔法方法做一个扩展性的说明。

魔法方法的存在是python的多态性的一种表现,不同其他语言的多态,python的多态更多的表现在动作或者称作功能上,对于想要实现某类功能的类只需要对应实现某些对应的魔法方法,即可通过python的内建函数进行某些特定功能的操作。如常见的求长度、求hash数值、迭代器、生成器的使用。如下,通过一个小的示例来了解一些常用的魔法方法。

class Base(object): def __init__(self): selfdex = 0 print "base __init__" # 返回字符串化 def __str__(self): return "Base" # # 返回对象长度 def __len__(self): return 10 # 返回hash数值 def __hash__(self): return 199908 # 真值判断 def __nonzero__(self): return True # 返回转化成一个unicode对象 def __unicode__(self): return u'海飞' # 当查找一个一个属性未查找到时调用 def __getattr(self, name): if name == "name": return "hfcai" else: raise Exception("No exists tohis attribute.") #当尝试给一个属性赋值时调用 def __setattr__(self, name, value): self.__dict__[name] = value # 当属性被删除时调用 def __delattr__(self, name): print "__delattr__:%s" % name # 新式类中访问属性的调用,使用超类的方法防止循环调用 def __getattribute__(self, name): return super(Base,self).__getattribute__(name) # 新式类作为描述器 def __get__(self, obj, type=None): return 'get', self, obj, type def __set__(self, obj, val): print 'set', self, obj, val def __delete__(self, obj): print 'delete', self, obj # # # 接受self[key]这样的切片操作,一般针对于序列对象 def __getitem__(self, key): return self.__dict__[key] def __setitem__(self, key, value): print "__setitem__" def __delitem__(self, key, value): print "__delitem__" # 迭代器 ,重写表明当前类的示例为一个迭代器 def __iter__(self): return self # next def next(self): selfdex+=1 return selfdex # 返回一个反向的迭代对象 def __reversed__(self): return [9, 8, 7, 6] # 含操作 def __contains__(self, item): return Truea = Base()#__contain__print "test" in a# __iter__b = iter(a)print b.next()# __len__print len(a)print reversed(a)print str(a),unicode(a)

base __init__True110[9, 8, 7, 6]Base 海飞

如上,涉及到的魔法方法较多,分类讲解一部分的魔法方法,其用法类似:

普通关联回调内建函数这种比较简单,在类中重写对应的魔法方法,使用对应的回调返回重写方法的返回值,大多的魔法方法都是这类的,如上len、str、unicode等就属于这类。属性相关魔法方法与属性相关的魔法方法getattr、setattrr、getitem、_setitem、getattribute,其中getitem、_setitem属于序列或映射的魔法方法,而getattr、setattrr属于获取类中的变量的属性的设置获取调用情况。其中getattr 属于当类中无法获取该变量时调用,而getattribute会拦截所有属性的获取。描述器对于实现了get、set、del魔法方法的类可以称之位描述器.同时具有get和set方法,这样的descriptor叫做data descriptor,如果只有get方法,则叫做non-data descriptor。迭代器python中的迭代器是实现了iter魔法方法的类,并通过实现 next(self)方法进行迭代调用,如上示例。生成器python中有一个特别的迭代器,可以通过关键词yield进行迭代返回,如下格式:

def reperater(value): while True: new = (yield value) if new is not None: value=newr=repeater(42)r.next()42r.send("Hello world!")"Hello world!"

如上demo来自《python基础教程 -生成器》一章的示例,其中包含yeild会返回一个对象,并挂起。而在挂起状态可以通过send方法发送一个值,而再次返回发送过的值.

如何用魔法打败魔法

要问高考数学哪道题最令人头疼?我想大多数人都会认为是圆锥曲线,那计算量也是没谁了。

当时总想着,要是能用量角器和尺子对着图把待求的长度和角度直接测出来,还费那些事干啥。

这种不着调的方法,情商高一点的人会称之为“师夷长技以制夷”,情商低的直接叫耍赖皮。它之所以屡试不爽,核心就四个字:反复横跳!有的人计算不好,OK!咱跳去测量,读数总没问题的吧;有的人老花,看不清刻度,没问题!咱跳回推导,把字放大肯定能看清,总有一款适合你!

通过反复横跳来寻找最适合的方法,看似无厘头,实则体现着深刻的科学思想。在现代力学中,这种方法被赋予了一个高大上的名字:比拟法。即如果两种力学现象对应于同一数学本质,则它们之间可以相互类比,以便使用其中一种(容易的)来模拟另一种(复杂的)。

简单来说,就是24字箴言:绝不正面硬刚,也不直面困难,奉行拿来主义,魔法打败魔法!

回到刚才的问题,以建立坐标系为基础的解析法和以尺子量角器为工具的测量法对应于同一个数学本质:欧氏几何,它就像一座桥联系着两种方法。对于无法直接或不方便测量的问题,采用解析法可以得到想要的结果;而对于某些解析求解过于复杂的问题,往往直接测量能起到很好的效果。哪个方法困难我就转向另一个,对!就是来回变!对应前12字:“绝不正面硬刚,也不直面困难”。

拿来主义的先驱是赫兹,他的老本行是电磁学,偶尔搞搞力学。25岁的赫兹某天突然发现,控制两个固体表面的接触区域形状的积分方程,竟然和带电椭球的电势分布的积分形式一模一样。好家伙,梦幻联动了属于是,赶紧拿来!

健身贴士

于是的他便将电磁学中发展成熟的理论直接照搬到了力学中,由此创立接触力学。这正是后12字:“奉行拿来主义,魔法打败魔法”。

类似的,关于弹性杆扭转的“薄膜比拟”,关于塑性杆扭转的“沙堆比拟”,以及结构振动理论中的“力-电路比拟”,无一不透露出比拟法的精髓。你说复杂边界条件下的泊松方程不好解,没问题,咱不解了,费啥脑细胞。直接找个保鲜膜照着边界形状剪下来,绷紧了再往上撒点小沙子,测一积,要求的扭矩不就出来了,甚至连塑性问题都一并解决了,齐活儿!

你又说线性常微分方程组变量太多不好解,OK,知难而退。去旁边电子城买点电源电阻电容啥的,顺着搭个简单电路,然后直接拿来基尔霍夫定律,对着电流电压表读数总可以吧,照样能给出关于结构振动的全部信息。

由此可见,比拟法在现代力学中发挥了举足轻重的作用。虽说搞学问不得“取巧”,但在山重水复疑无路时,能审时度势,开拓思路,拿来(情商高:借鉴)其它领域的先进成果,用魔法打败魔法,有时还真能柳暗花明又一村。

#时事热点头条说#

更多攻略
游戏推荐
更多+