一、isinstance(obj,cls)和issubclass(sub, super)
1.1 isinstance
isinstance(obj,cls)检查obj是否是类cls的对象 包括继承关系
1
class
Foo(object):
2
pass
3
4
obj =
Foo()
5
print
(isinstance(obj, Foo))
#
True
1.2 issubclass
issubclass(sub, super)检查sub类是否是super类的派生类 判断类与类之间的继承关系
1
class
Foo(object):
2
pass
3
4
5
class
Bar(Foo):
6
pass
7
8
9
print
(issubclass(Bar, Foo))
#
True
二、特殊方法
跟运算符无关的特殊方法:
| 类别 | 方法名 |
| 字符串 / 字节序列表示形式 | __repr__、 __str__、 __format__、 __bytes__ |
| 数值转换 | __abs__、 __bool__、 __complex__、 __int__、 __float__、 __hash__、 __index__ |
| 集合模拟 | __len__、 __getitem__、 __setitem__、 __delitem__、__contains__ |
| 迭代枚举 | __iter__、 __reversed__、 __next__ |
| 可调用模拟 | __call__ |
| 上下文管理 | __enter__、 __exit__ |
| 实例创建和销毁 | __new__、 __init__、 __del__ |
| 属性管理 | __getattr__、 __getattribute__、 __setattr__、 __delattr__、 __dir__ |
| 属性描述符 | __get__、 __set__、 __delete__ |
| 跟类相关的服务 | __prepare__、 __instancecheck__、 __subclasscheck__ |
| 类名 | 方法名和对应的运算符 |
| 一元运算符 | __neg__ -、 __pos__ +、 __abs__ abs() |
| 众多比较运算符 | __lt__ <、 __le__ <=、 __eq__ ==、 __ne__ !=、 __gt__ >、 __ge__ >= |
| 算术运算符 | __add__ +、 __sub__ -、 __mul__ *、 __truediv__ /、 __floordiv__ //、 __mod__ %、 __divmod__ |
| 反向算术运算符 | __radd__、 __rsub__、 __rmul__、 __rtruediv__、 __rfloordiv__、 __rmod__、 __rdivmod__、 __rpow__ |
| 增量赋值算术运算符 | __iadd__、 __isub__、 __imul__、 __itruediv__、 __ifloordiv__、 __imod__、 __ipow__ |
| 位运算符 | __invert__ ~、 __lshift__ <<、 __rshift__ >>、 __and__ &、 __or__ |、 __xor__ ^ |
| 反向位运算符 | __rlshift__、 __rrshift__、 __rand__、 __rxor__、 __ror__ |
| 增量赋值位运算符 | __ilshift__、 __irshift__、 __iand__、 __ixor__、 __ior__ |
2.1 __setattr__, __delattr__, __getattr__
- __setattr__ 添加/修改属性会触发它的执行
-
__delattr__ 删除属性的时候会触发
-
__getattr__ 只有在调用属性且属性不存在的时候才会触发
1
#
三者的用法演示
2
class
Foo:
3
x = 1
4
def
__init__
(self, y):
5
self.y =
y
6
7
def
__getattr__
(self, item):
8
print
(
'
----> from getattr:你找的属性不存在
'
)
9
10
def
__setattr__
(self, key, value):
11
print
(
'
----> from setattr
'
)
12
#
self.key=value # 这就无限递归了,你好好想想
13
self.
__dict__
[key] = value
#
应该使用它
14
15
def
__delattr__
(self, item):
16
print
(
'
----> from delattr
'
)
17
#
del self.item #无限递归了
18
self.
__dict__
.pop(item)
19
20
#
__setattr__ 添加/修改属性会触发它的执行
21
f1=Foo(10
)
22
print
(f1.
__dict__
)
#
因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
23
f1.z=3
24
print
(f1.
__dict__
)
25
26
#
__delattr__ 删除属性的时候会触发
27
f1.
__dict__
[
'
a
'
]=3
#
我们可以直接修改属性字典,来完成添加/修改属性的操作
28
del
f1.a
29
print
(f1.
__dict__
)
30
31
#
__getattr__ 只有在使用点调用属性且属性不存在的时候才会触发
32
f1.xxxxxx
2.2 __getattribute__
__getattribute__ : 不管有没有属性都会执行到,当__getattribute__和__getattr__同时存在时,只有当__getattribute__抛出AttributeError的异常时,才会执行到__getattr__,否则会一直执行__getattribute__
1
class
Foo(object):
2
3
def
__init__
(self, x):
4
self.x =
x
5
6
def
__getattr__
(self, item):
7
print
(
"
执行的是__getattr__
"
)
8
9
def
__getattribute__
(self, item):
10
print
(
"
执行的是getattribute
"
)
11
raise
AttributeError(
"
抛出异常了
"
)
#
只有抛出AttributeError的异常时,找不到属性才会执行__getattr__方法
12
13
14
f1 = Foo(10
)
15
f1.x
16
f1.xxx
2.3 __getitem__、__setitem__、__delitem__
-
__getitem__ 以字典形式获取属性时,触发__getitem__
-
__setitem__ 以字典形式设置属性时,触发__setitem__
-
__delitem__ 删除字典的key值时,会触发__delitem__
1
class
Foo(object):
2
3
def
__getitem__
(self, item):
4
print
(
"
getitem----->%s
"
%
item)
5
return
self.
__dict__
.get(item)
6
7
def
__setitem__
(self, key, value):
8
print
(
"
setitem---->%s %s
"
%
(key, value))
9
self.
__dict__
[key] =
value
10
11
def
__delitem__
(self, key):
12
print
(
"
delitem----->%s
"
%
key)
13
self.
__dict__
.pop(key)
14
15
16
f1 =
Foo()
17
print
(f1.
__dict__
)
18
19
f1[
'
name
'
] =
'
zhangsan
'
20
print
(f1.
__dict__
)
21
22
print
(f1[
'
name
'
])
23
24
del
f1[
'
name
'
]
25
26
print
(f1.
__dict__
)
2.4 __str__、__repr__、__format__
1
class
School(object):
2
3
def
__init__
(self, name, age):
4
self.name =
name
5
self.age =
age
6
7
def
__str__
(self):
8
return
'
名字是%s,年龄是%s
'
%
(self.name, self.age)
9
10
def
__repr__
(self):
#
只有当__str__没有定义时,才会执行
11
return
'
aaa
'
12
13
14
f1 = School(
'
alex
'
,
'
23
'
)
15
print
(f1)
16
17
#
在子类中使用__str__,先找子类的__str__,没有的话向上找,只要父类不是object,就执行父类的__str__
18
#
但是如果除了object之外的父类都没有__str__方法,就执行子类的__repr__方法,如果子类也没有,还要向上找父类的__repr__方法
19
#
一直找不到,再执行object类中的__str__方法
__format__ 格式化对象的字符串格式:
1
date_dic =
{
2
'
ymd
'
:
'
{0.year}:{0.month}:{0.day}
'
,
3
'
dmy
'
:
'
{0.day}/{0.month}/{0.year}
'
,
4
'
mdy
'
:
'
{0.month}-{0.day}-{0.year}
'
,
5
}
6
7
8
class
Date(object):
9
def
__init__
(self, year, month, day):
10
self.year =
year
11
self.month =
month
12
self.day =
day
13
14
def
__format__
(self, format_spec):
15
if
not
format_spec
or
format_spec
not
in
date_dic:
16
format_spec =
'
ymd
'
17
fmt =
date_dic[format_spec]
18
return
fmt.format(self)
19
20
21
d1 = Date(2016, 12, 29
)
22
print
(format(d1))
23
print
(
'
{:mdy}
'
.format(d1))
24
print
(format(d1,
'
ymd
'
))
2.5 __slots__
1
class
Foo(object):
2
#
创建完后,该类就不具有__dict__属性
3
__slots__
= [
'
name
'
,
'
age
'
]
4
5
6
f1 =
Foo()
7
f1.name =
'
alex
'
8
f1.age = 18
9
print
(f1.name)
10
11
f1.gender =
'
male
'
#
会报错 'Foo' object has no attribute 'gender'
2.6 __doc__
该属性的无法被继承
1
class
Foo:
2
"""
3
我是描述信息
4
"""
5
pass
6
7
8
class
Bar(Foo):
9
pass
10
11
12
print
(Foo.
__doc__
)
#
我是描述信息
13
print
(Bar.
__doc__
)
#
None
2.7 __module__和__class__
1
#
!/usr/bin/env python
2
#
-*- coding:utf-8 -*-
3
4
class
C:
5
6
def
__init__
(self):
7
self.name = ‘SB
'
8
9
#
lib/aa.py
1
from
lib.aa
import
C
2
3
obj =
C()
4
print
(obj.
__module__
)
#
输出 lib.aa,即:输出模块
5
print
(obj.
__class__
)
#
输出 lib.aa.C,即:输出类
2.8 __del__
1
class
Foo(object):
2
3
def
__init__
(self, name):
4
self.name =
name
5
6
def
__del__
(self):
7
print
(
"
我被删除了
"
)
8
9
10
f1 = Foo(
'
alex
'
)
11
del
f1
2.9 __call__
class
Foo(object):
def
__call__
(self, *args, **
kwargs):
print
(
"
hello world
"
)
f1
=
Foo()
f1()
Foo()()
2.10 描述符(__get__、__set__、__delete__)
class
Foo(object):
#
在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
def
__get__
(self, instance, owner):
pass
def
__set__
(self, instance, value):
pass
def
__delete__
(self, instance):
pass
2.描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中
1
class
Foo(object):
2
3
def
__get__
(self, instance, owner):
4
print
(
"
get方法
"
)
5
6
def
__set__
(self, instance, value):
7
print
(
"
set方法
"
)
8
#
instance.__dict__['x'] = value
9
10
def
__delete__
(self, instance):
11
print
(
"
delete方法
"
)
12
13
14
class
Bar(object):
15
16
x =
Foo()
17
18
19
b1 =
Bar()
20
b1.x = 1
#
触发__set__方法的执行
21
print
(b1.
__dict__
)
#
dict中为空
22
b1.x
#
触发__get__方法的执行
23
del
b1.x
#
触发__delete__方法的执行
-
数据描述符:至少实现了__get__()和__set__()
-
非数据描述符:没有实现__set__()
-
描述符本身应该定义成新式类,被代理的类也应该是新式类
-
必须把描述符定义成这个类的类属性,不能为定义到构造函数中
-
要严格遵循该优先级,优先级由高到底分别是
-
类属性
-
数据描述符
-
实例属性
-
非数据描述符
-
找不到的属性触发__getattr__()
类属性>数据描述符
1
#
描述符Str
2
class
Str:
3
def
__get__
(self, instance, owner):
4
print
(
'
Str调用
'
)
5
def
__set__
(self, instance, value):
6
print
(
'
Str设置...
'
)
7
def
__delete__
(self, instance):
8
print
(
'
Str删除...
'
)
9
10
11
class
People:
12
name=
Str()
13
def
__init__
(self,name,age):
#
name被Str类代理,age被Int类代理,
14
self.name=
name
15
self.age=
age
16
17
18
#
基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典
19
20
#
那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错
21
People.name
#
恩,调用类属性name,本质就是在调用描述符Str,触发了__get__()
22
23
People.name=
'
egon
'
#
那赋值呢,我去,并没有触发__set__()
24
del
People.name
#
赶紧试试del,我去,也没有触发__delete__()
25
#
结论:描述符对类没有作用-------->傻逼到家的结论
26
27
'''
28
原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级
29
People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__()
30
31
People.name='egon' # 那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__()
32
del People.name #同上
33
'''
数据描述符>实例属性
1
#
描述符Str
2
class
Str:
3
def
__get__
(self, instance, owner):
4
print
(
'
Str调用
'
)
5
def
__set__
(self, instance, value):
6
print
(
'
Str设置...
'
)
7
def
__delete__
(self, instance):
8
print
(
'
Str删除...
'
)
9
10
11
class
People:
12
name=
Str()
13
def
__init__
(self,name,age):
#
name被Str类代理,age被Int类代理,
14
self.name=
name
15
self.age=
age
16
17
18
p1=People(
'
egon
'
,18
)
19
20
21
#
如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性
22
p1.name=
'
egonnnnnn
'
23
p1.name
24
print
(p1.
__dict__
)
#
实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了
25
del
p1.name
实例属性 > 非数据描述符
1
class
Foo:
2
def
func(self):
3
print
(
'
我胡汉三又回来了
'
)
4
5
f1 =
Foo()
6
f1.func()
#
调用类的方法,也可以说是调用非数据描述符
7
#
函数是一个非数据描述符对象(一切皆对象么)
8
print
(dir(Foo.func))
9
print
(hasattr(Foo.func,
'
__set__
'
))
10
print
(hasattr(Foo.func,
'
__get__
'
))
11
print
(hasattr(Foo.func,
'
__delete__
'
))
12
#
有人可能会问,描述符不都是类么,函数怎么算也应该是一个对象啊,怎么就是描述符了
13
#
笨蛋哥,描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么
14
#
函数就是一个由非描述符类实例化得到的对象
15
#
没错,字符串也一样
16
17
f1.func=
'
这是实例属性啊
'
18
print
(f1.func)
19
20
21
del
f1.func
#
删掉了非数据
22
f1.func()
再次验证:实例属性>非数据描述符
1
class
Foo:
2
def
__set__
(self, instance, value):
3
print
(
'
set
'
)
4
def
__get__
(self, instance, owner):
5
print
(
'
get
'
)
6
class
Room:
7
name=
Foo()
8
def
__init__
(self,name,width,length):
9
self.name=
name
10
self.width=
width
11
self.length=
length
12
13
14
15
16
#
name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级
17
#
对实例的属性操作,触发的都是描述符的
18
r1=Room(
'
厕所
'
,1,1
)
19
r1.name
20
r1.name=
'
厨房
'
21
22
23
24
class
Foo:
25
def
__get__
(self, instance, owner):
26
print
(
'
get
'
)
27
28
class
Room:
29
name=
Foo()
30
def
__init__
(self,name,width,length):
31
self.name=
name
32
self.width=
width
33
self.length=
length
34
35
36
37
#
name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级
38
#
对实例的属性操作,触发的都是实例自己的
39
r1=Room(
'
厕所
'
,1,1
)
40
r1.name
41
r1.name=
'
厨房
'
非数据描述符>找不到
1
class
Foo:
2
def
func(self):
3
print
(
'
我胡汉三又回来了
'
)
4
5
6
def
__getattr__
(self, item):
7
print
(
'
找不到了当然是来找我啦
'
,item)
8
9
10
f1=
Foo()
11
f1.xxxxxxxxxxx
#
找不到,调用__getattr__方法
1
class
Typed(object):
2
def
__init__
(self,name,expected_type):
3
self.name=
name
4
self.expected_type=
expected_type
5
6
def
__get__
(self, instance, owner):
7
print
(
'
get--->
'
,instance,owner)
8
if
instance
is
None:
9
return
self
10
return
instance.
__dict__
[self.name]
11
12
def
__set__
(self, instance, value):
13
print
(
'
set--->
'
,instance,value)
14
if
not
isinstance(value,self.expected_type):
15
raise
TypeError(
'
Expected %s
'
%
str(self.expected_type))
16
instance.
__dict__
[self.name]=
value
17
18
def
__delete__
(self, instance):
19
print
(
'
delete--->
'
,instance)
20
instance.
__dict__
.pop(self.name)
21
22
23
class
People(object):
24
name=Typed(
'
name
'
,str)
25
age=Typed(
'
name
'
,int)
26
salary=Typed(
'
name
'
,float)
27
def
__init__
(self,name,age,salary):
28
self.name=
name
29
self.age=
age
30
self.salary=
salary
31
32
p1=People(123,18,3333.3
)
33
p1=People(
'
egon
'
,
'
18
'
,3333.3
)
34
p1=People(
'
egon
'
,18,3333)
6.类装饰器
1
#
检查对象属性的类型
2
class
Typed(object):
3
def
__init__
(self, name, expected_type):
4
self.name =
name
5
self.expected_type =
expected_type
6
7
def
__get__
(self, instance, owner):
8
print
(
'
get--->
'
, instance, owner)
9
if
instance
is
None:
10
return
self
11
return
instance.
__dict__
[self.name]
12
13
def
__set__
(self, instance, value):
14
print
(
'
set--->
'
, instance, value)
15
if
not
isinstance(value,self.expected_type):
16
raise
TypeError(
'
Expected %s
'
%
str(self.expected_type))
17
instance.
__dict__
[self.name] =
value
18
19
def
__delete__
(self, instance):
20
print
(
'
delete--->
'
, instance)
21
instance.
__dict__
.pop(self.name)
22
23
24
def
typeassert(**
kwargs):
25
def
decorate(cls):
26
print
(
'
类的装饰器开始运行啦------>
'
,kwargs)
27
for
name,expected_type
in
kwargs.items():
28
setattr(cls,name,Typed(name,expected_type))
29
return
cls
30
return
decorate
31
32
#
有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People)
33
@typeassert(name=str,age=int,salary=
float)
34
class
People:
35
def
__init__
(self,name,age,salary):
36
self.name=
name
37
self.age=
age
38
self.salary=
salary
39
40
41
print
(People.
__dict__
)
42
p1 = People(
'
egon
'
, 18, 3333.3)
1
class
LazyProperty(object):
2
3
def
__init__
(self, func):
4
self.func =
func
5
6
def
__get__
(self, instance, owner):
7
#
print(self.func)
8
#
print(instance)
9
#
print(owner)
10
#
print("haha")
11
return
self.func(instance)
12
13
14
class
Room(object):
15
16
def
__init__
(self, name, width, length):
17
self.name =
name
18
self.width =
width
19
self.length =
length
20
21
@LazyProperty
#
相当于 area = LazyProperty(area)
22
def
area(self):
23
return
self.width *
self.length
24
25
26
r1 = Room(
"
卧室
"
, 2, 3
)
27
print
(r1.area)
实现缓存计算的功能
1
class
Lazyproperty:
2
def
__init__
(self,func):
3
self.func=
func
4
5
def
__get__
(self, instance, owner):
6
print
(
'
这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
'
)
7
if
instance
is
None:
8
return
self
9
else
:
10
print
(
'
--->
'
)
11
value =
self.func(instance)
12
setattr(instance, self.func.
__name__
,value)
#
计算一次就缓存到实例的属性字典中
13
return
value
14
15
class
Room:
16
def
__init__
(self,name,width,length):
17
self.name=
name
18
self.width=
width
19
self.length=
length
20
21
@Lazyproperty
#
area=Lazyproperty(area) 相当于'定义了一个类属性,即描述符'
22
def
area(self):
23
return
self.width *
self.length
24
25
r1=Room(
'
alex
'
,1,1
)
26
print
(r1.area)
#
先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法
27
print
(r1.area)
#
先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
做了一点小改动,缓存计算的功能就失效了
1
#
缓存不起来了
2
3
class
Lazyproperty:
4
def
__init__
(self,func):
5
self.func=
func
6
7
def
__get__
(self, instance, owner):
8
print
(
'
这是我们自己定制的静态属性,r1.area实际是要执行r1.area()
'
)
9
if
instance
is
None:
10
return
self
11
else
:
12
value=
self.func(instance)
13
instance.
__dict__
[self.func.
__name__
]=
value
14
return
value
15
#
return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情
16
17
def
__set__
(self, instance, value):
18
print
(
'
hahahahahah
'
)
19
20
class
Room:
21
def
__init__
(self,name,width,length):
22
self.name=
name
23
self.width=
width
24
self.length=
length
25
26
@Lazyproperty
#
area=Lazyproperty(area) 相当于定义了一个类属性,即描述符
27
def
area(self):
28
return
self.width *
self.length
29
30
print
(Room.
__dict__
)
31
r1=Room(
'
alex
'
,1,1
)
32
print
(r1.area)
33
print
(r1.area)
34
print
(r1.area)
35
print
(r1.area)
#
缓存功能失效,每次都去找描述符了,为何,因为描述符实现了set方法,它由非数据描述符变成了数据描述符,数据描述符比实例属性有更高的优先级,因而所有的属性操作都去找描述符了
2.11 上下文管理协议(__enter__和__exit__)
上下文管理协议: 即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
1
#
上下文管理协议
2
class
Open:
3
def
__init__
(self,name):
4
self.name=
name
5
6
def
__enter__
(self):
7
print
(
'
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
'
)
8
#
return self
9
10
def
__exit__
(self, exc_type, exc_val, exc_tb):
11
print
(
'
with中代码块执行完毕时执行我啊
'
)
12
13
14
#
with Open--》触发Open.__enter__,拿到返回值
15
#
as f ---> f = __enter__的返回值
16
#
with Open('a.txt') as f =======> f = Open('a.txt')
17
with Open(
'
a.txt
'
) as f:
18
print
(
'
=====>执行代码块
'
)
19
#
print(f,f.name)
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
1
class
Open:
2
def
__init__
(self,name):
3
self.name=
name
4
5
def
__enter__
(self):
6
print
(
'
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
'
)
7
8
def
__exit__
(self, exc_type, exc_val, exc_tb):
9
print
(
'
with中代码块执行完毕时执行我啊
'
)
10
print
(exc_type)
11
print
(exc_val)
12
print
(exc_tb)
13
14
15
16
with Open(
'
a.txt
'
) as f:
17
print
(
'
=====>执行代码块
'
)
18
raise
AttributeError(
'
***着火啦,救火啊***
'
)
19
print
(
'
0
'
*100)
#
------------------------------->不会执行
如果__exit__()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
1
class
Open(object):
2
3
def
__init__
(self, name):
4
self.name =
name
5
6
def
__enter__
(self):
7
print
(
"
执行enter
"
)
8
return
self
9
10
def
__exit__
(self, exc_type, exc_val, exc_tb):
11
print
(
"
执行exit
"
)
12
print
(exc_type)
13
print
(exc_val)
14
print
(exc_tb)
15
return
True
#
包容了with中的异常,返回true,会正常结束with语句,会继续执行with后的语句;如果不包容异常,则出现异常就会停止
16
17
18
with Open(
'
aa
'
) as f:
19
print
(f)
20
raise
Exception(
"
aa
"
)
21
22
print
(
"
bbb
"
)
2.12 __dict__
1
class
Province:
2
3
country =
'
China
'
4
5
def
__init__
(self, name, count):
6
self.name =
name
7
self.count =
count
8
9
def
func(self, *args, **
kwargs):
10
print
'
func
'
11
12
13
#
获取类的成员,即:静态字段、方法、
14
print
Province.
__dict__
15
#
输出:{'country': 'China', '__module__': '__main__', 'func':
, '__init__':
, '__doc__': None}
16
17
18
obj1 = Province(
'
HeBei
'
,10000
)
19
print
obj1.
__dict__
20
#
获取 对象obj1 的成员
21
#
输出:{'count': 10000, 'name': 'HeBei'}
22
23
24
obj2 = Province(
'
HeNan
'
, 3888
)
25
print
obj2.
__dict__
26
#
获取 对象obj1 的成员
27
#
输出:{'count': 3888, 'name': 'HeNan'}
2.13 __new__ 构造方法
__init__ 初始化方法
1
class
Single(object):
2
3
__instance
=
None
4
5
def
__new__
(cls, *args, **
kwargs):
6
if
cls.
__instance
is
None:
7
cls.
__instance
= object.
__new__
(cls)
8
return
cls.
__instance
9
10
11
def
__init__
(self):
12
print
(
"
init
"
)
13
14
15
#
开辟一个空间,属于对象的
16
#
把对象的空间传给self,执行init
17
#
将这个对象的空间返回给调用者
18
obj =
Single()
19
obj2 =
Single()
20
print
(id(obj), id(obj2))
21
22
23
#
单例:如果一个类,从头到尾只能有一个实例,那么这个类就是一个单例类
2.14 __len__
1
class
A:
2
def
__init__
(self):
3
self.a = 1
4
self.b = 2
5
6
7
def
__len__
(self):
8
return
len(self.
__dict__
)
9
a =
A()
10
print
(len(a))
2.15 __hash__
1
class
A:
2
def
__init__
(self):
3
self.a = 1
4
self.b = 2
5
6
7
def
__hash__
(self):
8
return
hash(str(self.a)+
str(self.b))
9
a =
A()
10
print
(hash(a))
2.16 __eq__
1
class
A:
2
def
__init__
(self):
3
self.a = 1
4
self.b = 2
5
6
7
def
__eq__
(self,obj):
8
if
self.a == obj.a
and
self.b ==
obj.b:
9
return
True
10
a =
A()
11
b =
A()
12
print
(a == b)
2.17 __bool__
bool(x) 的背后,调用的就是__bool__()方法. 如果不存在 __bool__ 方法, 那么 bool(x) 会尝试调用 x.__len__()。 若返回 0, 则 bool 会返回False; 否则返回 True。
from
math
import
hypot
class
Vector:
"""
二维向量
"""
def
__init__
(self, x, y):
self.x
=
x
self.y
=
y
def
__repr__
(self):
return
'
Vector(%s, %s)
'
%
(self.x, self.y)
def
__abs__
(self):
return
hypot(self.x, self.y)
def
__bool__
(self):
return
bool(abs(self))
def
__add__
(self, other):
x
= self.x +
other.x
y
= self.y +
other.y
return
Vector(x, y)
def
__mul__
(self, other):
return
Vector(self.x * other, self.y * other)
三、加工数据类型
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
1
class
List(list):
2
3
def
show_middle(self):
4
mid_index = int(len(self) / 2
)
5
return
self[mid_index]
6
7
#
对append方法进行重写,只允许添加字符串类型
8
def
append(self, p_object):
9
if
type(p_object)
is
str:
10
super(List, self).append(p_object)
11
else
:
12
print
(
'
只能添加字符串类型
'
)
13
14
15
l1 = List(
"
hello world
"
)
16
print
(type(l1))
17
print
(l1.show_middle())
18
19
l1.append(
"
aa
"
)
20
print
(l1)
1
class
FileHandle(object):
2
3
def
__init__
(self, filename, mode=
'
r
'
, encoding=
'
utf-8
'
):
4
#
self.filename = filename
5
self.file = open(filename, mode, encoding=
encoding)
6
self.mode =
mode
7
self.encoding =
encoding
8
9
def
write(self, data):
10
t = time.strftime(
'
%Y-%m-%d %X
'
)
11
self.file.write(
'
%s %s
'
%
(t, data))
12
13
def
__getattr__
(self, item):
14
return
getattr(self.file, item)
15
16
17
f1 = FileHandle(
'
a.txt
'
,
'
w
'
)
18
print
(f1.file)
19
#
print(f1.read)
20
f1.write(
"
aabbcc
"
)
21
f1.close()
1
#
_*_coding:utf-8_*_
2
3
#
我们来加上b模式支持
4
import
time
5
class
FileHandle:
6
def
__init__
(self,filename,mode=
'
r
'
,encoding=
'
utf-8
'
):
7
if
'
b
'
in
mode:
8
self.file=
open(filename,mode)
9
else
:
10
self.file=open(filename,mode,encoding=
encoding)
11
self.filename=
filename
12
self.mode=
mode
13
self.encoding=
encoding
14
15
def
write(self,line):
16
if
'
b
'
in
self.mode:
17
if
not
isinstance(line,bytes):
18
raise
TypeError(
'
must be bytes
'
)
19
self.file.write(line)
20
21
def
__getattr__
(self, item):
22
return
getattr(self.file,item)
23
24
def
__str__
(self):
25
if
'
b
'
in
self.mode:
26
res=
"
<_io.BufferedReader name='%s'>
"
%
self.filename
27
else
:
28
res=
"
<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>
"
%
(self.filename,self.mode,self.encoding)
29
return
res
30
31
32
f1=FileHandle(
'
b.txt
'
,
'
wb
'
)
33
#
f1.write('你好啊啊啊啊啊') #自定制的write,不用在进行encode转成二进制去写了,简单,大气
34
f1.write(
'
你好啊
'
.encode(
'
utf-8
'
))
35
print
(f1)
36
f1.close()

