0%

面向对象高级之双下划线方法

1.__new__

类的构造方法,实例化时调用该方法返回对象,再调用init方法进行初始化。
new方法的返回值决定对象到底是什么。

1
2
3
4
5
6
7
8
9
10
11
12
class Bar(object):
def __init__(self, cls):
self.cls = cls

class Foo(object):

def __new__(cls, *args, **kwargs):
# return super(Foo,cls).__new__(cls,*args, **kwargs)
return Bar(cls)

obj = Foo()
print(obj)
单例模式:
1
2
3
4
5
6
7
8
9
10
11
12
class Foo(object):

def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_Foo__instance"):
cls.__instance = object.__new__(cls)
return cls.__instance

o1 = Foo()
o2 = Foo()

print(id(o1), o1)
print(id(o2), o2)

2.__iter__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Foo(object):

# def __iter__(self):
# return iter([11,22,33])

def __iter__(self):
yield 1
yield 2
yield 3

obj = Foo()

for item in obj:
print(item)

可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了iter方法。iter方法需要返回一个迭代器(生成器也是一种特殊的迭代器), 当一个对象内部实现了iter方法,就变为可迭代对象,就可以for循环。
iter()函数是内置方法,用于生成一个可迭代对象, 用法:

- iter(object)

object必须是集合对象,且支持迭代协议(iteration protocol)或者支持序列协议(sequence protocol)。
说白了,也就是实现了iter()方法或者getitem()方法。

1
2
3
l = [1, 2, 3]
for i in iter(l):
print(i)
- iter(object, sentinel)

如果传递了第二个参数,则object必须是一个可调用的对象(如,函数)。此时,iter创建了一个迭代器对象,每次调用这个迭代器对象的next()方法时,都会调用object。如果next的返回值等于sentinel,则抛出StopIteration异常,否则返回下一个值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class TestIter(object):

def __init__(self):
self.l=[1,2,3,4,5]
self.i=iter(self.l)
def __call__(self): #定义了__call__方法的类的实例是可调用的
item = next(self.i)
print ("__call__ is called,which would return",item)
return item
def __iter__(self): #支持迭代协议(即定义有__iter__()函数)
print ("__iter__ is called!!")
return iter(self.l)

t = TestIter() # t是可调用的
t1 = iter(t, 3) # t必须是callable的,否则无法返回callable_iterator
print(callable(t))
for i in t1:
print(i)
# 它每次在调用的时候,都会调用__call__函数,并且最后输出3就停止了。

True
__call__ is called,which would return 1
1
__call__ is called,which would return 2
2
__call__ is called,which would return 3

应用:

wtforms中,模板中循环form对象,其内部就是实现了iter方法。

3.__mro__

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

1
2
>>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

补充(钻石继承问题)

新式类:1570969847(1).jpg
1570970131(1).jpg
经典类:1570970332(1).jpg
1570970542(1).jpg

==super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的==

4.__dict__

类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类dict里的

对象的dict中存储了一些self.xxx的一些东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Foo(object):
key = 1234
def __init__(self, name, age):
self.name = name
self.age = age

def run(self):
print("running...")

obj = Foo("Jack", 23)

print("obj", obj.__dict__)
print("Foo", Foo.__dict__)

### 结果
obj {'name': 'Jack', 'age': 23}
Foo {'__module__': '__main__', 'key': 1234, '__init__': <function Foo.__init__ at 0x00000139AD9E9D08>, 'run': <function Foo.run at 0x00000139AD9E9B70>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}

5.__slot__

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class能添加的属性:

1
2
class A(object):
__slots__ = 'name', 'age'

执行如下:

1
2
3
obj = A()
obj.name = "Jack"
obj.score = 100

结果:

1
2
3
4
Traceback (most recent call last):
File "D:/django_test/df/test.py", line 356, in <module>
obj.score = 100
AttributeError: 'A' object has no attribute 'score'

由于’score’没有被放到slots中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

使用slots要注意,slots定义的属性仅对当前类起作用,对继承的子类是不起作用的:

1
2
3
4
5
6
class B(A):
pass

obj = B()
obj.name = "Jack"
obj.score = 100

除非在子类中也定义slots,这样,子类允许定义的属性就是自身的slots加上父类的slots

1
2
3
4
5
6
7
class B(A):
__slots__ = 'score'
pass

obj = B()
obj.name = "Jack"
obj.score = 100