文章目录
面向对象3大基本特征:封装 继承 多态
1. 继承
class Animal():
tel = 123456 # 类属性
__gender = 'male' # 私有类属性
def __init__(self, name, age, addr):
# 关键字self表示该方法的对象,python解释器会将对象作为第一个参数传递给函数
self.name = name # 实例属性
self.age = age # 实例属性
self.__addr = addr # 私有实例属性
def __view(self):
# 私有方法:在方法前加上 __
print(self.name + ' ', self.age, tel)
def viewd(self):
# 实例方法
print(tel)
# 类方法:使用装饰器@classmethod,第一个参数是类对象cls,一般配合类属性使用
@classmethod
def play(cls):
print(cls.name)
# 静态方法:使用装饰器@staticmethod,参数不需要传递类对象或实例对象。
@staticmethod
def jump(name):
print('jump', name)
class Dog(Animal):
def __init__(self,name, age, addr, pro):
# 重写父类Animal的__init__方法,还需使用父类__init__方法,需要使用super()方法,不然无法使用父类的name,age,addr属性
super(Dog, self).__init__(name, age, addr)
self.pro = pro
def eat(self):
print(self.pro, self.name)
dog = Dog(name='xiao', age=12, addr='fujian', pro='IT')
dog.eat()
# 子类不能继承父类私有属性和私有方法,子类可调用父类的共有方法访问父类的私有属性,私有方法。
# dog.__view() # Aninal 私有方法__view Dog不能继承 AttributeError: 'Dog' object has no attribute '__view'
# print(dog.__addr) # Animal 私有属性__addr Dog不能继承 AttributeError: 'Dog' object has no attribute '__addr'
# 类属性能被类对象和所有的实例对象访问,类属性只能被类对象修改。类属性和实例属性同名,实例对象优先使用实例属性。
print(dog.tel, Dog.tel, Animal.tel)
# 静态方法:可被实例对象和类对象访问。同时定义同名的实例方法、类方法和静态方法,优先类中最后定义的方法。
dog.jump('123')
Dog.jump('123')
# _xxx "单下划线 " 开始的成员变量叫做保护变量,意思是只有类对象(即类实例)和子类对象自己能访问到这些变量,需通过类提供的接口进行访问;不能用'from module import *'导入
from test import *
mt = Master()
print(age, mt._age, mt.name) # 99 66 xiaoming
print(_age) # NameError: name '_age' is not defined
import test
mt = test.Master()
print(test.age, mt._age, mt.name) # 99 66 xiaoming
print(test._age) # 88
# test.py
class Master():
def __init__(self):
self.name = 'xiaoming'
self._age = 66
def jump(self):
print('55')
_age = 88
age = 99
2. 多继承
# 多继承: 子类继承多个父类
class A():
def play(self):
print('A.play')
class B():
def eat(self):
print('B.eat')
class C(A, B):
def jump(self):
print('C.jump')
# 多继承的继承顺序:优先使用子类自己的方法和属性(参照C3算法)
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
3. 多态
# 多态:能在使用父类对象的地方也能使用子类对象。注意:解决Java或C#需要先声明参数类型
class A():
def play(self):
print('A.play')
class B():
def play(self):
print('B.play')
def demo(obj):
# obj 传参为实例对象名
obj.play()
b = B()
demo(b) # B.play
4. 魔法方法
# 魔法方法:在方法名两侧带有的__的方法
class Animal():
'''hhh'''
def __new__(cls, name):
# __new__方法:用于创建对象,一般python解释器提供,必须有返回值且返回值为创建的对象,可return 父类__new__的实例,也可直接返回object的__new__实例。
# 第一个参数必须是cls,代表要实例化的类。重写__new__方法之后,需要保留__init__方法中的形参位置,否则__init__方法将无法获取到参数。
# return super().__new__(cls, name)
return object.__new__(cls) # 返回object __new__的实例
def __init__(self, name):
# __init__方法:用于对象初始化,第一个参数必须是self,不需要返回值。
self.name = name
print( self.name + '__init__')
def __str__(self):
# __str__方法:通常返回字符串,用户打印类是返回类的描述信息。默认打印的是类的内存地址。
return '__str__'
def __del__(self):
# __del__方法:当对象被删除是将执行此方法
print('__del__')
def __call__(slef, *args, **kwargs):
# __call__方法可以使实例对象变成可调用对象,如
# a = Animal()
# a("555", age=18) # ('555',) ------ {'age': 18}
print(args,"------", kwargs)
class Pig(Animal):
def __new__(cls, name):
# __new__方法:用于创建对象,一般python解释器提供,必须有返回值且返回值为创建的对象,可return 父类__new__的实例,也可直接返回object的__new__实例。
return super().__new__(cls, name)
def __init__(self, name):
self.name = name
print( self.name + '__init__')
def __str__(self):
return 'pig'
def play():
"""hhhh"""
return None
print(play.__doc__) # hhhh 打印类/函数的说明文档
print(Animal.__doc__) # hhhh 打印类/函数的说明文档
ani = Animal('animal')
print(ani)
pig = Pig('pig')
print(pig)
import sys
a = 'hjjcxh'
b = a
c = b
print(sys.getrefcount(a)) # 获取类Animal的引用次数,sys.getrefcount(a)本身也算一次引用
4.1 利用__call__方法可解决hasattr函数针对实例对象无法判断指定的名称到底是类属性还是类方法的问题
# hasattr函数针对函数
def play():
print('function play')
print(hasattr(play, "__call__")) # True
# hasattr函数针对类
class A():
def play(self):
print('A.play')
print(hasattr(A.play, "__call__")) # True
5. type方法与isinstace方法
type方法可返回对象自身的类型,但不考虑对象的继承关系
isinstance用于判断对象的继承关系
class Animal(object):
def __init__(self):
self.attr = "animal"
self.country = "cn"
def print(self):
print(self.country)
class Dog(Animal):
def __init__(self):
self.attr = "dog"
super().__init__()
class WangCai(Dog):
def __init__(self):
self.attr = "wangcai"
super().__init__()
if __name__ == '__main__':
# WangCai的父类
print(WangCai.__bases__) # <class '__main__.Dog'>,)
# WangCai的继承关系
print(WangCai.__mro__) # <class '__main__.WangCai'>, <class '__main__.Dog'>, <class '__main__.Animal'>, <class 'object'>
w = WangCai()
# 判断w是否是Animal子类
print(isinstance(w, Animal)) # True
# 判断w是否是Animal类型
print(type(w) == Animal) # <class '__main__.WangCai'>, False
6. 基类object、元类type与Metaclass
python中一切皆对象,对象是类的实例,所有类都是object的子类,所有类都是type的实例(即type可用于动态创建类)
6.1 类方法、实例方法
类属性可以被实例对象和类直接访问,实例属性(使用self定义的属性)只能被实例对象访问但不能被类访问,实例对象可以修改类属性但不影响类属性和其他实例对象属性。属性可动态修改会影响新创建的实例对象但不影响已创建的实例对象。
class Animal(object):
age = 8
def __init__(self):
self.attr = "animal"
self.country = "cn"
# 创建对象a
a = Animal()
print(a.age) # 8
# 类无法访问实例对象属性,直接报错AttributeError: type object 'Animal' has no attribute 'attr'
# print(Animal.attr)
# 修改实例对象的age属性, 类属性不变
a.age = 9
print(a.age) # 9
print(Animal.age) # 8
# 修改类属性,已创建的实例对象属性不变
Animal.age = 10
print(a.age) # 9
print(Animal.age) # 10
# 新创建对象b
b = Animal()
print(b.age) # 10
6.2 type动态创建类
代码实例:Demo = type(name, bases, attrs)
文字说明:
英文 | 含义 |
---|---|
Demo | type返回的类对象 |
name | 定义类的名称,字符类型 |
bases | 类的父类们,默认为object, 可为空,元组类型 |
attrs | 类属性和类方法(方法第一个参数是cls即类本身), 字典类型:{“属性名称”:值, “方法名”: 方法名称} |
示例:
# 类方法
def run(self, num):
# self.age = 10
print(self.age)
print("实例对象方法: Dog: {} run... 动态参数num:{}".format(self.name, num))
@classmethod
def eat(cls, num):
print("类方法: Dog: {} eat... 动态参数num:{}".format(cls.age, num))
@staticmethod
def talk(num):
print("静态方法, 动态参数num:{}".format(num))
def init(self, country):
self.country = country
# 创建类Dog,等价于 class Dog(Animal):pass,其中定义的属性为类属性,方法为实例方法,定义类方法需要加@classmethod,定义静态方法需要就上@staticmethod,实例对象实例属性需要实现__init__方法
Dog = type("Dog", (Animal,), {"name": "wangcai", "run": run, "eat": eat, "talk": talk, "__init__": init})
dog = Dog("en")
# 实例属性
print(dog.country) # 未实现__init__之前继承自Animal为cn, 修改后为en
# Dog.run(8) # 不能调研实例对象方法,报错TypeError: run() missing 1 required positional argument: 'num'
dog.run(8) # 实例对象方法: Dog: wangcai run... 动态参数num:8
# 类和实例对象都能直接调用类方法(定义类方法需要加上@classmethod)
Dog.eat(8)
dog.eat(8)
# 类和实例对象都能直接调用静态方法
Dog.talk(8) # 静态方法, 动态参数num:8
dog.talk(8) # 静态方法不加@staticmethod会报错TypeError: talk() takes 1 positional argument but 2 were given
print(Dog.name) # wangcai
print(dog.name) # wangcai
dog.name = "xiaoqiang"
print(Dog.name) # wangcai
print(dog.name) # xiaoqiang
6.3 利用MetaClass自定义元类
使用metaclass元类时,该类必须继承自type。
应用场景:针对创建的类进行校验拦截(创建类之前增设条件);修改类扩展功能
6.3.1 示例1: 利用__new__方法和元类在创建TestLit类时添加add方法
class ListMetaClass(type):
def __new__(cls, name, bases, attrs):
attrs["add"] = lambda cls, num: cls.append(num)
return super().__new__(cls, name, bases, attrs)
class TestLit(list, metaclass=ListMetaClass):
pass
ls = TestLit()
ls.add(66)
print(ls)
# print(list.__dict__)
# 类直接调用add报错,因为add方法是实例方法,TypeError: <lambda>() missing 1 required positional argument: 'num'
# TestLit.add(77) # 类直接调用,需要使用@classmethod装饰add方法
ls = TestLit()
ls.add(66)
print(ls)
6.3.2 示例2: 利用元类解决实例对象不通过工厂函数创建而被直接创建的问题
class ObjectBuildFaildException(Exception):
pass
class AnimalMetaClass(type):
def __call__(self, *args, **kwargs):
# 此处self为元类创建的类
if len(args) == 0 or args[0] != "factory":
raise ObjectBuildFaildException("object cannot be build directly")
obj = object.__new__(self)
return obj
class Dog(metaclass=AnimalMetaClass):
def run(self):
print("dog dog dog run....")
class Pig(metaclass=AnimalMetaClass):
def eat(self):
print("pig pig pig eat....")
class Cat(metaclass=AnimalMetaClass):
def shut(self):
print("cat cat cat shut....")
class AnimalFactory(object):
animal_map = {
"pig": Pig,
"dog": Dog,
"cat": Cat
}
def __new__(cls, animal):
obj = cls.animal_map.get(animal)
if obj:
return obj("factory")
else:
return cls.animal_map["cat"]("factory")
# 直接Dog()、Pig()、Cat()创建对象会报错ObjectBuildFaildException, 需要执行如下Dog("factory")
dog = AnimalFactory("dog")
dog.run() # dog dog dog run....
cat = AnimalFactory("cat")
cat.shut() # cat cat cat shut....
cat = AnimalFactory("555")
cat.shut() # cat cat cat shut....
6.3.3 元类中的__new__,__init__和__call__方法
class AnimalMetaClass(type):
# def __new__(cls, class_name, class_parents, class_attr):
# # cls为元类,返回的是元类创建的类,继承元类的类定义之后就会执行new方法
# print('元类__new__')
# return type(class_name, class_parents, class_attr)
def __call__(self, *args, **kwargs):
# 此处self为元类创建的类,若定义__new__方法本方法不执行,返回的是元类创建的类实例
# obj = self.__new__(self) # 手动调用元类创建的类的__new__方法,注意创建的类是否有参数 *args, **kwargs
# self.__init__(*args, **kwargs) # 手动调用元类创建的类的__init__方法,注意创建的类是否有参数 *args, **kwargs
obj = object.__new__(self) # 会屏蔽元类创建的类的__new__方法和__init__方法
# obj = type.__call__(cls, *args, **kwargs) # 会调用元类创建的类的__new__方法和__init__方法
return obj
def __init__(self, *args, **kwargs):
# self为元类创建的类,若定义__new__方法本方法不执行
print('元类__init__')
super().__init__(*args, **kwargs)
class Dog(metaclass=AnimalMetaClass):
def __new__(cls):
return super().__new__(cls)
def __init__(self):
self.name = "dog"
def run(self):
print("dog dog dog run....")
dog = AnimalFactory("dog")
dog.run() # dog dog dog run....
6.3.4 元类执行顺序和继承关系(TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases)
class A(type):
def __new__(cls, name, bases, attrs):
print(name, "Aaaaaaaaaaaaaaaa")
return super().__new__(cls, name, bases, attrs)
class B(type):
def __new__(cls, name, bases, attrs):
print(name, "Bbbbbbbbbbbbbbbbb")
return super().__new__(cls, name, bases, attrs)
class H(object):
def demo(self):
print("demo demo hhhhhhhhhhhhhh")
class Z(object, metaclass=B):
def demo(self):
print("demo demo zzzzzzzzzzzzzzz")
报错:TypeError: metaclass conflict
现象:C继承自Z,元类是A,但是Z元类是B,存在冲突
class C(H, Z, metaclass=A):
def demo(self):
print("demo cccccccccccccccccc")
解决办法:定义类Ab继承自元类A和B,C继承自Z,元类是Ab。但是因为Z类有元类B导致元类B的__new__方法执行2次
class Ab(A, B):
pass
class C(H, Z, metaclass=Ab):
def __new__(cls, *args, **kwargs):
print("new dddddddddddddddddd")
return super().__new__(cls, *args, **kwargs)
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.H'>, <class '__main__.W'>, <class 'object'>)
解决元类方法重复执行问题:将Z类方法复制到W类(普通类,继承自object),而Z类改为继承自W,元类为A(此时单独使用Z类不影响),再将C类继承由Z类改为W,元类为Ab。
class Ab(A, B):
pass
class W(object):
def demo(self):
print("demo demo zzzzzzzzzzzzzzz")
class Z(W, metaclass=B):
pass
class C(H, W, metaclass=Ab):
def __new__(cls, *args, **kwargs):
print("new dddddddddddddddddd")
return super().__new__(cls, *args, **kwargs)
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.H'>, <class '__main__.W'>, <class 'object'>)
代码执行顺序:
定义类阶段:先执行元类方法(只要定义类有元类,无论是否创建实例对象都执行):(先定义Z类)元类B中__new__方法 -->(定义C类,元类Ab继承自A,B)元类A中__new__方法,再元类B中__new__方法。
类创建实例对象后(如下):执行D自己的方法(若存在__new__方法先执行__new__方法必须返回创建的对象,再执行__init__方法),再执行父类方法。若子类方法和父类方法重复,优先执行子类方法;若子类方法继承自父类,执行父类方法,若多个父类方法重复,子类优先执行左边的(实际C3算法)
d = D()
d.demo() # demo demo hhhhhhhhhhhhhh 因为D类未定义demo方法所以执行的是父类H的demo方法
7. 单例对象:确保某一个类只会创建一个实例
7.1 方法一:导入模块(python 的模块是天然的单例模式。首次模块导入产生.pyc文件,第二次直接加载.pyc文件,而不是再次执行模块代码)
7.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 A():
a = 1
def __init__(self, x=0):
self.x = x
7.3 方法三:类方法
import time
import threading
class Singleton():
_instance_lock = threading.Lock() # 线程锁:解决多线程抢夺公共资源
def __init__(self):
time.sleep(10)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, '_instance'): # 解决休眠时间过长此时已是单例模式上锁问题
with Singleton._instance_lock:
if not hasattr(Singleton, '_instance'):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def main():
# 注意实例化对象
obj = Singleton.instance() # 得到的是单例
print(obj, 3)
for i in range(10):
trd = threading.Thread(target=main)
trd.start()
7.4 方法四:使用类中的__new__方法
class Singleton():
_instance_lock = threading.Lock()
def __new__(cls):
if not hasattr(Singleton, '_instance'):
with Singleton._instance_lock:
if not hasattr(Singleton, '_instance'):
Singleton._instance = object.__new__(cls)
# Singleton._instance = super().__new__(cls)
return Singleton._instance
def __init__(self):
pass
def main():
# 注意实例化对象
obj = Singleton() # 得到的是单例
print(obj, 4)
for i in range(10):
trd = threading.Thread(target=main)
trd.start()
8 闭包、装饰器
9 抽象基类abc.ABCMeta
抽象基类不能实例化,继承抽象基类的类必须实现抽象基类中定义的方法。(python中借助ABCMeta实现抽象基类,定义抽象方法必须被@abstractmethod装饰)
若继承类未定义抽象类方法将报错:TypeError: Can’t instantiate abstract class Test with abstract methods prams, run。
若需要执行抽象类方法,使用super().method_name(),继承类中方法参数可以和抽象类方法不一致。
from abc import ABCMeta, abstractmethod
class TestAbstractClass(metaclass=ABCMeta):
@abstractmethod
def run(self):
print("TestAbstractClass ..........")
pass
@abstractmethod
def prams(self, name):
print("TestAbstractClass ..........{}".format(name))
pass
class Test(TestAbstractClass):
def run(self):
print("Test ..........")
def prams(self):
super().prams(“test 88888”)
print("Test ..........")
test = Test()
test.prams()
10 上下文管理器(__enter__
和__exit__
)
11 反射(setattr、getattr、hasattr、delattr)
12 python对象内存垃圾回收机制
主要以引用计数为主,标记清除和分代回收为辅
引用计数: 创建和引用时引用计数加1,删除引用对象引用计数-1,一个对象引用计数为0时会被删除(产生循环引用问题)
标记清除:(解决循环引用问题)依据对象间的引用指针形成的有向图,以根对象(全局变量、调用栈、寄存器等)为根节点进行遍历,将图中可达对象标记为“可达”,未被标记的对象即为需要清除的对象。
分代回收:(针对引用计数和标记清除时扫描全部对象耗时长影响程序执行的问题,对象存在时间越长,越可能不是垃圾,应该越少去收集,以空间换时间。)将对象分类为3代,刚创建对象为0代,依次后面1代、2代。python针对某代被分配的对象与被释放的对象之差是否达到设置的阈值就会触发某代对象垃圾回收。
import gc
# 执行垃圾回收
gc.collect()
# python中获取分代回收阈值,默认为(700, 10,10)(表示被分配的对象与被释放的对象之差大于700时触动0代对象回收;当进行10次0代对象回收后触发1代对象回收;当进行10次1代对象回收后触发2代对象回收)
gc.get_threshold() # (threshold0, threshold1, threshold2)
# 自定义分代回收阈值
gc.set_threshold(threshold0[, threshold1[, threshold2]])