zoukankan      html  css  js  c++  java
  • 面向对象编程-类

    面向对象编程OOP (object-oriented programming)是最有效的软件编写方法之一,面向对象是利用“类”和“对象”来创建各种模拟来实现对真实世界的描述,使用面向对象编程的原因一方面试因为它可以使程序的维护和扩展变得简单,
    并且可以大大提高程序开发效率,面向对象的程序可以让人更加理解代码的逻辑。面向对象的核心特性之一:Class 类
    一个类即是对一类拥有相同属性的对象的抽象,蓝图,原型。在类中定义了这些对象的都具备的属性,共同的方法。根据类来创建对象被称为实例化,这能够使用类的实例。
    类的成员分为三大类:字段,方法,属性

    一.创建和使用类

    创建Dog类,根据Dog类创建每个实例都将存储名字和年龄,赋予每条狗蹲下(sit)和打滚(roll)能力。

    class Dog(object):
        def __init__(self,name,age):  #传参数,叫构造函数也叫构造方法==初始化方法
            '''初始化属性name和age'''
            self.name = name
            self.age = age
        def sit(self):  #类的方法
            '''赋予小狗蹲下的能力'''
            print("[%s] is sitting now."%(self.name))
        def roll(self):
            '''赋予小狗打滚的能力'''
            print("[%s] rolling now!"%self.name)
    
    my_dog = Dog('XiaoHei',3) #实例化,my_dog相当于等于__init__(self,name,age)中的self,实例化后产生的对象叫实例
    your_dog = Dog("XiaoHuang",4)  #创建第二个实例
    my_dog.sit()  #调用类的方法
    my_dog.roll()
    your_dog.sit()
    print("My dog is called %s,it's %d years old"%(my_dog.name,my_dog.age))  #访问my_dog的属性name的值:my_dpg.name
    #执行结果:
    [XiaoHei] is sitting now.
    [XiaoHei] rolling now!
    [XiaoHuang] is sitting now.
    My dog is called XiaoHei,it's 3 years old
    1.方法__init__()
    类中的函数称为方法,__init__()是一个特殊的方法(叫做初始化方法或构造方法),每当根据Dog类创建新实例时,在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突.
    我们将方法__init__()定义成了包含三个形参:self,name和age,在这个方法的定义中,形参self必不可少,还必须位于其他形参的前面。为何必须在方法定义中包含形参self呢?因为Python调用这 __init__()方法来创建 Dog 实例时,
    将自动传入实参self。每个与类相关联的方法调用都自动传递实参 self ,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。我们创建 Dog 实例时,Python 将调用Dog类的方法 __init__() 。我们将通过实参向 Dog() 传递名字和年龄;self 会自动传递,
    因此我们不需要传递它。每当我们根据 Dog 类创建实例时,都只需给最后两个形参name和age提供值。
    2.self.name和self.age类似,像这样可通过实例访问的变量称为属性
    3.Dog 类还定义了另外两个方法: sit和roll由于这些方法不需要额外的信息,如名字或年龄,因此它们只有一个形参 self 。后面将创建的实例能够访问这些方法。
    4.我们创建了两条小狗,它们分别名为xiaohei和xiaohuang。每条小狗都是一个独立的实例,有自己的一组属性,能够执行相同的操作。

     二.给属性指定默认值或修改属性值

    类中的每个属性都必须有初始值,哪怕这个值是 0 或空字符串。在有些情况下,如设置默认值时,在方法 __init__() 内指定这种初始值是可行的;如果你对某个属性这样做了,就无需包含为它提供初始值的形参。

    '''编写表示汽车的类'''
    class Car(object):
        def __init__(self,name,model,year):
            '''初始化描述汽车的属性'''
            self.name = name
            self.model = model
            self.year = year
            self.odometer = 0  #给属性指定默认值
        def describe_car(self):
            '''返回汽车的信息'''
            print("%s %s %d"%(self.name,self.model,self.year))
        def odometer_read(self):
            '''打印汽车里程信息'''
            print("this car has " + str(self.odometer) + " miles on it")
    my_car = Car("Audi","a4",2016)
    my_car.describe_car()
    my_car.odometer_read()
    my_car.odometer = 100 #直接修改属性的值
    my_car.odometer_read()
    #执行结果:
    Audi a4 2016
    this car has 0 miles on it
    this car has 100 miles on it

     三.类的继承

    编写类时,并非总是要从空白开始。如果你要编写的类是另一个现成类的特殊版本,可使用 继承 。一个类 继承 另一个类时,它将自动获得另一个类的所有属性和方法;原有的
    类称为 父类 ,而新类称为 子类 。子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。

    class Person(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
            self.sex = "normal"
        def talk(self):
            print("person is talking...")
    class BlackPerson(Person):
        def __init__(self,name,age,strength):#先继承再重构
            super(BlackPerson,self).__init__(name,age)
            self.strength = strength
            print(self.name,self.age,self.sex)
        def talk(self):
            print("blackperson is talking")
        def walk(self):   #如果与父类方法重复,用自己的
            print("person is walking")
    b = BlackPerson("zww",10,"streng")
    b.talk()
    b.walk()
    #执行结果:
    zww 10 normal
    blackperson is talking
    person is walking

    对于BlackPerson来说,Person是它的父类,对于Person来说,BlackPerson是它的子类

    super()是一个特殊的函数,帮助python将父类和子类关联起来,这里代码让python调用Person的父类的方法__init__(),让BlackPerson实例包含父类的所有属性和方法,父类也叫超类(supercass),名称super因此得名。

    函数 super() 需要两个实参:子类名和对象 self 。为帮助 Python 将父类和子类关联起来,这些实参必不可少。另外,在 Python 2.7 中使用继承时,务必在定义父类时在括号内指定 object 。

     四.封装

    定义:顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

    在使用面向对象的封装特征时,需要:

       ·将内容封装到某处

       ·从某处调用被封装的内容

    #coding:utf-8
    #Author:zhiwenwei
    class Student(object):
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    obj1 = Student('XiaoMing',18)  #将XiaoMing和18分别封装到name和age属性中
    obj2 = Student('zww',24)       #将zww和24分别封装到name和age属性中
    print(obj1.name,obj1.age)      #直接调用封装的内容:对象.属性名

     五.静态方法

    通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

    #coding:utf-8
    #Author:zhiwenwei
    class Dog(object):
        def __init__(self,name):
            self.name = name
        @staticmethod  #把eat变为静态方法
        def eat(self):
            print("%s is eating"%self.name)
    d = Dog("XiaoHei")
    d.eat()

    上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。

    D:软件pythonpython.exe C:/python/day7/静态方法-staticmethod.py
    Traceback (most recent call last):
      File "C:/python/day7/静态方法-staticmethod.py", line 11, in <module>
        d.eat()
    TypeError: eat() missing 1 required positional argument: 'self'
    
    Process finished with exit code 1

    想让上面的代码可以正常工作有两种办法

    1. 调用时主动传递实例本身给eat方法,即d.eat(d) 

    2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了

    class Dog(object):
        def __init__(self,name):
            self.name = name
        @staticmethod  #把eat变为静态方法
        def eat():
            print(" is eating")
    d = Dog("XiaoHei")
    d.eat()

     六.类方法

    类方法通过@classmethod装饰器实现,类方法和普通方法区别是,类方法只能访问类变量,不能访问实例变量

    #coding:utf-8
    #Author:zhiwenwei
    class Dog(object):
        def __init__(self,name):
            self.name = name
        @classmethod
        def eat(self):
            print("%s is eating" % self.name)
    d = Dog("XiaoHei")
    d.eat()

    执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法不能访问实例变量

    D:软件pythonpython.exe C:/python/day7/类方法-classmethod.py
    Traceback (most recent call last):
      File "C:/python/day7/类方法-classmethod.py", line 11, in <module>
        d.eat()
      File "C:/python/day7/类方法-classmethod.py", line 9, in eat
        print("%s is eating" % self.name)
    AttributeError: type object 'Dog' has no attribute 'name'

    此时可以定义一个类变量也叫name,看下执行结果

    class Dog(object):
        name = "我是类变量"
        def __init__(self,name):
            self.name = name
        @classmethod
        def eat(self):
            print("%s is eating" % self.name)
    d = Dog("XiaoHei")
    d.eat()
    #执行结果
    我是类变量 is eating

     七.属性方法

    属性方法通过@property把一个方法变成一个静态属性

    #coding:utf-8
    #Author:zhiwenwei
    class Dog(object):
        def __init__(self,name):
            self.name = name
        @property
        def eat(self):
            print("%s is eating" %self.name)
    d = Dog("xiaohei")
    d.eat()

    执行会报错说TypeError: 'NoneType' object is not callable,因为eat已经变成一个静态属性了,不是方法,想调用不需要加(),直接d.eat即可

    class Dog(object):
        def __init__(self,name):
            self.name = name
        @property
        def eat(self):
            print("%s is eating" %self.name)
    d = Dog("xiaohei")
    d.eat
    #执行结果
    xiaohei is eating

     八.类的特殊成员方法

    __doc__表示类的描述信息,一般是三重号内的注释信息
    __module__表示当前操作的对象在哪个模块
    __class__表示当前操作的对象的类是什么
    __init__构造方法,通过类创建对象时,自动触发执行
    __del__析构方法,当对象在内存中释放时,自动触发执行
    __dict__ 类的字典属性、名称空间
    __base__ 类的第一个父类
    实例:
    class Student:
        '''在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间'''
        count = 0
        def __init__(self,name,age):
            self.name = name
            self.age = age
            Student.count +=1
    class Teacher(Student):
        def __init__(self,name,age,lesson):
            super(Teacher,self).__init__(name,age)
            self.lesson = lesson
            # print("My name is %s.I am %s years old I am your %s teacher"%(self.name,self.age,self.lesson))
        def t_info(self):
            print("My name is %s.I am %s years old I am your %s teacher" % (self.name, self.age, self.lesson))
    
    student1 = Student("Kevin",24)
    student2 = Student("Jay",28)
    teacher1 = Teacher("alex",24,"English")
    teacher1.t_info()
    print("__doc__:",Student.__doc__)
    print("__module__:",student1.__module__)
    print("__class__:",student2.__class__)
    print("__dict__:",student2.__dict__)
    print("__bash__:",Teacher.__base__)

    执行结果:

    My name is alex.I am 24 years old I am your English teacher
    __doc__: 在类内部定义的属性属于类本身的,由操作系统只分配一块内存空间,大家公用这一块内存空间
    __module__: __main__
    __class__: <class '__main__.Student'>
    __dict__: {'age': 28, 'name': 'Jay'}
    __bash__: <class '__main__.Student'>
    
    
    
  • 相关阅读:
    剑指Offer-二叉搜索树与双向链表
    剑指Offer-数组中只出现一次的数字
    剑指Offer-栈的压入、弹出序列
    剑指Offer-反转链表
    剑指Offer-和为S的两个数字
    剑指Offer-数字在排序数组中出现的次数
    剑指Offer-二叉树的下一个结点
    Notepad++中实现Markdown语法高亮与实时预览
    centos7安装activemq5.15
    博客园展示音频视频
  • 原文地址:https://www.cnblogs.com/wenwei-blog/p/7614277.html
Copyright © 2011-2022 走看看