这篇博客主要是阅读python之旅 时做的笔记。提取出最主要的知识点,供个人在以后中快速查阅。
多态:对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为。 直接看例子吧,因为太简单了。
class Animal(object): def __init__(self, name): self.name = name def greet(self): print 'Hello, I am %s.' % self.nameclass Dog(Animal): def greet(self): print 'WangWang.., I am %s.' % self.nameclass Cat(Animal): def greet(self): print 'MiaoMiao.., I am %s' % self.namedef hello(animal): animal.greet()>>> dog = Dog('dog')>>> hello(dog)WangWang.., I am dog.>>>>>> cat = Cat('cat')>>> hello(cat)MiaoMiao.., I am cat注意:类方法可有类或者实例调用,不过定义该方法时要传入cls参数,该参数代表了类本身,通过cls可以调用类中的属性和方法。
静态方法主要是运行时不需要实例和类参与,不需要传入任何参数。
在python中,经常会看到前后两个下划线的方法。这些方法称为魔法方法或者特殊方法。有特殊的功能,下面是常用的特殊方法:
__new____str__ , __repr____iter____getitem__, __setitem__, __delitem____getattr__, __setattr__, __delattr____call__创建实例时,调用__new__, 再 __init__对实例(self)进行初始化 - __new__ 是在 __init__ 之前被调用的; - __new__ 是类方法,__init__ 是实例方法; - 重载 __new__ 方法,需要返回类的实例;
一般情况下,我们不需要重载 __new__ 方法。但在某些情况下,我们想控制实例的创建过程,这时可以通过重载 __new_ 方法来实现。
class A(object): _dict = dict() def __new__(cls): if 'key' in A._dict: print "EXISTS" return A._dict['key'] else: print "NEW" return object.__new__(cls) def __init__(self): print "INIT" A._dict['key'] = self在上面,我们定义了一个类 A,并重载了 __new__ 方法:当 key 在 A._dict 中时,直接返回 A._dict[‘key’],否则创建实例。
>>> a1 = A()NEWINIT>>> a2 = A()EXISTSINIT>>> a3 = A()EXISTSINIT简单来说,就是如果直接print一个类的对象的话,就会得到类似 <__main__.Foo object at 0x10c37aa50>
。然而有时候我们就想显示这个类的对象的信息,此时就可以用__str__, 该函数表示,当print这个类的对象时,所输出该对象的信息。
你可能会说,哎呀, Foo(‘ethan’) 就没法显示这个对象的信息吗?我看这<__main__.Foo at 0x10c37a490>
东西有啥用啊。__repr__就是让 Foo(‘ethan’)也显示类似加了print的效果。
一句话:对象可用于 for … in 循环,此时要定义 __iter__ 和 next (Python3中是 __next__方法)。__iter__ 返回一个迭代对象,__next__ 返回容器的下一个元素,在没有后续元素时抛出 StopIteration 异常。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 def __iter__(self): # 返回迭代器对象本身 return self def next(self): # 返回容器下一个元素 self.a, self.b = self.b, self.a + self.b return self.a >>> fib = Fib()>>> for i in fib:... if i > 10:... break... print i...112358就是使用obj[n]的方式对实例对象取值
class Fib(object): def __getitem__(self, n): if isinstance(n, slice): # 如果 n 是 slice 对象 a, b = 1, 1 start, stop = n.start, n.stop L = [] for i in xrange(stop): if i >= start: L.append(a) a, b = b, a + b return L if isinstance(n, int): # 如果 n 是 int 型 a, b = 1, 1 for i in xrange(n): a, b = b, a + b return a>>> fib = Fib()>>> fib[0:3][1, 1, 2]>>> fib[2:6][2, 3, 5, 8]当我们获取对象的某个属性,如果该属性不存在,会抛出 AttributeError 异常,而__getattr__就能避免这个异常。
class Point(object): def __init__(self, x=0, y=0): self.x = x self.y = y def __getattr__(self, attr): if attr == 'z': return 0 raise AttributeError("Point object has no attribute %s" % attr)>>> p = Point(3, 4)>>> p.z #只有调用不存在的属性时,/__getattr__才会起作用0>>> p.w AttributeError: Point object has no attribute w这个比较有意思。一般来说obj.method()来调用对象的方法。 能不能简单点啊,直接obj()来啊。
class Point(object): def __init__(self, x, y): self.x, self.y = x, y def __call__(self, z): return self.x + self.y + z>>> p = Point(3, 4)>>> callable(p) # 使用 callable 判断对象是否能被调用True>>> p(6) # 传入参数,对实例进行调用,对应 p.__call__(6)13 # 3+4+6是是是是,我们可以定义类的时候加上属性和方法,但是有时候我们有了个实例,只想给这个实例加上一些新的属性和方法。。(要求真多。。)当然了,最简单的方法直接弄就行。有时候我们也不希望别人乱加属性。 slots:限定允许绑定的属性
class Point(object): __slots__ = ('x', 'y') # 只允许使用 x 和 y属性 def __init__(self, x=0, y=0): self.x = x self.y = y>>> p = Point(3, 4)>>> p.z = 5AttributeError: 'Point' object has no attribute 'z'如果是下面的情况
class Point(object): __slots__ = ('x', 'y','z') def __init__(self, x=0, y=0): self.x = x self.y = yp = Point(3,4) p.z = 5 #此时可以添加属性z了一个注意点:__slots__只能限定当前类,不能限定子类。除非子类也定义了 slots,这样,子类允许定义的属性就是自身的 slots 加上父类的 slots。
有些属性我们希望对其访问进行限制,比如下面的score, 我们总不能让别人随便设置score的值吧。所以一般要定义两个函数,set_score和get_score分别表示对score的读取和赋值进行限定。 比如:
class Exam(object): def __init__(self, score): self._score = score def get_score(self): return self._score def set_score(self, val): if val < 0: self._score = 0 elif val > 100: self._score = 100 else: self._score = val>>> e = Exam(60)>>> e.get_score()60>>> e.set_score(70)>>> e.get_score()70但你不感觉这样写很麻烦吗?回顾一下C#中的。不是有set和get的访问器吗? 比如下面的通过函数Code的get和set进行自定义限定code属性。
class Student { private string code = "N.A"; // 声明类型为 string 的 Code 属性 public string Code { get { return code; } set { code = value; } } }当然啊,python也有类似的。不过感觉写起来很繁琐。。唉唉 注意:get属性的话直接加上@property装饰器就行,然而set属性的话,就要加上类似@score.setter装饰器。。当然类似的,如果去掉 @score.setter装饰器的话,score就变成只读属性了。还敢说这样写不麻烦。。。
class Exam(object): def __init__(self, score): self._score = score @property def score(self): return self._score @score.setter def score(self, val): if val < 0: self._score = 0 elif val > 100: self._score = 100 else: self._score = val>>> e = Exam(60)>>> e.score60>>> e.score = 90>>> e.score90>>> e.score = 200>>> e.score100从上面可以看出。super貌似是直接在子类中调用父类的方法,从而减少劳动。。 然而如果是下面这样的继承方式。。
class Base(object): def __init__(self): print "enter Base" print "leave Base"class A(Base): def __init__(self): print "enter A" super(A, self).__init__() print "leave A"class B(Base): def __init__(self): print "enter B" super(B, self).__init__() print "leave B"class C(A, B): def __init__(self): print "enter C" super(C, self).__init__() print "leave C"可以看到,进入A之后,再调用super,并不是进入Base,而是进入了B。
事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序。mro可以获取类的MRO列表.
>>> C.mro() # or C.__mro__ or C().__class__.mro()[__main__.C, __main__.A, __main__.B, __main__.Base, object]MRO列表的顺序是根据C3线性化算法来定的。
cls代表类,inst代表实例 - 获取 inst 的 MRO 列表 - 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
所以super(C, self).__init__()
的解析方式不就是先C, 再A,再B,最后再Base了。
这个还是直接看原文吧
新闻热点
疑难解答