面向对象2
一.元类(type)
type元类又称构建类。
python中一切皆对象,类也是一个对象。python中大多数内置的类(包括object)以及自己定义的类,都是由type元类创造的。
1.type获取对象从属的类
# 以下三种方法得到各自从属的类str、list、tuple
print(type('123')) #<class 'str'>
print(type([1,2,3])) #<class 'list'>
print(type((1,2,3))) #<class 'tuple'>
#str、list、tuple都是源码中的类,同属于type元类
print(type(str)) #<class 'type'>
print(type(list)) #<class 'type'>
print(type(tuple)) #<class 'type'>
2.type和object的关系
object是所有类的父类(包含type类),type元类可以实例化成所有类(包含object)。总的来说,object实例化对象,type实例化类
# object类是type类的一个实例
print(type(object)) #<class 'type'>
# object类是type类的父类
print(issubclass(type,object)) # True
二.反射
反射是程序对自己内部代码的一种自省方式。
python面向对象中的反射:通过字符串的形式操作对象相关的属性。(python中一切事物都是对象,都可以使用反射)
下面通过四种方式实现代码自省(反射)
1.对对象的反射
class A:
country = "中国"
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print("in A func")
obj = A("alex",11)
print(hasattr(obj,"name")) # True 判断obj对象是否有name属性
print(getattr(obj,"age",None)) # 11 得到obj的age属性,默认得到None
getattr(obj,"func")()
setattr(obj,"name","wusir")
delattr(obj,"name")
2.对类的反射
class A:
country = "中国"
def __init__(self,name,age):
self.name = name
self.age = age
def func(self):
print("in A func")
print(hasattr(A,'country')) # True
getattr(A,"func")(1)
3.从其他模块
# module_test.py
def test():
print("from the test")
# index.py
import module_test as obj
print(hasattr(obj,'test')) # True
getattr(obj,"test")() # 打印 from the test
4.从当前模块
import sys
def func():
print("func")
current_modules = sys.modules[__name__] # 得到当前文件这个模块
hasattr(current_modules,"func") # True
getattr(current_modules,"func")() # 打印func
三.函数和方法的区别
函数都是显性传参,方法都是隐形传参(谨记)
以下有两种方法区分方法和函数:
1.打印函数名
通过类名调用类中的实例方法叫做函数
通过对象调用类中的实例方法叫方法
def func1():
pass
class A:
def func(self):
pass
print(func1) # <function func1 at 0x000001B5A5A0A8C8>
print(A.func) # <function A.func at 0x000001B5A5A0A950>
obj = A()
print(obj.func) # <bound method A.func of <__main__.A object at 0x000001B5A5A084A8>>
类中的静态方法其本质就是函数,类中的类方法就是方法
class A:
@staticmethod
def func1():
pass
@classmethod
def func2(cls):
pass
print(A.func1) # <function A.func1 at 0x000002D6FD10A9D8>
a = A()
print(a.func1) # <function A.func1 at 0x000002D6FD10A9D8>
print(A.func2) # <bound method A.func2 of <class '__main__.A'>>
print(a.func2) # <bound method A.func2 of <class '__main__.A'>>
2.借助模块判断
FunctionType 判断是否是函数
MethodType 判断是否是方法
from types import FunctionType
from types import MethodType
def func():
pass
class A:
def func(self):
pass
obj = A()
print(isinstance(func,FunctionType))
print(isinstance(A.func,FunctionType))
print(isinstance(obj.func,FunctionType))
print(isinstance(obj.func,MethodType))
四.特殊的双下方法
双下方法是特殊方法,是由python解释器提供的。
不同的双下方法有不同的触发方式。
1.__len__
len('alex') # 自动执行'alex'所属类(str)的__len__方法
len([1,2,3]) # 自动执行[1,2,3]所属类(list)的__len__方法
class B:
def __len__(self):
return 666
b = B()
len(b) # 自动执行对象b所属类B的__len__()方法
2.__hash__
class A:
def __init__(self):
self.a = 1
self.b = 2
def __hash__(self):
return hash(str(self.a) + str(self.b))
a = A()
hash(a) # 自动执行a的所属类A的__hash__方法
3.__str__
在打印对象或者str()方法时,自动执行对象所属类的__str__方法
class A:
def __init__(self):
pass
def __str__(self):
return '太白'
a = A()
print(a) # 自动执行a所属类A的__str__方法
4.__repr__
repr()执行对象所属类中的__repr__方法,返回对象的原有形态
class A:
def __init__(self):
pass
def __repr__(self):
return '太白'
a = A()
repr(a) # 自动执行a所属类A的__repr__方法
5.__call__
对象(),自动触发执行对象从属类的__call__方法
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print("__call__")
obj = Foo()
obj() # 打印 __call__
# 如果类中没有__call__方法,报错:TypeError: 'Foo' object is not callable
6.__eq__
class A:
def __init__(self):
self.a = 1
def __eq__(self, other):
if self.a == other.a:
return True
x = A()
y = A()
print(x == y) # 自动执行x和y从属类A的__eq__方法,将x传给self,y传给other
7.__del__
析构方法。(python中的垃圾回收机制,程序执行完,自动回收)
class A:
def __del__(self):
print(666)
obj = A() # 执行完自动执行obj所属类A的__del__方法
8.__new__
class A:
def __init__(self):
self.x = 1
print("in init function")
def __new__(cls, *args, **kwargs):
print("in new function")
return object.__new__(A) # 必须要有此行代码,不然对象()只会执行__new__方法,不执行__init__方法
a = A()
# 类名()
'''
1.先触发object类的__new__方法,此方法在内存中开辟一个对象空间
2.执行__init__的方法
'''
9.__item__系列
对象如果以字典形式出现,自动触发item系列中的方法。
class Foo:
def __init__(self,name):
self.name = name
def __getitem__(self, item): # self=f1 item='age'
print(self.__dict__)
def __setitem__(self, key, value): # self=f1 key='age1' value=18
self.__dict__[key] = value
def __delitem__(self, key): # self=f1 key='age1'
print(key)
def __delattr__(self, item): # self=f1 item='age'
print(item)
f1 = Foo('sb')
f1['age'] # 执行__getitem__()
f1['age1'] = 18 # 执行__setitem__()
del f1['age1'] # 执行__delitem__()
del f1.age # 执行__delattr__(),父类如果没有__delattr__()方法,会执行object中的,真的删除
10.上下文管理器相关
对于自己定义的类,如果想使用with statment方法,必须要在类中添加__enter__()和__exit__()两方法,缺一不可。
这种例子会报错:
class A:
def __init__(self,text):
self.text = text
with A("打印") as f:
print(f.text)
类中添加__enter__()和__exit__()方法后不会报错
class A:
def __init__(self,text):
self.text = text
def __enter__(self): # 开启上下文管理器对象时触发此方法
self.text = self.text + "您来了"
return self # 固定写法,返回self
def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f触发此方法
self.text = self.text + "这就走了"
with A("大爷") as f:
print(f.text) # 大爷您来了
print(f.text) # 大爷您来了这就走了
11. __iter__
class A:
def __init__(self,name):
self.name = name
def __iter__(self):
yield 10
obj = A("alex")
for i in obj: # for循环obj,自动执行类A中的__iter__()方法,有__iter__()方法,使得obj为可迭代对象。
print(i)
五.单例模式
所有实例化对象公用一个内存地址。
好处:节省内存
应用场景:
1.django中settings配置文件(项目启动将settings配置文件加载到内存,再开项目直接去内存中读取settings)
2.django的admin内部使用,将不同app的表都加载到一个内存中
3.数据库连接池
4.logger日志
class Singleton(object):
instance = None
lock = threading.RLock()
def __new__(cls, *arg, **kwargs):
if cls.instance:
return cls.instance
with cls.lock:
if not cls.instance:
cls.instance = object.__new__(cls)
return cls.instance
obj = A("alex")
print(obj) # <__main__.A object at 0x0000014B366A8470>
obj1 = A("wusir")
print(obj1) # <__main__.A object at 0x0000014B366A8470>