1,面向对象编程思想
类:一类具有相同属性的抽象
属性(静态属性):实例变量、类变量、私有属性
方法(动态属性):构造函数、析构函数(默认就有)、函数、私有函数
对象/实例:类经过实例化后,就是对象/实例
封装 encapsulation:隐藏对象的属性和实现细节,仅对外公开接口
继承 inheritance:类派生子类
多态 polymorphism:一个接口,多种实现
举例:
class Foo: # 类 typecode = 'd' # 类变量 def __init__(self, x, y): # 构造函数 self.x = x # 属性,实例变量 self._y = y # 私有属性,实例变量 def _test(self): # 私有方法 return self.x def __del__(self): # 析构函数 pass f = Foo(1, 2) # 类的实例化 print(f) # 打印类的实例f
2,继承
代码重用
基类不应该被单独实例化
2.1,继承的方法
class Human: pass class Male(Human): pass
2.2,子类和父类重名的方法
直接写会覆盖,想保留父类方法可以先执行父类方法再增加子类方法。
class Human: def sleep(self): print('sleep 1s') class Male(Human): def sleep(self): super().sleep() # 执行父类方法一 Human.sleep(self) # 执行父类方法二 print('sleep 2s')
2.3,子类的构造函数
需要先覆盖父类的构造函数,再继承父类的属性,再增加自己的属性,父类:
class Human: def __init__(self, name): self.name = name
子类构造函数方法一,多重继承时按指定父类继承:
class Male(Human): def __init__(self, name, age): Human.__init__(self, name) self.age = age
子类构造函数方法二,多重继承时按顺序继承:
class Male(Human): def __init__(self, name, age): super().__init__(name) self.age = age
2.3,多重继承
classA
classB(A)
classC(A)
classD(B, C)
ABCD含有相同方法时:
广度优先:先BC再A
深度优先:先BA再C
python3是广度优先
3,多态
3.1,实现多态
在父类中的一个方法,输入不同子类的对象时,可以实现不同的效果。
父类:
class Human: def __init__(self, name, age): self.name = name self.age = age
子类Male:
class Male(Human): def hobby(self): print('sports')
子类Female:
class Female(Human): def hobby(self): print('shopping')
不同子类,hobby输出不同,实现了多态:
m = Male('m', 20) f = Female('f', 20) m.hobby() # sports f.hobby() # shopping
还可以编写一个入口函数,统一输出不同对象的hobby:
def get_hobby(obj): obj.hobby() get_hobby(m) # sports get_hobby(f) # shopping
3.2,通过抽象基类强制要求子类必须实现方法
如果想要求子类在继承时必须实现hobby方法,可以对父类进行如下改造:
import abc class Human(abc.ABC): def __init__(self, name, age): self.name = name self.age = age @abc.abstractmethod def hobby(self): # 抽象方法无需实现,直接注释或pass即可 """必须实现hobby"""
4,内置三大类装饰器
4.1,@staticmethod
如果一个方法在类中定义,但没有用到类中的实例属性或者方法,建议加上staticmethod或者classmethod。
staticmethod:本质上就是放在类中的全局函数(可以通过类或实例调用),和类没关系,完全可以放在类的外面。
class Foo: def __init__(self, x): self.x = x @staticmethod def run(): print('hello world') f = Foo(1) f.run() # 输出hello world,通过类的实例调用 Foo.run() # 输出hello world,通过类调用
4.2,@classmethod
和staticmethod的区别是可以调用类的属性或方法。
被classmethod装饰的函数第一个参数是类的引用,相当于类的实例中执行type(self),或者self.__class__。
class Foo: hw = 'hello world' def __init__(self, x): self.x = x @classmethod def run(cls): print(cls.hw) f = Foo(1) f.run() # 输出hello world,通过类的实例调用 Foo.run() # 输出hello world,通过类调用
如果是实例想调用类的属性或方法,可以通过如下方法:
class Foo: hw = 'hello world' def __init__(self, x): self.x = x def run(self): print(type(self).hw) print(self.__class__.hw) f = Foo(1) f.run() # 输出hello world,通过类的实例调用 Foo.run(f) # 由于没有声明classmethod,无法通过Foo类直接调用run,想调用需把实例f传进去
4.3,@property
详见guxh的python笔记:类的属性