zoukankan      html  css  js  c++  java
  • Python面向对象编程-类的封装,继承、多态

    面向对象是一种程序设计思想,对象作为程序基本单元,包含了数据和操作数据的函数。

    面向对象的三大特点--数据封装、多态和继承。

    #类的创建,class关键字,类名大写,object表示从哪个类继承而来,如果没有继承的类,默认就是object,这是所有的类都会继承的类
    
    class Student(object):
        pass

    创建类的实例

    1 tom = Student()  #tom实例指向类Student

    还可以自由的为实例绑定属性

    tom.age = 18
    tom.sex = boy

    #访问实例属性
    >>>tom.age
    18
    >>>tom.sex
    'boy'

    类是一个模板,可以在创建类的同时将实例的属性绑定

    class Student(object):
        def __init__(self,name,age,sex):  #__init__方法可以将实例属性绑定,第一个参数永远是self,表示实例本身,这样,age、sex属性绑定后指向实例本身
         self.name=name        
    self.age
    =age self.sex=sex

    使用__init__方法后,再去创建实例时,属性就不允许为空,否则提示丢失需求参数

    tom = Student('tom',20,'boy')
    >>>tom.name
    tom
    >>>tom.age
    20
    >>>tom.sex
    'boy'

    >>>tom = Student()
    TypeError: __init__() missing 3 required positional arguments: 'name', 'age', and 'sex'

    实例的属性可以在外部随意访问,也可以再外部定义一个函数用来访问类实例全部的属性。

    #外部直接访问
    >>>print(tom.name)
    tom
    ......

    #外部函数访问
    def
    info(stu): print('%s %d %s ' %(stu.name,stu.age,stu.sex)) >>>tom = Student('tom',20,'boy')


    >>>info(tom)

    tom
    20 

    boy

     

    数据封装

    像上面在外部定义访问函数不是不可以的。但类本身具有这些属性,直接在类内部写出打印函数就行  这样就实现了数据的封装。

    完整的封装

    class Student(object):
        def __init__(self,name,age,sex):
                self.name=name
                self.age=age
                self.sex=sex
        def info(self):
                print('%s
    %d
    %s' %(self.name,self.age,self.sex))
    
    
    tom = Student('tom',20,'boy')
    
    >>>tom.info()
    tom
    20
    boy

    这样写出来,对象属性及操作方法对外隐藏了,调用很简单。

    同时封装的好处就是可以为类增加新的方法,比如内部定义一个函数来判定学生属于的班级。

    class Student(object):
        def __init__(self,name,stunum):
                self.name=name
                self.stunum=stunum
    
        def info(self):
                print('%s%s' %(self.name,self.stunum))
    
        def attclass(self):   #新增加的方法,根据学号判断所属班级
                if self.stunum > 0 and self.stunum <= 50:
                    print("class one")
                if self.stunum > 50 and self.stunum <=100:
                    print("class two")
                print("class three")

    >>>tom = Student('tom',56)
    >>>tom.info()
    tom
    56
    >>>tom.attclass()
    class two

     

     

    私有变量

    从上面的代码看,不仅在外部可以直接访问实例的属性,还可以随便的更改实例的属性,如何使属性变成私有属性,不能随便更改和访问?

    要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private)

    class Student(object):
        def __init__(self,name,num,age,sex):
            self.__name=name  #声明为私有变量,下同
            self.__num=num
            self.__age=age
            self.__sex=sex
    
        def print_std(self):
            print('name:%s
    stunum:%d
    age:%d
    sex:%s
    ' %(self.__name,self.__num,self.__age,self.__sex))
    
        def attclass(self):
            if self.__num >0 and self.__num <= 50:
                print('class one')
            elif self.__num >50 and self.__num <= 100:
                print('class two')
            else:
                print('class three')
    
    tom = Student('tom',65,20,'boy')
    
    tom.num=20  ###私有变量外部更改失效,失效不会有错误提示,编译器直接略过
    
    tom.print_std()
    
    tom.attclass()
    print(tom.__name)#访问时报错,AttributeError: 'Student' object has no attribute '__name'

    如果想要外部代码拿到属性怎么做?

    为类增加一个函数,函数直接返回实例属性

    class Student(object):
        pass
        
        def get_name(self):
                return self.__name
        def get...():
           return .....

    如何允许外部代码修改属性?

    为类增加一个函数,函数参数添加上要修改的属性,这样设置不仅可以避免参数的无效,还可以增加方法约束参数。

    class Student(object):
        pass
    
        def set_name(self,name):
                self.__name=name
        .....
    
    
    >>>tom = Student('tom'..)
    
    >>>tom.set_name('jerry')
    
    >>>print(tom.get_name())
    jerry

     所以,总结下来:

    当类的属性没有声明为私有变量时,类的方法(内部函数)可以修改和访问;外部实例和函数可以随便修改访问。

    当类的属性声明为私有变量时,类的方法可以修改和访问;外部实例和函数无法修改和访问。

    在Python中,当有__xxx__,以双下划线开头并以双下划线结束的变量名称时,是可以访问的,所以,不要和私有的变量命名方式混淆了。

    当类中定义有以单下划线开头的变量时,如_num这样的,是可以外部访问的,但是按照规范来说,最好是不要在外部访问。

     不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:tom._Student_name

    类的继承

    当已有定义好的父类时,再去定义一个类就可以从已定义好的继承,叫做子类。

    继承最大的好处就是父类的方法被子类全部继承

    class Food(object):
        def color(self):
            print('yello')
    
    
    class Banana(Food):
        pass

    >>>ban=Banana()#创建Banana实例
    >>>ban.color()
    yellow

    同时可以自己定义子类的其他方法

    class Banana(Food):
        def feture(self,fet):
                self.fet=fet
    
    >>>ban=Banana()
    
    >>>ban.feture('sweet')
    >>>ban.fet
    sweet

    当子类与父类方法相同时,父类方法被覆盖。

    class Food(object):
        def color(self):
            print('yellow')
    
    
    class Banana(Food):
        def color(self):
             print('good')
    
    >>>ban=Banana()
    >>>ban.color()
    good

    这样就得到了继承的另一个好处,多态。

    Python允许多重继承,

    class Person(class1,class2....):

      pass

    子类拥有所有父类的功能。

    多态

    当定义一个类时,就是定义了一种数据类型,使用isinstance()判断,实例ban即属于Banana类型,又属于Food类型,方向向上,反之不行。香蕉是食物,食物不一定是香蕉。

    class Person(object):
        def __init__(self,name,age):
            self.name=name
            self.age=age
        def say(self):
            print('i am %s' %self.name)
    
    class Student(Person):
        def __init__(self,name,age):
                self.name=name
                self.age=age
    
        def info(self):
                print('%s
    %d
    ' %(self.name,self.age))
    
    def info_pr(name):
        return name.say()
    
    >>>tom = Student('tom',20)
    
    >>>info_pr(tom)
    i am tom

    方法调用将作用在name的实际类型上,先查找Student自身的定义,找不随继承树向上查找,直到找到方法后停止。

    对于静态语言而言,想要传入Person类型,必须是Person或者Person的子类,不然无法使用say()方法

    对于动态语言,只要传入的对象有say()的方法。


    动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。

    Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个read()方法,返回其内容。但是,许多对象,只要有read()方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。

    实例属性和类的属性

    给实例绑定属性是通过实例变量或者self绑定,而给类绑定属性实在class中直接定义的。

    class Student(student):
        name='Student'
        pass
    
    
    
    #通过这种方式绑定类的属性,外部的实例是可以修改和访问的,如果实例属性和类的属性名称一致时,实例的优先级时大于类的属性的,外部访问先寻找实例属性,找不到再去寻找类的属性。
    >>>s = Student()
    >>>print(s.name)
    Student

    >>>print(Student.name)打印类的name属性
    Student

    >>>s.name='tom' 给实例的name属性绑定‘tom’
    >>>print(s.name)
    tom

    >>>print(Student.name)
    Student #类的属性依然存在
  • 相关阅读:
    Codeforces 834D The Bakery
    hdu 1394 Minimum Inversion Number
    Codeforces 837E Vasya's Function
    Codeforces 837D Round Subset
    Codeforces 825E Minimal Labels
    Codeforces 437D The Child and Zoo
    Codeforces 822D My pretty girl Noora
    Codeforces 799D Field expansion
    Codeforces 438D The Child and Sequence
    Codeforces Round #427 (Div. 2) Problem D Palindromic characteristics (Codeforces 835D)
  • 原文地址:https://www.cnblogs.com/mzc1997/p/7645989.html
Copyright © 2011-2022 走看看