python 基础笔记十九 - 面向对象
1、类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。
2、对象:类的实例
3、类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。
4、数据成员:类变量或者实例变量,用于处理类及其实例对象的相关数据。
5、实例变量:定义在方法中的变量,只能作用域当前实例的类。
6、实例化:创建一个类的实例,类的具体对象。
7、方法:类中定义的函数
8、对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
创建类:
使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾
class ClassName: '类的帮助信息' #类文档字符串 class_suite #类体
类的帮助信息可以通过ClassName.__doc__查看。
class_suite 由类成员,方法,数据属性组成。
类的构造方法:
创建对象的时候,会调用构造函数
1 class People: 2 def __init__(self): 3 print('这是构造函数') 4 5 people = People() #创建对象的时候,会调用构造函数,打印:这是构造函数
类的析构方法:
运行结束的时候,会自动调用类的析构函数
1 class People: 2 def __init__(self): 3 print('这是构造函数') 4 5 def __del__(self): 6 print('这是析构函数!') 7 8 people = People() #创建对象的时候,会调用构造函数,打印:这是构造函数 9 #运行结束的时候,会自动调用类的析构函数
Python垃圾回收机制:实际上是一个引用计数器和一个循环垃圾收集器。当对象创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说,这个对象的引用计数变为0时,它被垃圾回收。但是回收不是“立即”的,由解释器在适当的时机,将垃圾对象占用的内存空间回收。
类的属性方法:
属性变为私有属性,加断言
1 class People: 2 def __init__(self): 3 print('这是构造函数') 4 #普通的类方法 5 def print_Name(self,name): 6 print('这个人的名字是%s'%name) 7 8 @property #属性方法 9 def print_age(self): 10 print('这是一个属性方法') 11 12 def __del__(self): 13 print('这是析构函数!') 14 15 people = People() #创建对象的时候,会调用构造函数,打印:这是构造函数 16 people.print_Name('wuxuewen') 17 people.print_age #属性方法调用时,不能传入参数,只能是通过.方法名调用
self的含义:
self代表类的实例,而非类。类的方法与普通的函数只有一个特别的区别:他们必须有一个额外的第一个参数名称,按照惯例它的名称是self。
私有变量、私有方法:
用两个下划线‘__变量名’开头的变量,在类里可以调用,但是出了类就不可以被调用
1 class DB: 2 def __init__(self,host,user,password,db): 3 self.host = host 4 self.__user = user #私有变量 5 self.__password = password #私有变量 6 self.db = db 7 8 def sql(self,sql): 9 print('执行SQL') 10 self.__text() #在类里可以调用私有方法 11 12 def help(self): 13 print(self.host) 14 print(self.__user) 15 print(self.__password) 16 print(self.db) 17 18 def __text(self): 19 print('这是一个私有方法,出了类不能被调用') 20 21 db = DB('127.0.0.1','root','123456','wxw') 22 print(db.host) #类外可以直接调用实例变量,但是不可以调用私有变量 23 db.help() 24 db.__text() #会报错
类变量:
定义在类里,在方法之外的变量,
1 class DB: 2 port = 3306 3 def __init__(self,host,user,password,db): 4 self.host = host 5 self.__user = user #私有变量 6 self.__password = password #私有变量 7 self.db = db 8 9 def get_port(self): 10 print(self.port) 11 12 13 db = DB('127.0.0.1','root','123456','wxw') 14 db.get_port() #3306 15 db.port=3307 #这里只是给实例db新增了一个实例变量port,并没有修改类变量 16 db.get_port() #3307 17 18 DB.port = 3308 #通过类名.类变量,可以修改类变量,且所有实例共享 19 print(DB.port) #3308 20 oracle = DB('127.0.0.1','root','123456','wxw') 21 oracle.get_port() #3308 22 db.get_port() #3307,会优先取实例变量 23 my = DB('127.0.0.1','root','123456','wxw') 24 my.get_port() #3308
实例方法:
方法的参数加了self的函数,只能通过对象.方法名()来调用,不能通过类名.方法名()来调用
类方法:
类里面定义的公共方法,不需要实例化就可以调用,只需要类名.方法名()就可以实现,加断言:@classmethod
什么时候用类方法:这个方法里面没有用到实例变量或者没有调用实例方法的时候,只用到类变量,就可以给它定义成一个类方法。
1 class DB: 2 port = 3306 3 @classmethod 4 def help(cls): 5 print('这是一个类方法,不需要实例化就可以调用') 6 print('类变量的地址:%s' %id(cls)) 7 8 DB.help() #通过类名直接调用类方法,输出:5818952 9 print('类地址:%s'%id(DB)) #直接打印类的地址,输出:5818952 10 db = DB() #实例化对象 11 db.help() #通过对象调用类方法,打印的是类的地址,输出:5818952 12 print("db 的地址: %s"%id(db)) #打印的是对象的地址,输出:43827096
静态方法:
只是定义在类里面的一个普通的函数,加断言:@staticmethod
什么时候用静态方法:如果这个函数没有用到类变量、类方法、实例变量、实例方法,那么就可以把它定义成静态方法,类方法、实例方法可以随便调用静态方法。但是静态方法不能调用其他的方法。
1 class Pig: 2 words = 'aaaaaa' 3 @classmethod 4 def print_words(cls): 5 cls.words = 'wwwwwwww' #会修改类变量的值 6 print('这是一个类方法,words= %s'%cls.words) 7 # cls.print_word() #不能调用实例方法,会报错 8 9 @staticmethod 10 def print_static(): 11 print('这是一个静态方法,不能调用任何变量、方法') 12 13 def print_word(self): 14 Pig.words = '自定义方法' 15 print(Pig.words) 16 17 print(Pig.words) #aaaaaa 18 Pig.print_words() #wwwwwwww 19 Pig.print_static() #这是一个静态方法,不能调用任何变量 20 print(Pig.words) #wwwwwwww
类的继承 :
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
继承语法:
1 class 派生类名(基类名) 2 ...
在python中继承中的一些特点:
- 1、如果在子类中需要父类的构造方法就需要显示的调用父类的构造方法,或者不重写父类的构造方法。
- 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
- 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
1 class Parent: 2 parentAttr = 100 3 def __init__(self): 4 print('调用父类的构造函数!') 5 6 def parentMethod(self): 7 print('调用父类方法') 8 9 def setAttr(self,attr): 10 Parent.parentAttr = attr 11 12 def getAttr(self): 13 print('父类属性 : ',Parent.parentAttr) 14 15 class Child(Parent): 16 def __init__(self): 17 print('调用子类构造方法!') 18 19 def childMethod(self): 20 print('调用子类方法') 21 22 def childGetParent(self): 23 print('子类调用父类的方法') 24 self.getAttr() #在子类中调用父类的方法,用self 25 26 c = Child() #实例化子类 27 c.childMethod() #调用子类的方法 28 c.parentMethod() #调用父类的方法 29 c.setAttr(200) #调用父类的方法设置类变量 30 c.getAttr() #调用父类的方法 31 c.childGetParent() #调用子类的方法,子类方法中调用父类的方法
继承多个类的语法:
class A: # 定义类 A ..... class B: # 定义类 B ..... class C(A, B): # 继承类 A 和 B
你可以使用issubclass()或者isinstance()方法来检测。
- issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
- isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。
方法重写:
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法
1 class Parent: 2 parentAttr = 100 3 def __init__(self): 4 print('调用父类的构造函数!') 5 6 def setAttr(self,attr): 7 Parent.parentAttr = attr 8 9 def getAttr(self): 10 print('父类属性 : ',Parent.parentAttr) 11 12 class Child(Parent): 13 def __init__(self): 14 print('调用子类构造方法!') 15 16 def setAttr(self,attr): 17 self.parentAttr = attr #给实例对象新增parentAttr 的属性 18 print('子类重写父类的方法,self.parentAttr = %s'%self.parentAttr) 19 20 c = Child() #实例化子类 21 c.setAttr(200) #调用子类的方法设置类变量,输出:200 22 c.getAttr() #调用父类的方法,输出: 100
使用super()方法调用父类方法
1 class Parent: 2 parentAttr = 100 3 def __init__(self): 4 print('调用父类的构造函数!') 5 6 def setAttr(self,attr): 7 Parent.parentAttr = attr 8 9 def getAttr(self): 10 print('父类属性 : ',Parent.parentAttr) 11 12 class Child(Parent): 13 def __init__(self): 14 print('调用子类构造方法!') 15 16 def setAttr(self,attr): 17 super().setAttr(attr) #super()调用父类的方法 18 print('子类重写父类的方法,self.parentAttr = %s'%self.parentAttr)
21 c = Child() #实例化子类 22 c.childMethod() #调用子类的方法 23 c.parentMethod() #调用父类的方法 24 c.setAttr(200) #调用子类的方法设置类变量,输出:200 25 c.getAttr() #调用父类的方法,输出: 200