在Python中,有的名称会在前面和后面加上两个下划线,这种拼写表示名字有特殊含义,所以绝不要在自己的程序中使用这种名字。在Python中,由这些名字组成的集合所包含的方法称为魔法方法。他们是可以给类增加”magic”的特殊方法。
构造方法 __init__ 是一个很奇特的名字,它代表着类似于以前例子中使用过的那种名为init的初始化方法,但构造方法和其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法。在Python所有的魔法方法中,__init__ 是使用最多的一个。
Python中有一个魔法方法叫做 __del__,它在对象就要被垃圾回收之前调用,但发生调用的具体时间是不可知的,所以建议尽力避免使用 __del__ 方法。
class A:
def __init__(self):
self.value = 10
f = A()
f.value # 10
'''
super()
用于调用父类(超类)的一个方法。super函数很智能的,即使类已经继承多个超类,它也只需使用一次super函数(但要确保所有的超类的构造方法都使用了super函数)。
super函数返回了一个super对象,这个对象负责进行方法解析,当对其属性进行访问时,它会查找所有的超类(以及超类的超类),直到找到所需的属性为止(或者引发异常)。
'''
class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print('Aaaah...')
self.hungry = False
else:
print('No, thanks!')
b = Bird()
b.eat() # Aaaah...
b.eat() # No, thanks!
class FlyBird(Bird):
pass
f = FlyBird()
f.eat() # Aaaah...
f.eat() # No, thanks!
class SongBird(Bird):
def __init__(self):
self.sound = 'Squawk!'
s = SongBird()
s.eat() # 异常:'SongBird' object has no attribute 'hungry',因为__init__被覆盖,此时可使用super函数
class SongBird(Bird):
def __init__(self):
super().__init__()
self.sound = 'Squawk'
s = SongBird()
s.eat() # Aaaah...
s.eat() # No, thanks!
s.sound # 'Squawk'
'''
__len__(self)
返回集合中所含项目的数量,使用len()时调用。
__getitem__(self, key)
使用索引访问元素时调用。对于一个序列,键应该是一个 0 至 n-1 的整数(如果是负整数,那么要从末尾开始计数),n 是序列的长度;对于映射来说,可以使用任何不可变类型(Number、String、Tuple)的键。
__setitem__(self, key, value)
对索引值 key 赋值 value 时调用。
__delitem__(self, key)
在对一部分对象使用 del 语句时被调用。
'''
class Sequence():
def __init__(self):
self.lists = (0, 1, 2)
s = Sequence()
len(s) # 异常:object of type 'Sequence' has no len()
s[0] # 异常:'Sequence' object does not support indexing
s[0] = 1 # 异常:'Sequence' object does not support item assignment
del s[0] # 异常:'Sequence' object doesn't support item deletion
class Sequence():
def __init__(self, *args):
self.lists = args[0]
def __len__(self):
return len(self.lists)
def __getitem__(self, key):
return self.lists[key]
def __setitem__(self, key, value):
self.lists[key] = value
print(value)
def __delitem__(self, key):
value = self.lists[key]
del self.lists[key]
print(value)
s = Sequence([1, 2, 3, 4, 5, 6])
len(s) # 6
s[0] # 1
s[0] = 10 # 10
del s[1] # 2
s.lists # [10, 3, 4, 5, 6]
'''
子类化列表、字典和字符串
'''
class CounterList(list):
def __init__(self, *args):
super().__init__(*args)
self.counter = 0
def __getitem__(self, key):
self.counter += 1
return super().__getitem__(key)
cl = CounterList([1, 2, 3, 4, 5])
cl # [1, 2, 3, 4, 5]
cl.reverse()
cl # [5, 4, 3, 2, 1]
cl.counter # 0
cl[0] + cl[1] # 9
cl.counter # 2
'''
property([fget[, fset[, fdel[, doc]]]])
fget -- 获取属性值的函数,如果只有该参数,产生的属性是只读的
fset -- 设置属性值的函数
fdel -- 删除属性值函数,如果没有设置该参数,删除属性会报异常
doc -- 属性描述信息
返回属性,可以避免使用get和set的获取和设置属性的代码臃肿
'''
class Person():
def __init__(self):
self._score = 90
def getScore(self):
return self._score
def setScore(self, value):
if (value >= 0 and value <= 100):
self._score = value
else:
print('Wrong Score')
def delScore(self):
del self._score
score = property(getScore, setScore, delScore, "I'm the 'score' property.")
p = Person()
p.score # 90
p.score = 120 # Wrong Score
p.score = 100
p.score # 100
del p.score
p.score # 异常:'Person' object has no attribute '_score'
静态方法和类成员方法在创建时分别被装入 staticmethod 类型和 classmethod 类型的对象中。静态方法的定义没有self参数,且能够被类本身直接调用;类方法在定义时需要名为 cls 的类似于 self 的参数,类成员方法可以直接用类的具体对象调用,但 cls 参数是自动被绑定到类的。
class MyClass:
def smeth():
print('This is a static method')
smeth = staticmethod(smeth)
def cmeth(cls):
print('This is a class method of', cls)
cmeth = classmethod(cmeth)
MyClass.smeth() # This is a static method
MyClass.cmeth() # This is a class method of
在Python2.4中,引入了装饰器,它能对任何可调用的对象进行包装,既能够用于方法也能够用于函数。使用@操作符,在方法或函数的上方将装饰器列出,从而指定一个或者更多的装饰器(多个装饰器在应用时的顺序与指定顺序相反)。
'''
@property
@staticmethod
@classmethod
'''
class Person():
def __init__(self):
self._score = 90
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if (value >= 0 and value <= 100):
self._score = value
else:
print('Wrong Score')
@property
def percent(self):
return self._score/100
p = Person()
p.score # 90
p.percent # 0.9
p.score = 100
p.score = 120 # Wrong Score
p.score # 100
p.percent # 1.0
p.percent = 0.9 # 异常:can't set attribute
class MyClass:
@staticmethod
def smeth():
print('This is a static method')
@classmethod
def cmeth(cls):
print('This is a class method of', cls)
MyClass.smeth() # This is a static method
MyClass.cmeth() # This is a class method of
如果访问 a.x 不存在,那么就要转向到某个操作,我们把这种情况称之为“拦截”(intercept)。 __getattr__、__setattr__和它的朋友们用于拦截对象的所有属性访问。
'''
__dict__:存储属性和方法
__getattr__(self, name):当属性name被访问且对象没有相应的属性时被自动调用
__setattr__(self, name, value):当试图给属性name赋值时自动调用
__delattr__(self, name):当试图删除属性name时被自动调用
__getattribute__(self, name):当属性name被访问时自动被调用
'''
class Attribute():
def __init__(self):
self.name = 'name'
def __getattr__(self, name):
print(name, 'is not in Attribute')
def __setattr__(self, name, value):
print('setattr success')
self.__dict__[name] = value
def __delattr__(self, name):
del self.__dict__[name]
a = Attribute() # setattr success
a.name # 'name'
a.attr # attr is not in Attribute
a.name = 'value' # setattr success
a.attr = 'attr' # setattr success
a.name # 'value'
a.attr # 'attr'
del a.attr
a.attr # attr is not in Attribute
迭代的意思是重复做一些事很多次,就像在循环中做的那样。在 for 循环中对序列和字典进行迭代是很好理解的事,但实际上,也能对其他的对象进行迭代:实现 __iter__方法的对象。
__iter__方法返回一个迭代器(iterator),所谓迭代器就是具有 __next__ 方法(这个方法在调用时不需要任何参数)的对象。在调用 __next__ 方法时,迭代器会返回它的下一个值,如果 __next__ 方法被调用,但迭代器没有值可以返回,就会引发一个 StopIteration 异常。内建函数 next() 可以用于访问 __next__ 方法。任何实现了 __iter__ 和 __next__ 方法的对象都是迭代器。
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
def __iter__ (self):
return self
fibs = Fibs()
fibs # <__main__.Fibs object at 0x101f45048>
for f in fibs:
if f < 100:
print(f) # 输出:1 1 2 3 5 8 13 21 34 55 89
else:
break
it = iter([1, 2, 3])
it #
next(it) # 1
next(it) # 2
next(it) # 3
next(it) # 异常:StopIteration
除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下(除了在索引或者分片等操作中),能使用迭代器或者可迭代对象替换。
class TestIterator:
value = 0
def __next__(self):
self.value += 1
if self.value > 10: raise StopIteration
return self.value
def __iter__(self):
return self
ti = TestIterator()
ti # <__main__.TestIterator object at 0x103944198>
list(ti) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for t in ti:
print(t) # 无输出,生成器只能迭代一次
生成器是创建迭代器的一种简单而强大的工具,只是这种迭代器更加优雅,它不需要 __iter__ 和 __next__ 方法,只需要在返回数据的时候使用 yield 语句。每次 __next__ 调用时,生成器再恢复它离开的位置(它记忆语句最后一次执行的位置和所有的数据值)。
生成器是一个包含 yield 的函数,当它被调用时,在函数体中的代码不会被执行,而会返回一个迭代器。每次请求一个值,就会执行生成器中的代码,直到遇到一个 yield 或者 return 语句。yield 语句意味着应该生成一个值。return 语句意味着生成器要停止执行(不再生成任何东西,return 语句只有在一个生成器中使用时才能进行无参数调用)。
换句话说,生成器是由两部分组成:生成器的函数和生成器的迭代器。生成器的函数是用 def 语句定义的,包含 yield 的部分;生成器的迭代器是这个函数返回的部分。按一种不是很准确的说法,两个实体经常被当做一个,合起来叫做生成器。生成器的函数返回的迭代器可以像其他的迭代器那样使用。
'''
生成器函数
'''
def Fibs():
a, b = 0, 1
while (b < 100):
a, b = b, a + b
yield a
fibs = Fibs()
fibs #
for f in fibs:
print(f) # 输出:1 1 2 3 5 8 13 21 34 55 89
list(fibs) # []
'''
生成器表达式
'''
squares = (i*i for i in range(5))
squares # at 0x103054570>
list(squares) # [0, 1, 4, 9, 16]
for s in squares:
print(s) # 无输出,生成器只能迭代一次
sum(i*i for i in range(5)) # 30
'''
对生成器使用 send() 方法
'''
def repeater(value):
while True:
new = (yield value)
if new is not None:value = new
r = repeater(10)
next(r) # 10
r.send('hello world!') # 'hello world!'
next(r) # 'hello world!'
以上全部内容参考书籍如下:
Magnus Lie Hetland《Python基础教程(第2版)》