22. 面向对象-初始

空扰寡人 提交于 2020-03-28 17:44:18

一、面向对象书写

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!