面对对象(特殊方法)
一、__str__ 用法:
1.1 定义:
如果不实现str方法,那么对象打印出来只是对象的内存地址
直接打印这个实例化对象时,自动触发__str__方法
使用字符串格式化(%s/f{name}/{}.format)时,自动触发__str__方法
1.2 示例:
# 示例: class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period # 如果不实现str方法,那么对象打印出来只是对象的内存地址 def __str__(self): '''打印这个对象的时候 自动触发__str__''' '''使用%s进行字符串的拼接的时候 自动触发__str__''' return '%s,%s,%s' % (self.name, self.price, self.period) python = Course('python', 25000, '6 months') # 实例化 print(python) # 普通打印 print('course %s' % python) # 格式化字符串方式一 print(f'course {python}') # 格式化字符串方式二
二、 __str__ 与 __repr__ 用法:
2.1 三种类型:
1、如果str存在,repr也存在:
那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
而repr(obj)和%r格式化字符串,都会调用__repr__
2、如果str不存在,repr存在:
那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__
3、如果str存在,repr不存在
那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
repr(obj)和%r格式化字符串 都只会只打印出内存地址
2.2 示例:
# 示例: class Course: def __init__(self,name,price,period): self.name = name self.price = price self.period = period def __repr__(self): # 备胎 return '%s,%s,%s' % (self.name, self.price, self.period) def __str__(self): return self.name # 字符串方法必须有一个return返回值,且必须为字符串类型 python = Course('python', 25000, '6 months') print(python) print('course %s' % python) print(f'course {python}') print(repr(python)) print('course %r' % python) # str方式: print(str('123')) # repr方式: print(repr('123'))
三、 __new__ 构造方法:
3.1 定义:
创建对象的时候使用,通过构成方法,创建一个self对象
通过构造方法,实现单例模式
3.2 实例化:
定义一个类时,先开辟一块儿空间,如果定义了__new__方法,使用的是类内部__new__方法
如果我们的定义的类中是没有__new__方法,创建实例对象时调用object类的__new__方法
__new__方法就是在内存中开辟一块属于这个对象(self)的空间,并且在这个空间中存放一个类指针
3.3 构造方法示例:
# 示例: class Foo: # cls永远不能使self参数,因为self在之后才被创建 def __new__(cls, *args, **kwargs): # __new__创造self对象 print('in new') # 先执行 obj = object.__new__(cls) print(obj) return obj def __init__(self): print('init', self) # 后执行 Foo() # 实例化,先执行__new__方法,后执行__init__方法
3.4 单例模式:
定义:
一个类 有且只能有一个实例
保证一个类无论被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址
示例1:
# 示例: class A: __flag = None def __new__(cls, *args, **kwargs): if cls.__flag is None: cls.__flag = object.__new__(cls) return cls.__flag def __init__(self,name=None,age=None): self.name = name if age: self.age = age a1 = A('alex',84) print(a1) a2 = A('alex',83) print(a2) a3 = A('alex') print(a3) print(a1.age)
示例2:
# 装饰器实现单例模式 def singleton(cls): _instance = {} def _singleton(*args, **kwargs): if cls not in _instance: _instance[cls] = cls(*args, **kwargs) return _instance[cls] return _singleton @singleton class B(object): def __init__(self, name): self.name = name b1 = B("apple") b2 = B("orange") print(b1, b2)
示例3:
# 通过类实现单例模式 # 需要加锁,否则多线程会出问题 import time import threading class Singleton(object):
# 实例化Lock _instance_lock = threading.Lock() def __init__(self): time.sleep(1) # 实现一个静态方法 @classmethod def instance(cls, *args, **kwargs): # 上下文的形式加锁 with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance def task(arg): obj = Singleton.instance() print(obj) for i in range(10): t = threading.Thread(target=task, args=[i, ]) t.start() time.sleep(10) obj = Singleton.instance() print(obj)
示例4:
# 因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。 # 们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象 # a.py class Singleton(object): def foo(self): pass singleton = Singleton()
# 使用时,直接在a.py文件中导入此文件中的对象,这个对象即是单例模式的对象 from a import singleton
示例5:元类创建单例模式
import threading class SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super().__call__(*args, **kwargs) return cls._instance class Singleton(metaclass=SingletonType): def __init__(self): pass obj1 = Singleton() obj2 = Singleton() print(obj1 is obj2)
四、 __del__析构方法:
4.1 定义:
1、类中定义del方法,则会执行类中的__del__方法,此处的__del__方法只对类的对象做析构,与属性的析构方法无关。
2、在所有的代码都执行完毕之后,所有的值都会被python解释器回收。
3、如果类中未自定义__del__方法,则会执行父类(object)类中的__del__方法实现某析构,比如在文件操作后,在__del__方法中关闭文件句柄等,可以及时归还系统资源。
4.2 析构方法(__del__)的作用:
1、归还系统资源,例如关闭文件句柄,关闭套接字等等
2、析构方法一定是在删除对象(self)之前执行完成的,否则无法归还系统资源
4.2 示例:
# 示例一: import time class A: def __init__(self,name,age): self.name = name self.age = age def __del__(self): # 只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容 print('执行我啦') a = A('alex',84) print(a.name) time.sleep(1) del a # 通过__del__方法删除对象 a # 示例二: # 与文件操作相关,__del__方法归还系统资源 import time class A: def __init__(self,path): self.f = open(path,'w') def __del__(self): '''归还一些操作系统的资源的时候使用''' '''包括文件\网络\数据库连接''' self.f.close() a = A('userinfo') time.sleep(1)
五、 __call__方法:
5.1 定义:
实例化对象 + () :调用对象时,自动触发__call__中的内容
5.2 示例:
# 示例: class A: def call(self): print('in call') def __call__(self, *args, **kwargs): print('in __call__') A()() # 调用__call__方法 obj = A() # 实例化 obj() # 调用__call__方法 obj.call() # 自定义的类方法
六、 with的上下文处理(enter,exit):
6.1 定义:
__enter__方法 + __exit__方法结合使用,实现上下文管理
返回值:__enter__方法 的返回值
6.2 示例:
# 示例: # 写文件: import pickle class MypickleDump: def __init__(self, path, mode='ab'): self.path = path self.mode = mode # with的起始函数 def __enter__(self): self.f = open(self.path, self.mode) return self # 文件写入 def dump(self, obj): pickle.dump(obj, self.f) # with的终止函数 def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() with MypickleDump('pickle_file') as pickle_obj: # 实例化对象 pickle_obj.dump({1, 2, 3}) # 读文件: class MypickelLoad: def __init__(self, path, mode='rb'): self.path = path self.mode = mode def __enter__(self): self.f = open(self.path, self.mode) return self # 文件的读取 def loaditer(self): while True: # 异常处理,读取所有文件 try: ret = pickle.load(self.f) yield ret except EOFError: break def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() with MypickelLoad('pickle_file') as mypic: # 实例化对象 for obj in mypic.loaditer(): print(obj)
七、__module__方法
__module__ 描述:
- 如果当前模块为顶层模块执行 则打印__main__
- 如果当前模块为被调用模块的时候 打印当前模块的名称
test.py文件:
def func(): print("hello world!") if __name__ == '__main__': func() print(func.__module__) 打印结果: hello world! __main__
test2.py文件,通过导入test.py文件执行func函数:
from day9020190712.test import func if __name__ == '__main__': func() print(func.__module__) 打印结果: hello world! day9020190712.test
八、子类继承父类的三种方式
class Dog(Animal): #子类 派生类 def __init__(self,name,breed, life_value,aggr): # Animal.__init__(self,name,breed, life_value,aggr) #让子类执行父类的方法 就是父类名.方法名(参数),连self都得传 super().__init__(name,life_value,aggr) #super关键字 ,都不用传self了,在新式类里的 # super(Dog,self).__init__(name,life_value,aggr) #上面super是简写 self.breed = breed
def bite(self,person): #狗的派生方法 person.life_value -= self.aggr
# 重构父类方法的优点:代码更简洁。缺点:增加了耦合性,后期维护困难 def eat(self): #父类方法的重写 super().eat() # 执行父类方法 print('dog is eating') # 重写eat新增加的代码方法
九、__getitem__方法
class A(object): def __init__(self, name, age): self.name = name self.age = age def __getitem__(self, item): print(item) a = A("alex", 12) print(a.age) a["name"] a["age"] # 答案: 12 name age
十、重写__setitem__方法
class Foo(object): def __setitem__(self, key, value): print(key,value) obj = Foo() obj["xxx"] = 123 #给对象赋值就会去执行__setitem__方法
十一、继承dict方法
11.1 继承dict方法:
class Foo(dict): pass obj = Foo() obj["xxx"] = 123 print(obj)
#答案:
{"xxx": 123}
11.2 继承dict,重写__init__方法:
注意:重写__init__方法时,记得要继承父类的__init__方法
class Foo(dict): def __init__(self,val): super(Foo,self).__init__(val) # 继承父类的__init__方法
obj = Foo({"xxx": 123}) print(obj)
#答案
{"xxx": 123}
十二、__getattr__ 方法
class A(object): def __getattr__(self, item): print(item) a = A() a.name a.age
# 答案:
name
age
十三、__eq__方法
返回结果只跟__eq__方法的return返回值有关。
class A(object): def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return self.name == other.name a1 = A("alex", 12) a2 = A("egon", 13) print(a1 == a2)
# 答案 False
十四、__gt__方法
class A(object): def __init__(self, name, age): self.name = name self.age = age def __gt__(self, other): return self.age > other.age a1 = A("alex", 12) a2 = A("egon", 18) a3 = A("andy", 15) lst = [a1, a2, a3] lst.sort() print([a.age for a in lst]) # 答案: [12, 15, 18]