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

    1. 面向对象常用术语

    • Python是一门面向对象编程语言。
    • 面向对象编程是一种程序设计思想,把对象作为程序的基本单元,一个对象包含数据和操作数据的函数。
    • 在Python中,所有数据类型都被视为对象,也可以自定义对象。自定义对象数据类型就是面向对象中的类(Class)的概念。
    • 类:用来描述具有相同属性和方法的对象的集合。类定义了集合中每个对象共有的属性和方法。
    • 对象:对象是类的实例。
    • 类变量(属性):类变量在整个实例化的对象中是公用的。类变量定义在类中,且在方法之外。类变量通常不作为实例变量使用。类变量也称作属性。
    • 实例变量:定义在方法中的变量只作用于当前实例的类。
    • 数据成员:类变量或实例变量用于处理类及其实例对象的相关数据。
    • 方法重写:如果从父类继承的方法不能满足子类的需求,就可以对其进行改写,这个过程称为方法的覆盖(Override),也称为方法的重写。
    • 实例化(Instance):创建一个类的实例、类的具体对象。
    • 方法:类中定义的函数。
    • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
    • 面向对象的三大特性:
      • 多态(Polymorphism):对不同类的对象使用同样的操作。
      • 封装(Encapsulation):对外部世界隐藏对象的工作细节。
      • 继承(Inheritance): 即一个派生类(derivedclass)继承基类(base class)的字段和方法。

    2. 类

    2.1 类的定义和对象实例化

    类用关键字 class 进行定义,定义一个类,通常要定义属性和方法。类在定义后,一般通过类实例化对象,然后通过对象访问类的属性和方法。

    class Dog(): # 定义了一个Dog类
        name = "小花"           # 类的属性
        def cry(self):    # 类中定义的方法
            return "汪汪汪"
            
    dog = Dog()     # 实例化对象
    # 通过对象调用类的属性和方法。
    print(f"我的小狗名字为:{dog.name},它喜欢{dog.cry()}的叫")  
    
    我的小狗名字为:小花,它喜欢汪汪汪的叫
    

    2.2 类的构造方法

    在Python中,_init_()方法是一个特殊方法,在对象实例化时会被调用。_init_()的意思是初始化,是initialization的简写。这个方法也叫构造方法。在定义类时,若不显式地定义一个_init_()方法,则程序默认调用一个无参的_init_()方法。

    class Dog():  
        name = "小花"
        def __int__(self): # 不显示定义,默认调用该构造方法   
            pass 
    dog = Dog()
    dog.name
    
    '小花'
    
    class Dog():  
        def __init__(self,name):         
            self.name = name
            print(f"构造方法带一个参数:{self.name}")
    dog = Dog("小花")   
    
    构造方法带一个参数:小花
    
    class Dog():
        def __init__(self,name,age):      
            self.name = name
            self.age = age
            print(f"构造方法带两个参数:{self.name}-{self.age}")  
    dog = Dog("小花","2岁")
    
    
    构造方法带两个参数:小花-2岁
    

    2.3 类的访问权限

    类的访问权限在类内部有属性和方法,外部代码可以通过直接调用实例变量的方法操作数据,这样就隐藏了内部的复杂逻辑。

    class Dog():
        def __init__(self,name,age):      
            self.name = name
            self.age = age
        def show_info(self):
            print(f"姓名:{self.name}	 年龄:{self.age}")  
    dog = Dog("小花","2岁")
    print(f"修改前的年龄:{dog.age}")
    dog.show_info()
    dog.age = "5岁"
    dog.show_info()
    
    修改前的年龄:2岁
    姓名:小花	 年龄:2岁
    姓名:小花	 年龄:5岁
    

    在类中定义的非构造方法可以调用类中构造方法实例变量的属性,调用的方式为self.实例变量属性名。可以在类的外部修改类的内部属性。如果要让内部属性不被外部访问,可以在属性名称前加两个下画线__,使实例变量变为就会变成私有变量(private),如果外部代码要获取类中的name和score,可以为类增加get_attrs和set_attrs方法,获取和修改类中的私有变量。

    class Dog():
        def __init__(self,name,age):      
            self.__name = name
            self.__age = age
        def set_name(self,name):
            self.__name = name
        def set_age(self,age):
            self.__age = age
        def get_name(self):
            return self.__name
        def get_age(self):
            return self.__age
        def show_info(self):
            print(f"姓名:{self.get_name()}	 年龄:{self.get_age()}")  
    dog = Dog("小花","2岁")
    dog.show_info()
    dog.set_age("5岁")  
    dog.show_info()
    
    姓名:小花	 年龄:2岁
    姓名:小花	 年龄:5岁
    

    3. 继承

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NhRlKnFf-1584881814392)(attachment:image.png)]

      继承可以理解成类之间类型和子类型的关系。当我们定义一个class时,可以从某个现有的class继承,定义的新class称为子类(Subclass),而被继承的class称为基类、父类或超类(Baseclass、Superclass)。如上图:Animal和Plant类都继承object类,Dog和Cat类继承Animal类,Tree和Flower类继承Plant类。
    在Python中,继承有以下特点:

    • 在继承中,基类的构造方法(_init_()方法)不会被自动调用,需要在子类的构造方法中专门调用。
    • 在调用基类的方法时需要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通函数时不需要带self参数。
    • 在Python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找。
      注意: 继承语法class子类名(基类名)时,//基类名写在括号里,基本类是在定义类时,在元组中指明的。
    class Animal(object):
        def cry(self):       
            print("动物在叫。")
            
    class Dog(Animal):
        pass
    class Cat(Animal):
        pass
    
    dog = Dog()
    dog.cry()    # 子类直接继承父类的公有方法,如果cry()方法为__cry()私有方法,则不能继承。
    
    cat = Cat()
    cat.cry()
    
    动物在叫。
    动物在叫。
    
    class Animal(object):
        def __cry(self):       
            print("动物在叫。")
            
    class Dog(Animal):
        pass
    class Cat(Animal):
        pass
    
    dog = Dog()
    dog.__cry()    #如果cry()方法为__cry()私有方法,则不能继承。
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-20-71a8dd49d0b3> in <module>()
          9 
         10 dog = Dog()
    ---> 11 dog.__cry()    #如果cry()方法为__cry()私有方法,则不能继承。
    
    
    AttributeError: 'Dog' object has no attribute '__cry'
    

    4.多态

    继承可以帮助我们重复使用代码。但对于上面继承中的示例,无论是Dog还是Cat,调用父类的cry()方法时显示的都是“动物在叫。”,如果想让结果显示为“汪汪汪”和“喵喵喵”则需要对从父类继承的方法进行重写。

    class Animal(object):
        def cry(self):       
            print("动物在叫。")
            
    class Dog(Animal):
        def cry(self):       # 子类对父类的方法进行重写
            print("汪汪汪。")
        def eat(self):       #子类新增的方法
            print("小狗只吃狗粮。")
                
    class Cat(Animal): 
        def cry(self):      # 子类对父类的方法进行重写
            print("喵喵喵。")
        def eat(self):
             print("小猫只吃猫粮。")
    
    animal = Animal()
    animal.cry()
                
    dog = Dog()
    dog.cry()
    dog.eat()
    
    cat = Cat()
    cat.cry()
    cat.eat()
    
    动物在叫。
    汪汪汪。
    小狗只吃狗粮。
    喵喵喵。
    小猫只吃猫粮。
    
    # 为了理解多态,请观察下面的结果。
    print(f"dog 的类型为Dog吗:{isinstance(dog,Dog)}")
    print(f"dog 的类型为Animal吗:{isinstance(dog,Animal)}")
    
    dog 的类型为Dog吗:True
    dog 的类型为Animal吗:True
    

    因为Dog是从Animal继承下来的,当我们创建Dog的实例dog时,我们认为dog的数据类型是Dog,但dog同时也是Animal,Dog本来就是Animal的一种。实际上,任何依赖Animal作为参数的函数或方法都可以不加修改地正常运行,原因就在于多态。如下面的例子,在定义cry_twice()方法中,传入的参数为animal类型,想要具体到子类,不需要在改为dog或者cat,只需要传入相应类型的子类对象即可。

    def  cry_twice(animal):
        animal.cry()
        animal.cry()
    
    cry_twice(Animal())
    cry_twice(Dog())
    cry_twice(Cat())
    
    动物在叫。
    动物在叫。
    汪汪汪。
    汪汪汪。
    喵喵喵。
    喵喵喵。
    

    5. 封装

    封装并不等同于多态。多态可以让用户对不知道类(或对象类型)的对象进行方法调用,而封装可以不用关心对象是如何构建的,直接使用即可。

    class Dog():
        def __init__(self,name,age):      
            self.__name = name
            self.__age = age
        def set_name(self,name):
            self.__name = name
        def set_age(self,age):
            self.__age = age
        def get_name(self):
            return self.__name
        def get_age(self):
            return self.__age
        def show_info(self):
            print(f"姓名:{self.get_name()}	 年龄:{self.get_age()}")  
    dog = Dog("小花","2岁")
    dog.show_info()
    dog.set_age("5岁")  
    dog.show_info()
    
    姓名:小花	 年龄:2岁
    姓名:小花	 年龄:5岁
    

      每个实例都拥有各自的name和age数据。我们可以通过函数访问这些数据就没有必要从外面的函数访问,可以直接在Dog类内部定义访问数据的函数,这样就把“数据”封装起来了。这些封装数据的函数和Dog类本身是相关联的,我们称之为类的方法。这样一来,我们从外部看Dog类,只需要知道创建实例需要给出的name和age,如何输出是在Dog类的内部定义的,这些数据和逻辑被“封装”起来了,调用很容易,不用知道内部实现的细节。

    6. 多重继承

    多重继承: 一个子类就可以继承多个父类,同时获得多个父类的所有非私有功能。

    class People():
        def run(self):
            print("每天都要走路。")
            
    class Student():
        def study(self):
            print("每天都要学习。")
            
    class Senior(People,Student):
        pass
    
    senoir = Senior()
    senoir.run()
    senoir.study()
    
    每天都要走路。
    每天都要学习。
    

    7. 获取对象信息

    7.1 type()函数

    type(123)
    
    int
    
    type(dog)
    
    __main__.Dog
    
    type(senoir)
    
    __main__.Senior
    

    7.2 isinstance()函数

    isinstance(dog,Dog)
    
    True
    
    isinstance(senoir,Senior)
    
    True
    
    isinstance(senoir,Student)
    
    True
    
    isinstance(senoir,People)
    
    True
    
    isinstance(senoir,object)
    
    True
    
    isinstance(cat,Dog)
    
    False
    

    7.3 dir()函数

    dir(dog)  ##获取对象所有的属性和方法
    
    ['__class__',
     '__delattr__',
     '__dict__',
     '__dir__',
     '__doc__',
     '__eq__',
     '__format__',
     '__ge__',
     '__getattribute__',
     '__gt__',
     '__hash__',
     '__init__',
     '__init_subclass__',
     '__le__',
     '__lt__',
     '__module__',
     '__ne__',
     '__new__',
     '__reduce__',
     '__reduce_ex__',
     '__repr__',
     '__setattr__',
     '__sizeof__',
     '__str__',
     '__subclasshook__',
     '__weakref__',
     'age',
     'name',
     'show_info']
    

    8. 类的专有方法

    8.1. _str_

    class Student(object):
        def __init__(self,name):
            self.name = name
            
    print(Student('小明'))
    
    <__main__.Student object at 0x000001844A42C390>
    
    class Student(object):
        def __init__(self,name):
            self.name = name
        def __str__(self):
            return f'学生名称:{self.name}'
    print(Student('小明'))
    
    学生名称:小明
    

    8.2._repr_

    class Student(object):
        def __init__(self,name):
            self.name = name
        def __str__(self):
            return f'学生名称:{self.name}'
    stu = Student('小明')
    stu
    
    <__main__.Student at 0x18448ae3ef0>
    
    class Student(object):
        def __init__(self,name):
            self.name = name
        def __str__(self):
            return f'学生名称:{self.name}'
        __repr__ = __str__
    stu = Student('小明')
    stu
    
    学生名称:小明
    

    8.3. _iter_

    如果想将一个类用于for …in循环,类似list或tuple一样,就必须实现一个_iter_()方法。该方法返回一个迭代对象,Python的for循环会不断调用该迭代对象的_next_()方法,获得循环的下一个值,直到遇到StopIteration错误时退出循环。

    class Fib(object):
        def __init__(self):
            self.a, self.b = 0, 1 # 初始化:a和b
        
        def __iter__(self):
            return self   # 实例本身就是迭代对象,故返回自己
        
        def __next__(self):
            self.a, self.b = self.b, self.a + self. b # 计算下一个月的值
            if self.a > 10000: #退出循环
                raise StopIteration();
            return self.a  # 返回下一个值
    
    for n in Fib():
        print(n)
    
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    89
    144
    233
    377
    610
    987
    1597
    2584
    4181
    6765
    

    8.4 _getitem_

    Fib()[5]
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-79-14290f619470> in <module>()
    ----> 1 Fib()[5]
    
    
    TypeError: 'Fib' object does not support indexing
    

    上面的实例,如果要取出第n个元素,直接Fib()[n],不可行。要像list一样按照下标取出元素,则需要实现__getitem__方法

    class Fib(object):
        def __getitem__(self,n):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a+b
            return a 
    
    fib = Fib()
    fib[5]
    
    8
    

    8.5 _getattr_

    Python还提供了一种机制,就是写一个_getattr_()方法,动态返回一个不存在的属性。
    注: 只有在没有找到属性的情况下才调用_getattr_,已有的属性(如name)不会在__getattr__中查找。此外,如果所有调用都会返回None(如stu.abc),就是定义的__getattr__默认返回None。

    class Student(object):
        def __init__(self):
            self.name = "小明"
        
        def __getattr__(self,attr):
            if attr == "score":
                return 90
            
    stu = Student()
    print(stu.name)
    print(stu.score)
    
    小明
    90
    

    8.6 _call_

    一般通通过对象名.方法名()调用实例,但是,任何类,如果定义了一个_call_()方法,就可以直接对实例进行调用,就合函数调用差不多。

    class Student(object):
        def __init__(self,name):
            self.name =name
        def __call__(self):
            print(f"学生姓名:{self.name}")
    stu = Student( "小明")
    stu()  # 直接使用实例进行调用
    
    学生姓名:小明
    

    怎么判断一个变量是对象还是函数呢? 通过callable()函数可以判断一个对象是否为“可调用”对象。

    callable(stu)
    
    True
    
    callable(Student("小明"))
    
    True
    
    callable(max)
    
    True
    
    callable(list)
    
    True
    
    callable([1,2,3,4])
    
    False
    
    callable("小明")
    
    False
  • 相关阅读:
    RedHat7安装NetCore环境并发布网站
    【WPF学习】第四十二章 透明
    细说枚举
    js获取ip地址,操作系统,浏览器版本等信息,可兼容
    js实现数据流(日志流,报警信息等)滚动展示,并分页(含实现demo)
    js实现点击copy,可兼容
    js实现htmlToWordDemo
    H5 web 存储之 Webstorage
    已发布的WEB项目,如何挂在服务器或者本机的IIS下
    Nuget打包没有注释显示
  • 原文地址:https://www.cnblogs.com/sinlearn/p/12665474.html
Copyright © 2011-2022 走看看