zoukankan      html  css  js  c++  java
  • 22. 面向对象-初始

    一、面向对象书写

    class Car:
        # self表示当前类对象,当前你创建的是谁,谁来访问这个方法,self就是谁
        def __init__(self, color, displacement, number):
            self.color =     color
            self.displacement = displacement
            self.number = number
    
        def run(self, speed):
            print(f"这辆车可以跑{speed}迈")
    
    #实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
    car = Car("red", "1.8T", "京A88888")
    car.run(100)
    
    1. __new__(cls, *args, **kwargs)
        __new__ 负责对象的创建而 __init__ 负责对象的初始化;至少需要传递一个参数cls,必须要有返回值,返回实例化出来的实例。可以return父类通过super(当前类名,cls).__new__出来的实例,或者直接是object的__new__出来的实例。
    
    2. __init__()  - 构造方法
        __init__()在__new()的基础上完成初始化动作,不需要返回值;有一个参数self,该self参数就是__new__()返回的实例;
    
    3. 实例
    
    class B():
        def __new__(cls, *args, **kwargs):
            print("__new__方法被执行")
            return super(B, cls).__new__(cls)
    
    
        def __init__(self):
            print("__init__方法被执行")
    
    b = B()
    

    二、继承

    1、新式类与经典类

    • 新式类:继承了object类以及该类的子类都是新式类;Python3中如果没有继承任何类,则默认继承object类。因此Python3中都是新式类(广度优先遍历)
    • 经典类:没有继承object类以及该类的子类,都是经典类;在Python2中如果一个类没有继承任何类,不会继承object类(深度优先遍历)

    2、抽象与派生

    ​ (1) 抽象:通过抽象可以得到类,抽象是一种分析的过程。比如,猪八戒、小猪佩奇可以抽象出一个类,就是猪类;接着还可以从猪类、狗类抽象出动物类。先分析、抽象之后,就可以通过继承,在程序上实现这个结构。

    ​ (2) 派生:就是在子类继承父类的属性的基础上,派生出自己的属性。子类有不同于父类的属性,这个子类叫做派生类。

    class Animals:
        def __init__(self, name):
            self.name = name
    
        def walk(self):
            print('我会走')
    
    class Dog(Animals):
        # Dog类派生出bite功能
        # 派生:狗有咬人的技能
        def bite(self):
            print('我会咬人')
    

    3、组合

    class Mobile():
        def __init__(self, color):
            self.color = color
    
        def call(self):
            print("打电话")
    
    class People():
        def __init__(self, name, mobile):
            self.name = name
            self.mobile = mobile
    
    mobile = Mobile("red")
    people = People("Tom", mobile)
    people.mobile.call()
    

    4、属性查找顺序

    ​ 对象自己->所在类中->找父类->父类的父类->Object

    5、多继承

    class ParentOne:
        pass
    
    class ParentTwo:
        pass
    
    class SubClass(ParentOne, ParentTwo):
        pass
    
    
    #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    print(SubClass.__bases__)
    
    >(<class '__main__.ParentOne'>, <class '__main__.ParentTwo'>)
    
    MRO顺序
    
    >F.MRO()
    >[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    

    三、覆盖(overrides)

    1、子类访问父类内容

    注:当子类出现了和父类名称完全一致的属性或方法
    
    方式一
        super.(当前类名称, self).你要调用的父类的属性或方法
    
    方式二
        super().你要调用的父类的属性或方法
    
    方式三
        类名称.你要调用的父类的属性或方法(self)
    
    注:当你继承一个现有的类,并且你覆盖了父类的init方法时,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需的参数
    
    练习:实现一个可以现在元素类型的容器(字典、列表、元组、集合、字符串)
    
    class MyList(list):
        def __init__(self, element_type):
            # 调用父类初始化方法来完成基本的初始化
            super().__init__()
            self.element_type = element_type
    
        def append(self, object):
            """
            :param object: 是要存储的元素
            :return: 无
            """
            if type(object) == self.element_type:
                super(MyList, self).append(object)
            else:
                print(f"sorry, you element type not is {self.element_type}")
    
    m = MyList(int)
    m.append(1)
    print(m[0])
    m.append("11")
    

    四、封装

    1、类成员-属性

    1. 实例变量(字段)
    2. 类变量(静态变量)
    
    每个实例都应该拥有的变量. 比如.在上述事例中电影的的名字,电影的类型, 电影的语言,电影的时长,都是实例变量而类变量就是这一类事物统一拥有的变量,比如上述事例中可以说这些个电影都可以是3D(规定下),类变量最好是用类名来访问
    
    方式一:
    class Movie:
        film_format="3D"
        def __init__(self,genre,language,name,time):
            self.genre=genre
            self.language=language
            self.name=name
            self.time=time
        def show(self):
            print("%s在中国上映" %self.name)
    
    
    M1 = Movie("剧情","国语","少林足球","2H")
    M2 = Movie("喜剧","国语","大话西游","2H")
    Movie.film_format="2D"                    #把类变量中的值改了,都跟着变了.
    print(M1.film_format)                     #2D
    print(M2.film_format)                     #2D
    
    
    方式二:
    class Movie:
        film_format="3D"
        def __init__(self,genre,language,name,time):
            self.genre=genre
            self.language=language
            self.name=name
            self.time=time
        def show(self):
            print("%s在中国上映" %self.name)
    M1 = Movie("剧情","国语","少林足球","2H")
    M2 = Movie("喜剧","国语","大话西游","2H")
    M1.film_format="2D"
    print(M1.film_format)                   #2D
    print(M2.film_format)                   #3D
    

    2、类成员-方法

    (1)成员方法 - 对象直接可以访问的方法
    class Computer:
        # 成员方法
        def play(self):
            print("play game!")
    
    computer = Computer()
    computer.play()
    
    (2)静态方法

    ​ 不需要给方法传递self;即当出现一个方法不需要用到成员变量时[@staticmethod]

    class Person:
        def __init__(self):
            pass
    
        # 实例方法需要传递类的对象self
        def think(self):
            print("人能思考")
    
        @staticmethod
        def calculate(a, b):
            return a + b
    
    # 类名可以访问
    person = Person.calculate(1, 2)
    print(person)
    > 3
    
    (3)类方法

    ​ 当方法需要传递类名时,需要类方法[@classmethod]

    class Person:
        def __init__(self):
            pass
    
        # cls表示类
        @classmethod
        def clsMethod(cls):
            # 可以动态创建对象
            person = cls()
            print("我是一个类方法", person)
    
    
    # 类方法默认第一个参数接受的是类名
    Person.clsMethod()
    > 我是一个类方法 <__main__.Person object at 0x00000241E7A17358>
    

    3、类成员-属性

    ​ 应用场景: 我们⼀般保存数据的时候, 不会保存⼀个⼈的年龄. 因为随着时间的推移. 每个人的年年龄都时刻在改变着. 那如何保存更更加完美呢? 很简单. 保存出生年年月日. 然后用程序来 计算,你当前的年龄实时的那这个时候就需要进行行相应的计算了了. 而计算属于⼀个功能. 当然要写方法里了. 但是对于年年龄这个属性而言. 他应该是一个数值. 而不是动作. 所以python 就提供了这样⼀种机制. 通过方法来描述⼀个属性.

    ​ 注意:

    • 方法参数只能有⼀个self
    • 方法上方要写@property
    • 调用的时候, 我们不需要写括号. 直接当成属性变量量来用就可
    • 这种套路只能取值. 不能设置值
    class Person:
        def __init__(self, name, num, gender, birthday):
            self.name = name
            self.num = num
            self.gender = gender
            self.birthday = birthday
    
        # 表示当前方法是一个属性.方法的返回值就是这个属性的值
        @property
        def age(self):
            # 方法只能有一个参数self;可以是计算结果,必须有返回值
            return 10 * 9
    
    
    person = Person("alex", "10086", "不详", "1989-01-02")
    print(person.age)
    > 90
    

    4、私有

    (1)私有变量

    ​ 私有的内容不能直接访问,但是如果对方开辟了外界访问的通道(公共方法),那可以通过这个公共的方法来获取到私有的内容,这样做的好处是. 外界只能看, 但是改不了.

    class Tiger:
        def __init__(self, name,figure, money):
            self.name = name
            self.figure = figure
            self.__money = money
    
        def buy(self):
            print(f"我有{self.__money}这么多钱")
    
    tiger = Tiger("永康", "正直", "1亿")
    tiger.buy()
    > 我有1亿这么多钱
    
    (2)私有方法
    class Tiger:
        def __init__(self,name,figure,style,qingfu,money,fangchan):
            self.name = name
            self.figure = figure
            self.style = style
            self.__qingfu = qingfu
            self.__money = money
            self.__fangchan=fangchan
    
        def buy(self):
            print("我有%s这么多钱" % self.__money)                  #我有10亿这么多钱
            self.__sel()
    
        def __sel(self):
            print("我要卖掉%s套房" % self.__fangchan)
    
    T1=Tiger("呵呵","正直","廉洁","潘潘","10亿","10")
    T1.buy()
    
    >我有10亿这么多钱
    >我要卖掉10套房
    

    五、单例模式

    import threading
    # 多线程情况下需要加锁,因为它们共享一个内存
    class Singleton(object):
        _instance = None
        _lock = threading.RLock()
        # cls是当前正在实例化的类;初始化一块内存
        def __new__(cls, *args, **kwargs):
            # 如果已创建实例,直接返回即可
    		if cls._instance:
                return cls._instance
            # 加锁
            with cls._lock:
                if not cls._instance:
                    cls._instance = super().__new__(cls, *args, **kwargs)
                return cls._instance
    
  • 相关阅读:
    Spring声明式事务可能出现的问题
    SpringBoot自定义starter
    查找和最小的K对数字
    SpringBoot配置嵌入式Servlet容器和使用外置Servlet容器
    Redis的数据结构及应用场景
    高考还没结束,这份试卷已经流出,你能拿多少分?
    Linux C/C++编程之(十六)进程及进程控制
    Dom4j修改xml文档引入
    淘宝,京东,苏宁易购技术架构(路线)分析和比较
    android 解析服务器数据使用json还是xml方式
  • 原文地址:https://www.cnblogs.com/hq82/p/12587764.html
Copyright © 2011-2022 走看看