首页 > 代码库 > 学习4: 面向对象
学习4: 面向对象
1. 类的定义和实例化
class dog(): def __init__(self,name,age,s,color): self.name = name self.age = age self.single = s self.color = color def walk(self): self.a = ‘aaa‘ self.b = 100 print ‘running dog‘ def eat(self,food): print ‘eat..‘,food def talk(self): print ‘w w w‘ w = dog(‘heizi‘,1,True,‘black‘) l = dog(‘nana‘,3,True,‘yellow‘) l.money = ‘bumai!‘ print l.money print w.name
总结:
1) class后面紧接着是类名,类的类型分为经典类和新式类。经典类后面括号不继承任何东西。新式类括号里面面一般最好添加(object),表示该类是从哪个类继承下来的。通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
2) 由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,age等属性绑上去
3) 注意到__init__为初始化方法,第一个参数永远是self,表示创建的实例本身
4) 变量w就是指向dog的类的实例变量,而dog本身就是一个类。()里面的都是给他捆绑的属性
5) 有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去。另外和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数和关键字参数。
6) 类的方法:在上面的dog类中,每个实例就拥有各自的name和age这些数据,因为dog的实例本身就有这些数据,要访问这些数据,就没有必要从外面的函数去访问,可以直接在dog类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和dog类本身是关联起来的,我们称之为类的方法。要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入。
2. 属性
class student(object): grade = ‘Four‘ #类的公有属性,可以被类和实例访问 __teacher = ‘David‘ #类的私有属性(以__为前缀),不可以被类和实例访问,只可用于类的方法中调用 def __init__(self,name,age): self.name = name #实例的公有属性,可以被实例访问 self.__age = age #实例的私有属性(以__为前缀),不可以被实例访问,只可用于类的方法中 def getGrade(self): print self.grade def getTeacher(self): print self.__teacher def getName(self): print self.name def getAge(self): print self.__age s = student(‘Lina‘,18) print ‘---测试1:类的公有属性可以被类和实例访问‘ print student.grade print s.grade print ‘---测试2:类的私有属性不可以被类和实例访问‘ #print student.__teacher #print s.__teacher print ‘---测试3: 实例的公有属性,可以被实例访问,但是不能被类访问‘ print s.name #print student.name print ‘---测试4, 实例的私有属性,不可以被实例访问‘ #print s.__age print ‘---测试5, 公有属性和私有属性都可以被类的方法中调用‘ s.getGrade() s.getTeacher() s.getName() s.getAge()
总结:
属性分为类的属性和实例属性。定义在类中方法之外的属性,称为类的属性,又分为类的公有属性和私有属性;
1) 类的公有属性,可以被类和实例访问;
2) 类的私有属性(以__为前缀),不可以被类和实例访问,只可用于类的方法中通过self.__private_attrs调用
3) 实例的公有属性,可以被实例访问
4) 实例的私有属性(以__为前缀),不可以被实例访问,只可用于类的方法中通过self.__private_attrs调用
5) 如果类的公有属性和实例公有属性同名,则两者互相不影响;
(类和实例的私有属性都是只能被类中定义的方法使用)
3. 方法
class student(object): grade = ‘Four‘ #类的公有属性,可以被类和实例访问 __teacher = ‘David‘ #类的私有属性(以__为前缀),不可以被类和实例访问,只可用于类的方法中调 def __init__(self,name,age): self.name = name #实例的公有属性,可以被实例访问 self.__age = age #实例的私有属性(以__为前缀),不可以被实例访问,只可用于类的方法中 def getGrade(self): print self.grade def getTeacher(self): print self.__teacher def getName(self): print self.name def __getAge(self): #私有方法(以__为前缀),不可以被实例访问 print self.__age def getAge(self): #公有方法,可以被实例访问 self.__getAge() s = student(‘Lina‘,18) print ‘---测试1:类的公有属性可以被类和实例访问‘ print student.grade print s.grade print ‘---测试2:类的私有属性不可以被类和实例访问‘ #print student.__teacher #print s.__teacher print ‘---测试3: 实例的公有属性,可以被实例访问,但是不能被类访问‘ print s.name #print student.name print ‘---测试4, 实例的私有属性,不可以被实例访问‘ #print s.__age print ‘---测试5, 公有属性和私有属性都可以被类的方法中调用‘ s.getGrade() s.getTeacher() s.getName() print ‘---测试6, 私有方法不可以被实例访问‘ #s.__getAge() s.getAge()
class Dav(student): grade = ‘one‘ __teacher = ‘Mrliu‘ def __init__(self,name,age): self.name = name self.__age = age @staticmethod def getStu(): #print self.grade #print self.__teacher #print self.name #print self.__age print ‘调用静态方法‘ @classmethod def getInfo(cls): print cls.grade print cls.__teacher #print self.name #print self.__age print ‘调用类方法‘ print ‘---测试10: 静态方法不能访问类和实例的属性,定义时候也不需要加self参数,可以被实例或者类调用且两者效果一致‘ d = Dav(‘david‘, 21) d.getStu() Dav.getStu() print ‘---测试11: 类方法可以访问类的属性,包含类的公有属性和私有属性,可以被实例或者类调用且两者效果一致‘ dd = Dav(‘tom‘, 23) dd.getInfo() Dav.getInfo()
总结:
方法包含实例方法,静态方法,类方法。
1) 私有方法以两个下划线开头,不可以被实例访问,只能在类的方法中通过self.__private_methods调用
2) 公有方法,可以被实例访问
3) 以上说的方法实际都是实例方法,其它还有静态方法,类方法。
4) 静态方法使用装饰器@staticmethod定义,并且方法参数中不能有self. 类对象和实例都可以调用静态方法,但是无法访问类属性、实例属性,相当于一个相对独立的方法,跟类其实没什么关系;
5) 类方法使用@classmethod装饰器定义,其第一个参数必须为cls,且不需要self参数。类对象和实例都可以调用类方法,可以访问类属性包含公有属性和私有属性,但是无法访问实例属性。
还有一种类中普通的方法(没有self参数),这种方法既可以被类直接调用也可以被类的实例对象调用,但是被实例对象调用的时候,要求方法至少有一个参数,因为调用时会将实例对象本身传给第一个参数。staticmethod函数功能就是将这种方法定义成类的静态方法,正确的方法是使用 @staticmethod装饰器,这样在实例对象调用的时候,不会把实例对象本身传入静态方法的第一个参数了。
4. 构造方法
class student(object): grade = ‘Four‘ #类的公有属性,可以被类和实例访问 __teacher = ‘David‘ #类的私有属性(以__为前缀),不可以被类和实例访问,只可用于类的方法中调用 def __init__(self,name,age): self.name = name #实例的公有属性,可以被实例访问 self.__age = age #实例的私有属性(以__为前缀),不可以被实例访问,只可用于类的方法中 print ‘父类构造函数‘ def getGrade(self): print self.grade def getTeacher(self): print self.__teacher def getName(self): print self.name def __getAge(self): #私有方法(以__为前缀),不可以被实例访问 print self.__age def getAge(self): #公有方法,可以被实例访问 self.__getAge() s = student(‘Lina‘,18) print ‘---测试1:类的公有属性可以被类和实例访问‘ print student.grade print s.grade print ‘---测试2:类的私有属性不可以被类和实例访问‘ #print student.__teacher #print s.__teacher print ‘---测试3: 实例的公有属性,可以被实例访问,但是不能被类访问‘ print s.name #print student.name print ‘---测试4, 实例的私有属性,不可以被实例访问‘ #print s.__age print ‘---测试5, 公有属性和私有属性都可以被类的方法中调用‘ s.getGrade() s.getTeacher() s.getName() print ‘---测试6, 私有方法不可以被实例访问‘ #s.__getAge() s.getAge()
class Liming(student): def getName(self): print self.name print ‘---测试7, 子类未定义构造函数,将默认使用父类构造函数‘ l = Liming(‘liming‘, 20) l.getName() class Liutao(student): def __init__(self,name,age,height): self.name = name self.age =age self.height = height print ‘子类自己的构造函数‘ def getName(self): print self.name print ‘--测试8,子类定义了构造函数,实例化将使用自己的构造函数‘ lt = Liutao(‘liutao‘, 35, 168) lt.getName() class litao2(student): def __init__(self,name,age,height): student.__init__(self,name,age) self.height =height print ‘子类自己的构造函数‘ def getName(self): print self.name print ‘---测试9,子类定义了构造函数,还可以继续调用父类构造函数‘ lt2 = litao2(‘litao2‘,20,180) lt2.getName()
总结:
1) 如果子类没有定义构造函数,将默认使用父类构造函数;
2) 如果一个子类从多个父类派生,而子类又没有自己的构造函数,则按顺序继承,
哪个父类在最前面且它又有自己的构造函数,就继承它的构造函数;如果最前面第一个父类没有构造函数,
则继承第2个的构造函数,第2个没有的话,再往后找,以此类推。
3) 如果子类有自己的构造函数,不会自动调用父类的构造函数,只会调用自己的构造函数
4) 如果需要用到父类的构造函数,则需要在子类的构造函数中显式的调用
5) 显式调用父类构造函数有两种方法:super以及 通过父类直接调用__init__函数;
5. 多态
class A(): def login(self): print ‘A‘ class B(A): def login(self): print ‘B‘ class C(A): def login(self): print ‘C‘ def test(a) a.login() test(B()) test(A()) test(C())
总结:
1) 如果父类方法的功能不能满足需求,可以在子类重写父类的方法。实例对象调用方法时会调用其对应子类的重写后的方法
6. 继承
class A: pass class B(A) pass
总结:
1) 定义:class 派生类名(基类名)
2) 特点:
I: 在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。使用super().__init__()或parentClassName.__init__()
II: 在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
III: 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
7. 封装
学习4: 面向对象