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

    面向对象编程

    类的定义形式多样

    • 既可以直接创建新的类,也可以基于一个或多个已有的类创建新的类;
    • 既可以创建一个空的类,然后再动态添加属性和方法,也可以在创建类的同时设置属性和方法。
    • 类是对现实世界中一些事物的封装,可以把数据(属性)和操作(方法)封装在一起,从而使得
      程序结构更加清晰。
    • 使用class保留字定义一个类:

    定义类

    定义一个类

    class Person:
        #定义一个属性
        name="小明"
        #定义一个方法
        def getName(self):
            return self.name
    
    

    定义一个空类

    class Person:
        pass
    

    创建对象

    p=Person()
    
    • 类定义好后进行实例化 p=Person( ),产生一个Person类的实例对象
    • 实例对象是根据类模版生成一个内存体,系统都会在内存中选择一块区域分配给对象,有确定的
      数据与内存地址,每次选择的内存通常是不一样的

    构造函数

    构造函数:初始化方法,命名为__init__,在对象创建后自动调用

    class Person:
        name="小明"
        def __init__(self):
            print(self,self.name)
    
    
    f=Person()
    

    默认参数

    class Person:
        def __init__(self,n="小红"):
            self.name=n
            print(self,self.name)
    
    >>>f=Person()
    >>>p=Person("小明")
    

    自定义参数

    class Complex:
        def __init__(self,realpart,imagpart):
            self.real=realpart
            self.imag=imagpart
    

    类属性和实例属性

    class Person:
        name="Max"# 类属性
        age=12#类属性
        def __init__(self,height):
            self.height=height#实例属性
    
    • 类属性可通过两种方式访问:
      • 使用类的名称,例如,Person.name, Person.age
      • 使用类的实例对象,例如p=Person( )是对象,通过p.name, p.age访问
      • 注意:类属性虽然归类所有,但实例化的对象都可以访问类属性
    • 实例属性通过实例对象可绑定属性,新建、改变属性

    改变类属性

    class Person:
        name='Max'
        age=10
    #类型读取类属性
    print(Person.name,Person.age)
    
    #类名称改变类属性
    Person.name="小明"
    Person.age=22
    
    print(Person.name,Person.age)
    
    

    改变实例属性

    通过对象实例改变类属性
    格式:对象实例.属性=…

    • 如果该对象实例存在这个属性,这个属性的值就被改变。
    • 如果该对象实例不存在这个属性,自动为该对象实例创建一个新的属性。
    class Person:
        name='Max'
        age=10
    
    #读取类属性
    print(Person.name,Person.age)
    
    p=Person()
    p.name='John'
    print(p.name,p.age)
    print(Person.name,Person.age)
    
    # 'Max' 10
    # 'John' 10
    # 'Max' 10
    

    相同名称的实例属性优先级高于类属性(覆盖)实例属性改变,不影响类属性

    删除实例属性

    删除实例属性后,访问该名称对应的属性时,将访问类属性

    class Person:
        name='Max'
        age=12
    
    p=Person()
    print(p.name)#Max
    p.name='John'
    print(p.name)#John
    print(Person.name)#Max
    del p.name
    print(p.name)#Max
    

    不同实例对象属性不同

    不同的实例对象,有不同的实例属性

    class Person:
        name='Max'
        age=12
    #用类名读取类属性
    print(Person.name,Person.age)
    
    # 用对象实例改变类属性
    p=Person()
    p.name='John'
    print(p.name,p.age)
    print(Person.name,Person.age)
    
    q=Person()
    q.age=21
    print(q.name,q.age)
    
    # Max 12
    # 'John' 12
    # Max 12
    # Max 21
    
    

    建立新的属性

    class Person:
        name='Max'
        age=22
    
    #对象实例改变类属性
    p=Person()
    p.gender='male'
    print(p.name,p.age,p.gender)
    
    

    Python作为一种动态语言,除了可以在定义类时指定类属性外,还可以动态地为已经创建的对象绑定新的属性

    可变对象作为类属性

    class Person:
        part_time=[]
        def __init__(self,name):
            self.name=name
        def add_part(self,sh):
            self.part_time.append(sh)
    
    p=Person('Max')
    q=Person('John')
    q.add_part('read')
    p.add_part('walk')
    
    print(p.part_time)
    print(q.part_time)
    #['read','walk']
    #['read','walk']
    # part_time被共享了
    
    

    使用实例属性替代类属性,以避免实例操作改变类属性变量的值

    class Person:
        def __init__(self,name):
            self.name=name
            self.part_time=[]
        def add_part(self,sh):
            self.part_time.append(sh)
    
    p=Person('Max')
    q=Person('John')
    q.add_part('read')
    p.add_part('walk')
    print(p.part_time)
    print(q.part_time)
    #['walk']
    #['read']
    #各是各的
    

    小结

    • 类属性是与类绑定的,它被这个类所拥有的,如果要修改类的属性,就必须使用类名称访问它,而不能使用对象实例访问它。
    • 对象实例的属性默认和类相同,通过赋值语句进行修改、创建后,不同的实例对象,有不同的属性。
    • 可变对象作为类属性时,需注意每个实例操作都
      可能改变其值。

    类方法

    实例方法

    通过实例对象调用的方法一般以‘self’的变量作为第一个参数(其他名称也可以),self表示对象自身的含义,某个实例对象调用该方法时,将该对象作为第一个参数传递给self

    class Person:
        name='Max'
        age=12
        def getName(self):
            return self.name
        def getAge(self):
            return self.age
    p=Person()
    print(p.getName(),p.getAge())
    #Max 12
    

    p.getName( )时,将p传递给self,执行return p.name得 到name,类似地,通过p.getAge( )得到age

    实例方法调用

    1. 一般使用实例对象调用,调用时向实例方法传递实例参数,例如p.getName( )
    2. 也可以用类名称Person调用,但要传递实例参数,例如Person.getName(p)
    class Person:
        name='Max'
        age=12
        def getName(self):
            return self.name
        def getAge(self):
            return self.age
    p=Person()
    print(p.getName(),p.getAge())
    print(Person.getName(p),Person.getAge(p))
    #Max 12
    #Max 12
    

    类方法

    定义

    在类中可以定义类的方法

    • 通过@classmethod 修饰
    • 第一个参数一般命名为cls (也可以是其他名称)
    class Person:
        name='Max'
        age=12
        @classmethod
        def show(cls):
            print(cls.name,cls.age)
    
    

    调用

    一般通过类名称调用,调用时传递类参数,例如Person.show( ), 将Person 传递给cls,因此
    print(cls.name,cls.age)等价于执行print(Person.name,Person.age)

    class Person:
        name='Max'
        age=12
        @classmethod
        def show(cls):
            print(cls.name,cls.age)
    
    Person.show()
    

    也可以通过实例对象调用,这时候对象p的类Person会传递给函数的参数cls

    class Person:
        name='Max'
        age=12
        @classmethod
        def show(cls):
            print(cls.name,cls.age)
    
    p=Person()
    p.show()
    

    静态方法

    通过@staticmethod修饰,无参数传递

    class Person:
        name='Max'
        age=12
        @staticmethod
        def display():
            print(Person.name,Person.age)
    
    

    通过类名称调用,不传递参数,与类方法调用不同(传递类参数)

    静态方法调用

    通过类名称调用,不传递参数,与类方法调用不同(传递类参数)

    class Person:
        name='Max'
        age=12
        @classmethod
        def show(cls):
            print(cls.name,cls.age)
        @staticmethod
        def display():
            print(Person.name,Person.age)
    >>>Person.show()
    >>>'Max' 12
    >>>Person.display()
    >>>'Max' 12
    

    通过实例对象调用,不传递参数

    class Person:
        name='Max'
        age=12
        
        @staticmethod
        def display():
            print(Person.name,Person.age)
    p=Person()
    p.display()
    #Max 12
    

    小结

    • 实例方法
      • self
      • 对象实例调用p.getName( ),类名称调用
      • (Person.getName(p)、传递对象实例参数
    • 类方法
      • @classmethod, cls
      • 类名称调用Person.show( )、对象实例调用 p.show( ),传递类参数
    • 静态方法
      • @staticmethod
      • 类名称调用Person.display ( )、对象实例调用p.display( ),不传递参数

    访问权限

    Person类中的name 和age属性是公有的,可以直接在类外访问

    class Person:
        name='Max'
        age=12
    
    

    私有变量

    如果想定义为私有的,在属性前面加两个下划线‘__’

    class Person:
        __name='Max'
        age=12
    
    

    私有属性不能直接在类外访问

    Person.name
    #报错
    

    私有属性,可以被类内定义的方法访问

    class Person:
        __name='Max'
        age=12
        def getName(self):
            return self.__name
    
    p=Person()
    p.show()
    

    私有方法

    可以在类内定义私有方法,在方法名称前加两个下划线‘__’

    class Person:
        __name='Max'
        age=12
        def __getName(self):
            return self.__name
    
    

    私有方法不能直接在类外调用

    class Person:
        __name='Max'
        age=12
        def __getName(self):
            return self.__name
    p=Person()
    name=p.getName()
    

    私有方法可被类内定义的其它方法调用

    class Person:
        __name='Max'
        age=12
        
        def __show(self):
            print(self.name)
        def display(self):
            self.__show()
    p=Person()
    p.display()
    
    

    小结

    • 在共有属性/方法前加两个下划线‘__’,即变成私有属性/方法
    • 公有属性/方法可以在类外直接访问/调用
    • 私有属性/方法不可以再类外直接访问/调用
    • 在类定义的内部,可以访问私有属性/方法

    继承

    继承的语法形式

    • DerivedClassName为子类,BaseClassName为父类
      (又称基类、超类)
    class DerivedClassName(BaseClassName):
        pass
    

    子类通过继承可以获得父类的所有方法

    class Person:
        def __init__(self,name):
            self.name=name
        def getName(self):
            return self.name
    
    class Student(Person):
        pass
    
    p=Student('Max')
    print(p.name)
    print(p.getName())
    

    重写

    对于父类的方法,子类实现重新定义

    class Person:
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The Person '+self.name+' is reading...')
    
    
    class Student(Person):
        def read(self):
            print('The Student'+self.name+' is reading...')
    
    p=Person('xiaoming')
    p.read()
    >>>The Person xiaoming is reading...
    q=Student('xiaohong')
    q.read()
    >>>The Student xiaohong is reading...
    
    

    若不想子类覆盖基类的方法,可将方法设为私有

    class Person:
        def __init__(self,name):
            self.name=name
        def __read(self):
            print('The Person '+self.name+' is reading...')
        def test(self):
            self.__read()
    
    
    class Student(Person):
        def __read(self):
            print('The Student'+self.name+' is reading...')
    
    p=Person('xiaoming')
    p.test()
    >>>The Person xiaoming is reading...
    q=Student('xiaohong')
    q.test()
    >>>The Peerson xiaohong is reading...
    
    

    重写构造方法

    class Person:
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The Person '+self.name+' is reading...')
    
    
    class Student(Person):
        def __init__(self,age):
            self.age=age
    
    >>>p=Student(12)
    >>>p.age
    >>>12
    >>>p.name
    >>>报错,没有name这个属性
    
    
    1. 调用父类的构造函数
    class Person:
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The Person '+self.name+' is reading...')
    
    
    class Student(Person):
        def __init__(self,name,age):
            Person.__init__(name)
            self.age=age
    
    >>>p=Student('Hello',12)
    >>>p.name
    >>>'Hello'
    >>>p.age
    >>>12
    
    1. 使用super函数
    class Person:
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The Person '+self.name+' is reading...')
    
    
    class Student(Person):
        def __init__(self,name,age):
            super().__init__(name)
            self.age=age
    
    >>>p=Student('Hello',12)
    >>>p.name
    >>>'Hello'
    >>>p.age
    >>>12
    

    子类中添加新方法

    class Person:
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The Person '+self.name+' is reading...')
    
    
    class Student(Person):
        def __init__(self,name,age):
            super().__init__(name)
            self.age=age
    
        def getAge(self):
            return self.age
    
    >>>p=Student('xiaoming',12)
    >>>print(p.getAge())
    >>>'xiaoming'
    

    两个重要的内置方法

    • isinstance(object,classinfo)如object是classinfo的实例返回True或object是classinfo子类的实例返回True
    • issubclass(class,classinfo)如class是classinfo的子类返回True

    在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类

    isinstance(p,Student)#True
    isinstance(p,Person)#True
    
    
    issubclass(Student,Person)#True
    issubclass(Person,Student)#False
    
    

    多继承

    class DerivedClassName(Base1,Base2,Base2):
        pass
    

    继承也可一级级继承下来,而任何类,最终都可以回溯到根节点object,这些继承关系就像一颗倒挂的树。

    子类把父类的所有功能都直接拿过来,这样就不必从零做起

    • 子类把父类不适合的方法覆盖(构造函数的重写)
    • 若不想子类覆盖父类的方法,将父类方法设为私有
      方法
    • 子类可新增自己特有的方法

    多态

    多态:呈现多种形态

    • 尽管不知道变量指向的是哪种类型的对象,也能对其进行操作,且操作的行为会随对象所属的类型(类)而异
    class Person:
        def __init__(self,name):
            self.name=name
        def getName(self):
            return self.name
        def read(self):
            print('The person is '+self.name+' is reading...')
    
    class Student(Person):
        def read(self):
            print('The student is '+self.name+' is reading...')
    
    class Teacher(Person):
        def read(self):
            print('The teacher is '+self.name+' is reading...')
    
    def read_twice(person):
        person.read()
        person.read()
    >>>read_twice(Person('xiaoming'))
    >>>The person is xiaoming is reading...
    >>>read_twice(Student('xiaoli'))
    >>>The student is xiaoli is reading...
    >>>read_twice(Teacher('xiaoliu'))
    >>>The teacher is xiaoliu is reading...
    

    新增Person的子类,不必对read_twice( ) 进行任何修改,就可以正常运行。

    • 实际上,任何依赖Person作为参数的方法和函数
      都可以不加修改正常运行,这就是多态
    • 由于Person类型有read( )方法,因此,传入的任意
      类型,只要是Person类或者子类,就会自动调用
      实际类型的read( )方法。

    只管调用,不管细节

    鸭子类型

    静态语言(例如Java),如果需要传入参数是
    Person类型,则传入的对象必须是Person类型或者它的子类,否则,将无法调用read( )方法

    • Python作为动态语言,则不一定需要传入Person类 型,只需保证传入的对象有一个read( )方法就可以
    class Timer:
        def read(self):
            print("Reading is good!")
    
    read_twice(Timer())
    >>>Reading is good!
    >>>Reading is good!
    

    动态语言的“鸭子类型”:并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来
    像鸭子”,那它就可以被看做是鸭子。

    封装

    将抽象得到的属性和功能相结合,形成一个有机整体,隐藏对象的属性和实现细节,仅对外提供
    公共访问方式的接口

    • 封装:无需知道对象的构造
    • 多态:无需知道对象的类型,就能调用其方法

    通过 类名. 或者 对象名. 形式访问封装内部的属性和方法

    class Person:
        add='Beijing'
        def __init__(self,name):
            self.name=name
        def read(self):
            print('The person '+self.name+'is reading')
    
    >>>p=Person('Hello')
    >>>p.add
    >>>'Beijing'
    >>>p.read()
    >>>The person Helli is reading
    

    封装的优点

    好处:

    • 保护隐私、提高安全性
    • 将变化隔离,便于使用
    • 提高复用性

    模块

    模块:Python中,可理解为对应于一个.py文件,将属性变量和实现方法封装在这个文件中

    • 任何Python 程序可作为模块导入,通过import 模块名导入(import jieba, import time…)
    • 一般用module_name.fun_name、module_name.var_name进行使用(模块名是文件名
      去掉.py后缀)

    包(package): 将多个模块分为一个包

    • 包是python模块的有层次的文件目录结构
    • 包中包含模块和子包
    • 包中必须存在__init__.py文件,包的标识,一般不在
      init.py 中写入模块,尽可能保证简单

    常见包结构

    包中包含多个模块

    包中包含多个模块和子包

    若main.py要引用package_b中的test_fact模块,导入包
    可以使用:

    通过模块名.函数名进行引用

    from package_b import test_fact
    print(test_fact.fact(3))
    

    需要通过完整的名称进行引用

    import package_b.test_fact
    print(package_b.test_fact.fact(3))
    

    若main.py要引用子包package_a_a中的hello模块,导
    入包可以使用:

    from package import item 方式导入包时,这个子项(item)既可以是子包也可以是其他命名,如函数、类、变量等

    • 例如, from package_a.package_a_a.hello import say_hello
    • import item.subitem.subsubitem 这样的语法时,这些子项必须是包,最后的子项可以是包或模块,但不能是类、函数、变量等
    • 例如,import package_a.package_a_a.hello
    • 从* 导入包,利用import *找出包中的所有模块,然后导入
    • 在需要导入所有模块的包的__init__.py文件中,定义模糊导入:all=[‘模块1’,‘模块2’,…]
    • 慎用 import *
  • 相关阅读:
    localStorage保存账号密码
    作品第二课----简易年历
    作品第二课----滚动列表
    自己遇到的冒泡事件
    Oct 20th-绿叶学习网站总结
    Sep 30th-JavaScript的数组方法总结
    Sep 8th -css sprite
    前端知识体系【转】
    July 27th
    第一节 简单的jsp实例
  • 原文地址:https://www.cnblogs.com/mengxiaoleng/p/11566758.html
Copyright © 2011-2022 走看看