草庐IT

15面向对象特性

DaGuo'sBlogs 2023-11-12 原文

面向对象特性

封装

  • 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象,即将某些部分隐藏起来,在程序外部看不到,其含义是其他程序无法调用。要了解封装,离不开“私有化”,就是将类或者是函数中的某些属性限制在某个区域之内,外部无法调用。
  • 封装的作用:
    • 1、保护隐私(把不想别人知道的东西封装起来)
    • 2、隔离复杂度(比如:电视机,我们看见的就是一个黑匣子,其实里面有很多电器元件,对于用户来说,我们不需要清楚里面都有些元件,电视机把那些电器元件封装在黑匣子里,提供给用户的只是个按钮接口,通过按钮就能实现对电视机的操作。)
  • 封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问)
    • 第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装。
    • 第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
class Person:
    def __init__(self, name, age):
        self.__name = name
        self.age = age

    # 私有方法
    def __getname(self):
        # print(self.__name)
        print(f'{self.__name}')

    # 实例方法
    def printinfo(self):
        print(f'{self.__name},{self.age}')

p = Person('zhangsan', 18)
p.printinfo()

继承

  • 继承是面向对象程序设计的重要特征,也是实现代码复用的重要手段,如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作难度。已有的类,我们称为父类或者基类,新的类,我们称为子类或者派生类。

单继承

单继承指的是子类只继承一个父类 当对象调用方法时,查找顺序先从自身类找,如果自身没找到,则去父类找,父类无,再到父类的父类找,直到object类,若还无,则报错。这也称为 深度优先机制。

# 单继承
class Grandfather:
    def __init__(self):
        print('Grandfather')

    def sleep(self):
        print("sleep")

class Father(Grandfather):
    def eat(self):
        print("eat")

    def drink(self):
        print("drink")

class Son(Father):
    def study_python(self):
        print("python")

s = Son()
s.study_python()
s.eat()
s.sleep()

多继承

多继承指的是子类继承了多个父类。并且具有它们的特征。

"""情景1"""
class Father1:
    def run(self):
        print("father1 run")

class Father2:
    def run(self):
        print("father2 run")

class Son(Father1, Father2):  # 拥有相同方法时,左边优先执行
    pass

s = Son()
s.run()

"""情景2"""
class Grandfather:
    def sleep(self):
        print("Grandfather sleep")

class Father1(Grandfather):
    def run(self):
        print("father1 run")

class Father2:
    def sleep(self):
        print(" Father2 sleep")

class Son(Father1, Father2):  # 必须要左边的执行完了,才会执行右边的父类
    pass

s = Son()
s.sleep()

"""情景3"""
class Grandfather1:
    def sleep(self):
        print("sleep 12")

class Father1(Grandfather1):
    def run(self):
        print("father1 run")

class Father2(Grandfather1):
    def sleep(self):
        print("sleep 6")

class Son(Father1, Father2):  # 如果同根的话,根是最后才执行的
    pass

s = Son()
s.sleep()


print(Son.__mro__)  # 通过mro方法可以程序执行或者继承顺序的情况
# (<class '__main__.Son'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class '__main__.Grandfather1'>, <class 'object'>)

方法的重写

当子类与父类拥有同名称的方法时,子类对象调用该方法优先执行自身的方法。那么实际上就是子类的方法覆盖父类的方法,也称为重写。实际的开发中,遵循开放封闭原则。我们并不会完全的重写父类的方法,而是希望同时实现父类的功能。

# 相对而言是我们B的父类
class A:
    # init同时也能够被继承
    def __init__(self):
        print('A')

    def test(self):
        print("aaaa")

# B继承了A 子类
class B(A):
    def __init__(self):
        print('B')
        # A.__init__(self)
        super(B, self).__init__()

    # 子类重写父类的同名方法
    def test(self):
        print("bbbb")
        # 对该方法进行重写,同时实现子类和父类的功能 三个方法都可以
        # super(B, self).test()
        # super().test()
        # A.test(self)   # 通过类名.方法名 强写 不推荐


b = B()  # 创建了B的对象
b.test()  # bbbb
"""
若将test方法里的注释放开,则也会打印A中test方法中的aaaa
"""

多态

Python中函数的参数是没有类型限制的,所以多态在python中的体现并不是很严谨。多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。python是弱语言类型。

  • 多态(polymorphism):指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度

1、实现多态的步骤:

1)定义一个父类(Base),实现某个方法(比如:run)
2)定义多个子类,在子类中重写父类的方法(run),每个子类run方法实现不同的功能
3)假设我们定义了一个函数,需要一个Base类型的对象的参数,那么调用函数的时候,传入Base类不同的子类对象,那么这个函数就会执行不同的功能,这就是多态的体现。

class Animal(object):
    """动物类"""
    def func(self):
        print('动物发出了声音')

class Cat(Animal):
    """猫类"""
    def func(self):
        print('喵 喵 喵')

class Dog(Animal):
    """狗类"""
    def func(self):
        print('汪 汪 汪 ')

class Hero:
    def func(self):
        print('这个是英雄类的方法,不是动物类的对象')

def work01(Animal):
    Animal.func()


work01(Dog())  # 传入的对象 结果:汪 汪 汪 
work01(Animal())  # 动物发出了声音
# 传入不同的对象,产生不同的结果
# 调用灵活 更容易编写出通用的代码

多态的意义:

(1)在程序运行过程中展现出动态的特性,在程序编译的时候无法知道调用哪个函数
(2)函数重写必须多态实现,否则没有意义
(3)多态是面向对象组件化程序设计的基础特性

注意点:Python中函数的参数是没有类型限制的,所以多态在python中的体现并不是很严谨。多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

鸭子类型

  • 鸭子类型概念:他并不要求严格的继承体系,关注的不是对象的类型本身,而是它是否具有要调用的方法(行为)
class Duck:
    def quack(self):
        print("嘎嘎嘎嘎。。。。。")

class Bird:
    def quack(self):
        print("bird imitate duck....")

class geese:
    def quack(self):
        print("geese imitate duck....")

def in_the_forest(duck):
    duck.quack()


duck = Duck()
bird = Bird()
geese = geese()
for x in [duck, bird, geese]:
    in_the_forest(x)
"""
嘎嘎嘎嘎。。。。。
bird imitate duck....
geese imitate duck....
"""

有关15面向对象特性的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby-on-rails - 按天对 Mongoid 对象进行分组 - 2

    在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev

  3. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  4. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  5. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  6. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  7. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  8. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  9. ruby - 更改 ActiveRecord 中对象的类 - 2

    假设我有一个FireNinja我的数据库中的对象,使用单表继承存储。后来才知道他真的是WaterNinja.将他更改为不同的子类的最干净的方法是什么?更好的是,我很想创建一个新的WaterNinja对象并替换旧的FireNinja在数据库中,保留ID。编辑我知道如何创建新的WaterNinja来self现有FireNinja的对象,我也知道我可以删除旧的并保存新的。我想做的是改变现有项目的类别。我是通过创建一个新对象并执行一些ActiveRecord魔法来替换行,还是通过对对象本身做一些疯狂的事情,或者甚至通过删除它并使用相同的ID重新插入来做到这一点,这是问题的一部分。

  10. ruby-on-rails - ActiveRecord 对象相等 - 2

    根据ActiveRecord::Base的文档:==(comparison_object)Returnstrueifcomparison_objectisthesameexactobject,orcomparison_objectisofthesametypeandselfhasanIDanditisequaltocomparison_object.id.Notethatnewrecordsaredifferentfromanyotherrecordbydefinition,unlesstheotherrecordisthereceiveritself.Besides,ifyoufet

随机推荐