Python3笔记043 - 7.9 特殊方法
第7章 面向对象程序设计
- 7.1 面向对象概述
- 7.2 类的定义
- 7.3 类的实例化
- 7.4 访问限制
- 7.5 继承
- 7.6 封装
- 7.7 多态
- 7.8 装饰器
- 7.9 特殊方法
7.9 特殊方法
__format__
用于将对象格式化输出
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __format__(self, format_spec):
fmt = {
'-': '{obj.name}-{obj.age}-{obj.city}',
'/': '{obj.name}/{obj.age}/{obj.city}'
}[format_spec]
return fmt.format(obj = self)
p = Person('Kitty', 19, 'HZ')
# format 函数会调用对象的绑定方法 __format__
print(format(p, '-'))
print(format(p, '/'))
# 输出结果:
Kitty-19-HZ
Kitty/19/HZ
__del__
析构方法,当对象在内存中被释放时,会自动触发执行。但是此方法一般无须定义,因为Python解释器会来完成内存的分配和释放工作,所以,析构方法的调用是由解释器在进行垃圾回收时自动触发执行的。
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def __del__(self):
print('delete...')
p = Person('Kitty', 19, 'HZ')
del p
# 输出结果:
delete...
item系列
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, item):
self.__dict__.pop(item)
def __delattr__(self, key):
self.__dict__.pop(key)
p = Person('Kitty', 19)
print(p['name']) # Kitty,调用 __getitem__ 方法
p['age'] = 18
print(p['age']) # 18
p['city'] = 'HZ'
print(p.__dict__) # 调用 __setitem__ 方法
# {'name': 'Kitty', 'age': 18, 'city': 'HZ'}
del p['city'] # 调用 __delitem__ 方法
print(p.__dict__)
# {'name': 'Kitty', 'age': 18}
del p.age # 调用 __delattr__ 方法
print(p.__dict__)
# {'name': 'Kitty'}
__len__
len(obj) 会调用obj的 __len__
方法
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __len__(self):
return len(self.__dict__)
p = Person('Kitty', 19)
print(len(p)) # 2
__call__
对象后面加括号,就会触发 __call__
方法的执行,即调用方式:对象() 或者 类()()
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __call__(self):
print('hello' + ' ' + self.__name)
p = Person('Kitty', 19)() # hello Kitty
# p()
__new__
在类的是实例化过程中,第一个被调用的是 __new__方法。在对象的初始化之前首先要创建对象,__new__
方法正是用来创建这个对象~
类的实例化过程也可以通过如下语句来实现:
>>> p = object.__new__(Person)
>>> Person.__init__(p, 'Kitty', 18)
>>> p.name
'Kitty'
在Person类中重写 __new__
方法:
class Person:
country = "China"
def __new__(cls, name, age):
print('__new__ called')
return super(Person, cls).__new__(cls)
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self, word):
print(word)
p = Person('Kitty', 18) # 实例化对象
print('name : %s' % p.name)
# 输出结果:
__new__ called
name : Kitty
可以看到 new 方法 是先于 __init__
方法被调用的~
类的实例化过程大致步骤如下:
1、p = Person('Kitty', 18) ,会调用 Person类的 new 方法,并传递 name 和 age 参数
2、new 方法 会创建一个 Person类的对象并返回
3、最后利用这个对象调用类的 __init__
方法 完成初始化, __init__
方法的第一个参数是self,对象在调用 __init__
方法时会将自己当做参数传递给 这个self。
单例模式
重写 new 来实现单例模式~
class Person:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Person, cls).__new__(cls, *args, **kwargs)
return cls._instance
p1 = Person()
p2 = Person()
print(p1) # <__main__.Person object at 0x108eb6438>
print(p2) # <__main__.Person object at 0x108eb6438>
对象的内存地址相同,则表示为同一个对象~
__hash__
和__eq__
在判断两个对象是否一致时,往往会用到这两个函数~
__hash__
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def __hash__(self):
return hash(str(self.__name))
p = Person('Kitty', '19')
print(hash(p))
__eq__
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, obj):
if self.name == obj.name and self.age == obj.age:
return True
p1 = Person('Kitty', '19')
p2 = Person('Kitty', '19')
print(p1 == p2) # True
集合(set)是一个无序不重复元素的序列。集合中只能存放不可变对象(可hash的)。在向 set 集合中添加对象时,会通过调用对象的 __hash__
和 __eq__
这两个方法来判断集合中是否已经存在一样的对象~
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __hash__(self):
print('调用了__hash__方法')
return hash(self.name)
def __eq__(self, obj):
print('调用了__eq__方法')
return self.name == obj.name and self.age == obj.age
def __str__(self):
return '(' + self.name + ', ' + self.age + ')'
p1 = Person('Tom', '19') # 调用了__hash__方法
p2 = Person('Jeff', '20') # 调用了__hash__方法
my_set = {p1, p2}
for i in my_set:
print(i) # (Jeff, 20), (Tom, 19)
在向 set 集合中添加对象时,会首先调用对象的 hash 若是 返回的 hash值不一样,则认为不是重复的对象,进行添加~
p1 = Person('Tom', '19') # 调用了__hash__方法
p2 = Person('Tom', '20') # 调用了__hash__方法,调用了__eq__方法
my_set = {p1, p2}
for i in my_set: # (Tom, 20), (Tom, 19)
print(i)
若是返回的hash值有重复的,则会接着调用对象 __eq__
方法,若 __eq__
方法的返回值为False,则认为不是重复对象,进行添加,若返回为True,则不进行添加~