一、私有方法
- 私有方法: 在方法名前添加两个下划线
__
class Person:
def __run(self):
print("跑")
print(Person.__dict__)
# 打印:
# {'__module__': '__main__', '_Person__run': , '__dict__': , '__weakref__': , '__doc__': None}
复制代码
- 有打印可知:
__run
方法被重整为_Person__run
方法
p = Person()
p._Person__run() # 打印: 跑
复制代码
- 如果额外添加一个
_Person__run
方法, 将会覆盖__run
方法
class Person:
def __run(self):
print("跑")
def _Person__run(self):
print("pao")
def run(self):
self.__run()
self._Person__run()
p = Person()
p.run()
# 打印:
# pao
# pao
复制代码
对方法进行命名时, 不要使用类似
_Person__run
的命名方式, 以防止覆盖私有方法
二、特殊内置方法
1、__init__
__init__
在实例初始化的时候调用, 可以在此时设置实例属性, 同时可以传入参数
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("张三", 18)
print(p.name, p.age) # 打印: 张三 18
复制代码
2、__str__
- 当打印实例的时候, 会调用实例的
__str__
方法, 将该方法的返回值打印出来
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return "%s %s"%(self.name, self.age)
p1 = Person("张三", 18)
print(p1) # 打印: 张三 18
p2 = Person("李四", 20)
print(p2) # 打印: 李四 20
复制代码
内置函数
str(实例)
, 也可以获取该实例__str__
方法的返回值
s = str(p1) print(s, type(s)) # 打印: 张三 18
复制代码
3、__repr__
- 在上面, 通过
print
函数打印实例时, 会调用实例的__str__
方法, 而当类没有重写__str__
方法时, 就会调用__repr__
, 并打印返回值 __repr__
: 返回实例的详细信息, 主要给开发人员调试使用, 我们可以重写该方法的实现
class Person:
def __repr__(self):
return "xxxxx"
p = Person()
print(p) # 打印: xxxxx
复制代码
- 同时可以使用函数
repr(实例)
, 来获取实例__repr__
的返回值
tmp = repr(p)
print(tmp) # 打印: xxxxx
复制代码
- 如果实现了
__str__
方法, 只能通过repr()
函数获取__repr__
的返回值
class Person:
def __str__(self):
return "str"
def __repr__(self):
return "repr"
p = Person()
print(p) # 打印: str
tmp = repr(p)
print(tmp) # 打印: repr
复制代码
- 当我们不重写
__repr__
方法时, 可以获取到实例的详细信息
class Person:
def __str__(self):
return "str"
p = Person()
print(p) # 打印: str
tmp = repr(p)
print(tmp) # 打印: <__main__.Person object at 0x1034017b8>
复制代码
- 可以使用
eval()
函数, 将repr()
获取的实例信息, 转为一个实例
import datetime
r = datetime.datetime.now()
print(r) # 打印: 2018-04-11 15:55:40.726878
tmp = repr(r)
print(tmp) # 打印: datetime.datetime(2018, 4, 11, 15, 55, 40, 726878)
result = eval(tmp)
print(result) # 打印: 2018-04-11 15:55:40.726878
复制代码
4、__call__
__call__
: 可以使一个实例如同函数一样调用
class Person:
def __call__(self, *args, **kwargs):
print("xxx", args, kwargs)
p = Person()
p() # 打印: xxx () {}
p(123, name = "zhangsan") # xxx (123,) {'name': 'zhangsan'}
复制代码
__call__
方法的应用场景: 可以用作偏好函数使用
# 现有两种类型的笔(钢笔, 铅笔), 以及多种颜色(红色, 绿色, 黄色, 黑色)
# 创建不同种类, 不同颜色的笔
class PenFactory:
def __init__(self, p_type):
self.p_type = p_type
def __call__(self, p_color):
print("这是一支%s, 颜色是%s"%(self.p_type, p_color))
penF = PenFactory("钢笔")
penF("红色") # 打印: 这是一支钢笔, 颜色是红色
penF("绿色") # 打印: 这是一支钢笔, 颜色是绿色
penF("黄色") # 打印: 这是一支钢笔, 颜色是黄色
penF("黑色") # 打印: 这是一支钢笔, 颜色是黑色
pencilF = PenFactory("铅笔")
pencilF("红色") # 打印: 这是一支铅笔, 颜色是红色
pencilF("绿色") # 打印: 这是一支铅笔, 颜色是绿色
pencilF("黄色") # 打印: 这是一支铅笔, 颜色是黄色
pencilF("黑色") # 打印: 这是一支铅笔, 颜色是黑色
复制代码
5、索引操作
- 可以如同使用字典的方式, 操作实例, 只需实现下面的方法
class Person:
# 初始时, 创建缓存字典
def __init__(self):
self.cache = {}
# 增/改
def __setitem__(self, key, value):
self.cache[key] = value
# 取
def __getitem__(self, item):
return self.cache[item]
# 删
def __delitem__(self, key):
del self.cache[key]
p = Person()
print(p.cache) # 打印: {}
p["age"] = 18 # 调用__setitem__方法
print(p.cache) # 打印: {'age' : 18}
age = p["age"] # 调用__getitem__方法
print(age) # 打印: 18
del p["age"] # 调用__delitem__方法
print(p.cache) # 打印: {}
复制代码
6、切片操作
- 实例的切片操作和索引操作一样, 需要实现三个方法
class Person:
# 改
def __setitem__(self, key, value):
print(key, value)
# 取
def __getitem__(self, item):
print(item)
# 删
def __delitem__(self, key):
print(key)
p = Person()
p[0:4:2] = ["a", "b"] # 打印: slice(0, 4, 2) ['a', 'b']
p[1:5:2] # 打印: slice(1, 5, 2)
del p[2:6:4] # 打印: slice(2, 6, 4)
复制代码
- 上面代码中, 打印的
slice
, 就是切片类型, 我们可以给实例添加一个列表属性, 用来操作切片
class Person:
# 改
def __setitem__(self, key, value):
print(key)
print(key.start) # 起点
print(key.stop) # 终点
print(key.step) # 步长
p = Person()
p[0:4:2] = ["a", "b"]
# 打印:
# slice(0, 4, 2)
# 0
# 4
# 2
复制代码
- 实际操作如下
class Person:
def __init__(self):
self.cache = [0, 1, 2, 3, 4, 5, 6, 7]
# 改
def __setitem__(self, key, value):
self.cache[key] = value
# 取
def __getitem__(self, item):
return self.cache[item]
# 删
def __delitem__(self, key):
del self.cache[key]
p = Person()
p[0:4:2] = ["a", "b"]
print(p.cache) # 打印: ['a', 1, 'b', 3, 4, 5, 6, 7]
result = p[0:4:2]
print(result) # 打印: ['a', 'b']
del p[0:4:2]
print(p.cache) # 打印: [1, 3, 4, 5, 6, 7]
复制代码
7、比较操作
-
作用: 可以自定义对象"比较大小, 相等以及真假"的规则
-
对象之间进行比较, 需要实现几个对应的方法
比较 | 方法 |
---|---|
相等 | __eq__ |
不相等 | __ne__ |
小于 | __lt__ |
小于或等于 | __le__ |
大于 | __gt__ |
大于或等于 | __ge__ |
- 以相等为例, 指定对象相等时的条件
class Person:
def __init__(self, age):
self.age = age
def __eq__(self, other):
return self.age == other
p1 = Person(20)
p2 = Person(21)
print(p1 == p2) # 打印: False
复制代码
-
上述六个方法中, 可以分为三组
相等 和 不相等
,小于 和 大于
,小于或等于 和 大于或等于
, 在这三组中, 只要实现某组中的一个, 该组的另一个不需要实现也可以进行比较 -
在这六个方法中, 都有两个参数
self 和 other
, 如果只实现某对中的一个方法, 那么使用两个不同的比较方式, 传入的参数会互相颠倒
class Person:
def __init__(self, age):
self.age = age
def __lt__(self, other):
print(self.age, other.age)
p1 = Person(20)
p2 = Person(21)
p1 < p2 # 打印: 20 21
p1 > p2 # 打印: 21 20
复制代码
注意: 如果是 相等 和 不相等, 在只实现一个改组方法的情况下, 传入参数不会互相颠倒
- 正常境况下, 比较方法不会叠加, 比如实现
小于 和 等于
两个方法, 并不会叠加为支持小于等于
方法, 如果需要, 必须实现小于等于
对应的方法
class Person:
def __init__(self, age):
self.age = age
def __eq__(self, other):
return self.age == other.age
def __lt__(self, other):
print(self.age, other.age)
p = Person(20)
print(Person.__dict__)
# 打印信息:
{
'__module__': '__main__',
'__init__': <function Person.__init__ at 0x104d227b8>,
'__eq__': <function Person.__eq__ at 0x104d22840>,
'__lt__': <function Person.__lt__ at 0x104d228c8>,
'__dict__': '__dict__' of 'Person' objects>,
'__weakref__': '__weakref__' of 'Person' objects>,
'__doc__': None, '__hash__': None
}
复制代码
-
由打印信息可知, 并没有出现其他的比较方法
-
Python中提供了一个装饰器, 可以将比较方法进行叠加, 并衍生出相反的方法
import functools
@functools.total_ordering
class Person:
def __init__(self, age):
self.age = age
def __eq__(self, other):
return self.age == other.age
def __lt__(self, other):
print(self.age, other.age)
p = Person(20)
print(Person.__dict__)
{
'__module__': '__main__',
'__init__': <function Person.__init__ at 0x1038227b8>,
'__eq__': <function Person.__eq__ at 0x103822840>,
'__lt__': <function Person.__lt__ at 0x1038228c8>,
'__dict__': '__dict__' of 'Person' objects>,
'__weakref__': '__weakref__' of 'Person' objects>,
'__doc__': None, '__hash__': None,
'__gt__': <function _gt_from_lt at 0x101fe3a60>,
'__le__': <function _le_from_lt at 0x101fe3ae8>,
'__ge__': <function _ge_from_lt at 0x101fe3b70>
}
复制代码
- 由打印可以看出, 通过
__eq__
和__lt__
, 衍生出__gt__
,__le__
,__ge__
8、__bool__
-
__bool__
: 当实例做为条件语句时, 决定实例的真或假 -
在Python中, 判断条件是
非0即真, 非空即真
, 而实例对象也可以作为判断语句
class Person:
def __bool__(self):
return True
p = Person()
if p:
print("xxx")
else:
print("ooo")
# 打印: xxx
复制代码
class Person:
def __bool__(self):
return False
p = Person()
if p:
print("xxx")
else:
print("ooo")
# 打印: ooo
复制代码