学习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. 封装

原文地址:https://www.cnblogs.com/lypy/p/6370444.html