每个编程语言都有自己的最佳实践.通常你不能套用别的语言来写出pythonic
的代码.
Python
是一门初学简单,越学越难的语言.
在Python
的世界中, 万物皆对象.当我们说某个对象是什么类型时,在根本上其实指的是:这个对象满足了该类型的特定接口规范,可以被当成这个类型来使用.
如何定义一个对象的特定接口呢?
dunder methods
, 即双下划线方法.
Python
的对象定义了非常多的双下划线方法,比如 __init__
/__eq__
/__hash__
等等,接下来进行实战中常见一个小总结
__str__
当对象定义了以上协议,就可以使用str函数,打印自定义的结果
class Foo:
def __str__(self):
return 'my name is bingo!'
print(Foo())
__format__
将对象表示成字符串,有利于开发者理解
# 额外定义展示格式:long/short.其中long打印出当前对象在内存中的位置
class Foo:
def __format__(self, fmt):
if fmt == 'long':
return 'I am a Foo instance, I stay at {}'.format(id(self))
elif fmt == 'short':
return 'I am a Foo instance.'
f1 = Foo()
f2 = Foo()
print('{:long}'.format(f1))
# I am a Foo instance, I stay at 139870957014152
print('{:short}'.format(f2))
# I am a Foo instance.
__bool__
当对象定义了以上协议,在进行布尔判断时,使用自定义的逻辑
class Foo:
def __bool__(self):
return True # 当进行布尔判断时,永远返回True.仅仅是一个示例,没有实际价值
if Foo():
print('yes')
# yes
__enter__
和 __exit__
当对象定义了以上两种协议时,此对象可以作为上下文文件管理器
__hash__
和 __eq__
当对象定义了以上两种协议时, 此对象可以作为可哈希对象,可以作为字典的键和集合的元素.
来自 腾讯技术专栏 的一个例子.这个例子需要使用集合的差集计算,所以需要实现上述两个协议.
class VisitRecord:
"""旅游记录
"""
def __init__(self, first_name, last_name, phone_number, date_visited):
self.first_name = first_name
self.last_name = last_name
self.phone_number = phone_number
self.date_visited = date_visited
def __hash__(self):
return hash(
(self.first_name, self.last_name, self.phone_number)
)
def __eq__(self, other):
# 当两条访问记录的名字与电话号相等时,判定二者相等。
if isinstance(other, VisitRecord) and hash(other) == hash(self):
return True
return False