面向对象—基础、名称空间、三大特性

一、面向对象的简介

面向对象

  • 初识

    • 一种新的编程思路

      • 面向过程开发:想要一个结果 写代码 实现计算结果
      • 面向对象开发:有哪些角色 角色的属性和技能之间是如何交互的
  • 什么时候用?

    复杂的 拥有开放式结局的程序 比较适合使用面向对象开发

    • 游戏
    • 购物
  • 例子:人狗大战
    alex = {    ‘name‘: ‘alex‘,    ‘sex‘: ‘不详‘,    ‘job‘: ‘搓澡工‘,    ‘level‘: 0,    ‘hp‘ : 250,    ‘weapon‘:‘搓澡巾‘,    ‘ad‘ : 1}?小白 = {    ‘name‘:‘小白‘,    ‘kind‘:‘泰迪‘,    ‘hp‘:5000,    ‘ad‘:249}
    
    # 1.你怎么保证所有的玩家初始化的时候都拥有相同的属性# 2.每来一个新的玩家,我们都自己手动的创建一个字典,然后向字典中填值# 3.人物和狗的技能如何去写?# 建立人物的模子:def Person(name,sex,job,hp,weapon,ad,level=0):   # 人模子    def 搓(dog):        dog[‘hp‘] -= dic[‘ad‘]        print(‘%s 攻击了 %s,%s掉了%s点血‘ % (dic[‘name‘], dog[‘name‘], dog[‘name‘], dic[‘ad‘]))    dic = {    ‘name‘: name,    ‘sex‘: sex,    ‘job‘: job,    ‘level‘: level,    ‘hp‘ :hp,    ‘weapon‘:weapon,    ‘ad‘ : ad,    ‘action‘:搓    }    return dic??# 建立狗的模子:def Dog(name,kind,hp,ad):    def 舔(person):  # 函数不是一个公用的函数 是一个有归属感的函数        person[‘hp‘] -= dic[‘ad‘]        print(‘%s 舔了 %s,%s掉了%s点血‘ % (dic[‘name‘], person[‘name‘], person[‘name‘], dic[‘ad‘]))    dic = {    ‘name‘: name,    ‘kind‘: kind,    ‘hp‘: hp,    ‘ad‘: ad,    ‘action‘:舔    }    return dic?alex = Person(‘alex‘,‘不详‘,‘搓澡工‘,250,‘搓澡巾‘,1)wusir = Person(‘wusir‘,‘male‘,‘法师‘,500,‘打狗棍‘,1000)小白 = Dog(‘小白‘,‘泰迪‘,5000,249)小金 = Dog(‘小金‘,‘柯基‘,10000,499)?小白[‘action‘](alex)   # 小白 舔了 alex,alex掉了249点血alex[‘action‘](小白)   # alex 攻击了 小白,小白掉了1点血

    以上的程序可以用面向对象的方法解决:

    class Person: # 类名    def __init__(self,name,sex):    # 必须叫 __init__这个名字,不能改变的,所有的在一个具体的人物出现之后拥有的属性都可以写在这里        self.name = ‘alex‘        self.sex = ‘man‘?alex = Person() # alex 就是对象 alex = Person()的过程 是通过类获取一个对象的过程 — 实例化# 类名()会自动调用类中的__init__方法??class Person:       # 类名    def __init__(self,name,sex,job,hp,weapon,ad):        # 必须叫__init__这个名字,不能改变的,所有的在一个具体的人物出现之后拥有的属性        self.name = name        self.sex = sex        self.job = job        self.level = 0        self.hp = hp        self.weapon = weapon        self.ad = ad?alex = Person(‘alex‘,‘不详‘,‘搓澡工‘,260,‘搓澡巾‘,1)    # alex 就是对象  alex = Person()的过程 是通过类获取一个对象的过程 - 实例化print(alex,alex.__dict__)# <__main__.Person object at 0x00000224364739B0> # {‘name‘: ‘alex‘, ‘sex‘: ‘不详‘, ‘job‘: ‘搓澡工‘, ‘level‘: 0, ‘hp‘: 260, ‘weapon‘: ‘搓澡巾‘, ‘ad‘: 1}?wusir = Person(‘wusir‘,‘male‘,‘法师‘,500,‘打狗棍‘,1000)# print(wusir,wusir.__dict__)print(alex.name)   # print(alex.__dict__[‘name‘])  属性的查看alex.name = ‘alexsb‘        # 属性的修改print(alex.name) # alexsbalex.money = 1000000        # 属性的增加print(alex.money) # 1000000print(alex.__dict__)# {‘name‘: ‘alex‘, ‘sex‘: ‘不详‘, ‘job‘: ‘搓澡工‘, ‘level‘: 0, ‘hp‘: 260, ‘weapon‘: ‘搓澡巾‘, ‘ad‘: 1, ‘money‘: 1000000}del alex.money               # 属性的删除print(alex.__dict__)
  • 类和对象之间的关系?
    • 类 是一个大范围 是一个模子 它约束了事物有哪些属性 但是不能约束具体的值
    • 对象 是一个具体的内容 是模子的产物 它遵循了类的约束 同时给属性附上具体的值
    • Person是一个类 alex,wusir是这个类的对象
    • 类有一个空间,存储的是定义在class中的所有名字
    • 每一个对象又拥有自己的空间,通过对象名.__dict__就可以查看这个对象的属性和值
    • 修改列表\字典中的某个值,或者面向对象的某个属性 都不会影响这个对象\字典\列表所在的内存空间
  • 实例化所经历的步骤
    1. 实例 = 类名() 类名()之后的第一件事:开辟一块空间
    2. 首先开辟空间,调用init方法,把开辟的空间地址传递给self参数,调用__init__把空间的内存地址作为self参数传递到函数内部
    3. init方法中一般完成:把属性的值存储在self的空间里 — 对象的初始化,所有的这一对象需要使用的属性都要和self关联起来
    4. self这个地址会作为返回值,返回给“实例”,执行完__init__中的逻辑后,self变量会自动的被返回到调用处(发生实例化的地方)
  • 实例变量:self.名字

二、面向对象中类的成员和命名空间

  1. 命名空间

    • 在类的命名空间里:静态变量、绑定方法
    • 在对象的命名空间里:类指针、对象的属性(实例变量)
  2. 调用的习惯
    • 类名.静态变量
    • 对象.静态变量(对象调用静态变量的时候,不能对变量进行赋值操作 )
    • 绑定方法
      • 对象.绑定方法() # ==> 类名.绑定方法(对象)
      • 对象.实例变量
      • 对象
    • 对象 = 类名()

      怎么用

      • 类能做什么用:

        • 1.实例化对象
        • 2.操作静态变量
      • 什么时候是对类中的变量赋值,或者去使用类中的变量
        • 类名.名字 = ‘值’
        • print(类名.名字 )
        • print(对象名.名字 ) # 如果对象本身没有这个名字
      • 什么时候是对对象中的变量赋值
        • 对象.名字 的时候
        • self.名字 的时候
# 例题1class A:    Country = ‘中国‘     # 静态变量/静态属性 存储在类的命名空间里的    def __init__(self,name,age):  # 绑定方法 存储在类的命名空间里的        self.name = name        self.age = age    def func1(self):        print(self)    def func2(self):pass    def func3(self):pass    def func4(self):pass    def func5(self):pass?a = A(‘alex‘,83)print(a.name)     # alexprint(a.Country)  # 中国(先在a的属性的小空间找Country,没有就通过类指针在A类里找Country)?print(A.Country)   # 中国a.func1() # == A.func1(a)  # <__main__.A object at 0x000002171C4F87F0>?# 可以看出,a实例化开辟自己的空间,调用init方法在自己的空间建立name,age变量,所以调用a.name是用自己的,而调用a.Country时,自己内部没有,就用A类的??# 例题2class A:    Country = ‘中国‘     # 静态变量/静态属性 存储在类的命名空间里的    def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的        self.name = name        self.age = age        self.Country = country    def func1(self):        print(self)    def func2(self):pass    def func3(self):pass    def func4(self):pass    def func5(self):pass?a = A(‘alex‘,83,‘印度‘)print(a.name)    # alexprint(a.Country) # 印度print(A.Country) # 中国?# 可以看出,a的空间里有name,Country,都用自己的??# 例题3class A:    Country = ‘中国‘     # 静态变量/静态属性 存储在类的命名空间里的    def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的        self.name = name        self.age = age        self.country = country    def func1(self):        print(self)    def func2(self):pass    def func3(self):pass    def func4(self):pass    def func5(self):pass?a = A(‘alex‘,83,‘印度‘)b = A(‘wusir‘,74,‘泰国人‘)a.Country = ‘日本人‘print(a.Country) # 日本print(b.Country) # 泰国print(A.Country) # 中国?# a本来自己的空间中有Country = ‘印度‘,但是a.Country = ‘日本人‘,就在a空间改变了Country的属性??# 例题4class A:    Country = ‘中国‘     # 静态变量/静态属性 存储在类的命名空间里的    def __init__(self,name,age,country):  # 绑定方法 存储在类的命名空间里的        self.name = name        self.age = age   # 注意,此处没有匹配country的参数    def func1(self):        print(self)    def func2(self):pass    def func3(self):pass    def func4(self):pass    def func5(self):pass?a = A(‘alex‘,83,‘印度‘)b = A(‘wusir‘,74,‘泰国人‘)A.Country = ‘日本人‘print(a.Country)print(b.Country)print(A.Country)?# init的方法中没有Country的属性,所以实例化a,b的时候,调用init方法没有在自己的内部建立Country的属性,所以a.Country和b.Country都是用的A中的Country,就都是日本人
  • 由此可得出静态变量的作用

    • 如果一个变量,是所有的对象共享的值,那么这个变量应该被定义成静态变量
    • 所有和静态变量相关的增删改查都应该使用类名来处理;

      而不应该使用对象名直接修改静态变量

  1. 组合

    • 一个类的对象是另一个类对象的属性
    • 两个类之间 有 什么有什么的关系:班级有学生 学生有班级 图书有作者.....

三、面向对象的三大特性——继承、封装、多态

(一)、继承

  1. 目的:解决代码的重复性
  2. 继承中遇到的两种情况
    • 当子类和父类的方法重名的时候,我们只使用子类的方法,而不会去调用父类的方法了

      class Animal:    def __init__(self,name):        self.name = name    def eat(self):        print(‘%s is eating‘%self.name)class Cat(Animal):    def eat(self):        print(‘%s吃猫粮‘%self.name)小白 = Cat(‘小白‘)小白.eat()        # 小白吃猫粮(因为在Cat类型中有eat属性,就不调用父类的)        
    • 子类想要调用父类的方法的同时还想执行自己的同名方法

      在子类的方法中调用父类的方法 :父类名.方法名(self)

      class Animal:    def __init__(self,name,food):        self.name = name        self.food = food        self.blood = 100    def eat(self):        print(‘%s is eating %s‘%(self.name,self.food))class Cat(Animal):    def eat(self):        self.blood += 100        Animal.eat(self)        print(f‘{self.name}此时的体力为{self.blood}‘)小白 = Cat(‘小白‘,‘猫粮‘)小白.eat()# 小白 is eating 猫粮# 小白此时的体力为200print(小白.__dict__) # {‘name‘: ‘小白‘, ‘food‘: ‘猫粮‘, ‘blood‘: 200}
    • 总结:
      • 继承语法: class 子类名(父类名):pass
      • 父类和子类方法的选择:
        • 子类的对象,如果去调用方法

          永远先调用自己的

          1. 如果自己有 用自己的
          2. 自己没有 用父类的
          3. 如果自己有 还想用父类的:直接在子类方法中调父类的方法 父类名.方法名(self)
  3. 多继承

    一个子类有多个父类

    单继承

    • 调子类的 : 子类自己有的时候
    • 调父类的 : 子类自己没有的时候
    • 调子类和父类的 :子类父类都有,在子类中调用父类的

    多继承

    • 一个类有多个父类,在调用父类方法的时候,按照继承顺序,先继承的就先寻找
    • 新式类和经典类

      python3 所有的类都继承object类,都是新式类

      在py2中 不继承object的类都是经典类

      继承object就是新式类

      在单继承方面(无论新式类,还是经典类,都是一样的)

      在多继承的情况中:

      • 对于新式类,在走到一个点,下一个点既可以从深度走,也可以从广度走,总是先走广度,广度优先
      • 在经典类中,都是深度优先,总是在一条路走不通之后再换一条路,走过的点不会再走了
      • 广度优先 C3算法

      总之:

      • 经典类 — 深度优先 新式类 — 广度优先
      • 深度优先会看
      • 广度预先遵循C3算法,要会用mro,会查看顺序
      • 经典没有mro,但新式类有
    • 通过继承实现的类的开发规范(工作中)
      • 1.不用模块的:

        class 父类    def 子类必须实现的方法名(self,参数们):        raise NotImplementedError(‘提示信息‘)        class 子类(父类):    def 父类要求实现的方法(self,参数们):        print(‘‘‘code‘‘‘)
      • 2.用模块的
        from abc import ABCMeta,abstractmethodclass 父类(metaclass = ABCMeta):     @abstractmethod    def 子类必须实现的方法名(self,参数们):passclass 子类(父类):     def 父类要求实现的方法(self,参数们):        print(‘‘‘code‘‘‘)

(二)、多态

  1. 什么是多态:一个类表现出的多种状态,实际上是通过继承来完成的

    • 例子:如果狗类继承动物类,猫类也继承动物类
    • 那么我们就说猫的对象也是动物类型的
    • 狗的对象也是动物类型的
    • 在这个例子里,动物这个类型表现出了猫和狗的形态
  2. 鸭子类型

    在py中,一个类可以是很多类的鸭子类型

    • tuple 元组类

      是可哈希的

      但是又不依靠继承哈希来判定是不是可哈希类型

      元组类是可哈希类型的鸭子类型

    • 可迭代的类型

      不是依靠继承迭代来判定是不是迭代类型

      看他长得像(内部实现了__init__

    子类继承父类,我们说子类也是父类这个类型的

    ? 在Python中,一个类是不是属于某一个类型,不仅仅通过继承完成,还可以是不继承,但是如果这个满足了某些类型的特征条件,我们就说它长得像这个类型,那么它就是这个类型的鸭子类型

(三)、封装

  1. 封装:就是把属性和方法装起来

    • 广义上的封装:把属性和方法装起来,外面不能直接调用,要通过类的名字来调用
    • 狭义上的封装:把属性和方法藏起来,外面不能调用了,只能在内部偷偷调用
  2. 给一个名字前面加上了双下划綫的时候,这个名字就变成了一个私有的

    所有的私有的内容或者名字都不能在类的外部调用,只能在类的内部使用了

  3. 使用的三种情况
    • 使用的三种情况

      • 不想让你看,也不想让你改

        class User:    def __init__(self,name,passwd):        self.usr = name        self.__pwd = passwd   # 私有的实例变量/私有的对象?# 没有其他的方法,既不能看,也不能改
      • 可以让你看,但不让你改
        class User:    def __init__(self,name,passwd):        self.usr = name        self.__pwd = passwd  # 私有的实例变量/私有的对象属性    def get_pwd(self):       # 表示的是用户不能改只能看 私有 + 某个get方法实现的        return self.__pwd    alex = User(‘alex‘,‘sbsbsb‘)print(alex.get__pwd())        # sbsbsb (只能看不能改)
      • 可以让你看,也可以让你改(但是要求你按照我的规则改)
        class User:    def __init__(self,name,passwd):        self.usr = name        self.__pwd = passwd  # 私有的实例变量/私有的对象属性    def get_pwd(self):       # 表示的是用户不能改只能看 私有 + 某个get方法实现的        return self.__pwd    def change_pwd(self):    # 表示用户必须调用我们自定义的修改方式来进行变量的修改 私用 + change方法实现        pass    
    • 封装的语法
      • 私有的静态变量

        # 外部不可以调class User:    __Country = ‘China‘   # 私有的静态变量    def func(self):        print(User.__Country)  # 在类的内部可以调用print(User.Country)  # 报错 在类的外部不能调用print(User.__Country)# 报错 在类的外部不能调用??# 内部可以调class User:    __Country = ‘China‘   # 私有的静态变量    def func(self):        print(User.__Country)  # 在类的内部可以调用User().func()   # China  说明内部可以调用
      • 私有的实例变量
        class User:    def __init__(self,name,passwd):        self.usr = name        self.__pwd = passwd   # 私有的实例变量/私有的对象
      • 私有的绑定方法
        import  hashlibclass User:    def __init__(self,name,passwd):        self.usr = name        self.__pwd = passwd  # 私有的实例变量    def __get_md5(self):     # 私有的绑定方法        md5 = hashlib.md5(self.usr.encode(‘utf-8‘))        md5.update(self.__pwd.encode(‘utf-8‘))        return md5.hexdigest()    def getpwd(self):        return self.__get_md5()alex = User(‘alex‘,‘sbsbsb‘)print(alex.getpwd())  # d6170374823ac53f99e7647bab677b92
      • 私有化目的:所有的私有化都是为了让用户不在外部调用类中的某个名字
      • 私有化作用:如果完成私有化,那么这个类的封装度就更高了,封装度越高各种属性和方法的安全性也越高,但是代码越复杂
      • 私有的特点
        • 能不能类的内部使用? 可以
        • 能不能类的外部使用? 不可以
        • 能不能类的子类中使用? 不可以
      • 类中变量的级别,哪些是python支持的,哪些是python不支持的
        • 共有的

          public 公有的 类内类外都能用,父类子类都能用

          python支持

        • 保护的

          protect 保护的 类内能用,父类子类都能用,类外不能用

          python不支持

        • 私有的

          private 私有的 本类的类内部能用,其他地方都不能用

          python支持

原文地址:https://www.cnblogs.com/yangzm/p/10993651.html

时间: 2024-11-08 17:34:51

面向对象—基础、名称空间、三大特性的相关文章

OC基础 类的三大特性

OC基础  类的三大特性 OC的类和JAVA一样,都有三大特性:继承,封装,多态,那么我们就来看一下OC中类的三大特性. 1.继承 继承的特点: (1)子类从父类继承了属性和方法. (2)子类独有的属性和方法不能被父类使用. (3)子类独有的属性和方法,不能够在子类之间互相使用. (4)子类能够重写父类的方法,子类调用该方法时:首先调用子类的方法,如果子类没有该方法,就调用父类的该方法. (5)子类对象指针可以转换成父类对象指针,但是父类对象指针不能够转换成子类对象指针. 三种权限变量的继承:

Java面向基础概述和三大特性

Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心.围绕着 Java 类和 Java 对象,有三大基本特性:封装是 Java 类的编写规范.继承是类与类之间联系的一种形式.而多态为系统组件或模块之间解耦提供了解决方案. 本文主要围绕这三大特性介绍一下 Java 面向对象.组件解耦的核心思想. 1.面向对象思想 面向对象编程是当今主流的程序设计思想,已经取代了过程化程序开发技术,Java 是完全面向对象编程语言,所以必须熟悉面向对象才能够编写 Java 程序. 面向对象的程序

python基础名称空间与作用域

1.名称空间:存放名字与值的绑定关系 2.名称空间分为三种 1)内置名称空间:python解释器自带的名字,python解释器启动就会生成 2)全局名称空间:文件级别定义的名字都会存放于全局名称空间,执行python文件时会产生x=1def func(): passclass Foo(): passimport os 3)局部名称空间:定义在函数内部的名字,局部名称空间只有在调用函数时生效def func(x,y): z=3 func(1,2)3.三者的加载顺序:内置名称空间>>全局名称空间&

面向对象,类名称空间,查找顺序,组合

# 程序从上往下一次把类的静态变量和方法全部加载进一个内存空间,直到遇到类名加括,实例化对象的时候会新开辟一个内存空间,# (会有一个类对象指针)在对象里面没找到目标会根据指针,去类里面找 # 查询顺序:# 对象.属性:先从对象空间找,如果找不到,再从类空间找,再找不到再从父类找# 类名.属性:先从本类空间找,如果找不到,再从父类找 类名称空间:在定义类的时候会开辟一个空间,这个空间里面装着所有的类class Person: animal='高级动物' soul='有灵魂' language='

面向对象(二)——三大特性(封装、继承、多态)

一.封装 目的:保护类,让类更加安全. 做法:让类里面的成员变量变为私有(即访问修饰符)的,做相应的方法或者属性去间接的操作成员变量 ※访问修饰符 private 私有的              只能在该类中访问 protected 受保护的       只能在该类和它的子类中访问 public 公有的                在任何地方都可以访问 △封装成员方法来间接操作类里面的成员变量 例: class Ren { private string name; private int a

java第五章:面向对象(oop)三大特性之多态

多态(把代码写活,提高代码的扩展性和可维护性) 生活中的多态:同一种物质,因不同的环境展现不同的形态(水:气态,液态,固态/碳12:金刚石,石墨) 程序中的多态:同一个"接口"因不同的实现,而执行不同的操作(就是在方法中把父类作为形式参数传入,调用的时候,传入子类的实例,最终执行的是子类中重写父类的方法) 多态一般结合方法重写.继承使用,父类引用指向子类: 多态实现步骤: 1.实现继承 2.编译时将父类作为形式参数类型传入(范围大一点,模糊一点) 3.运行时将子类new出的实例传入,最

【WPF学习】第三章 使用其他名称空间中的类型

前面已经介绍了如何在XAML中使用WPF中的类来创建基本的用户界面.但XAML是实例化.NET对象的通用方法,包括那些位于其他非WPF名称空间以及自己创建的名称空间中的对象. 创建那些不是用于在XAML窗口中显示的对象听起来像是多余的,但在很多情况下这是需要的.一个例子是,但使用数据绑定并希望在某个控件上显示从其他对象提取的信息时.另外一个例子是希望使用非WPF对象为WPF对象设置属性时. 例如,可使用数据对象填充WPF的ListBox控件.ListBox控件将调用ToString()方法来获取

JAVA基础——面向对象三大特性:封装、继承、多态

JAVA面向对象三大特性详解 一.封装 1.概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: 只能通过规定的方法访问数据.     隐藏类的实例细节,方便修改和实现. 3.封装的实现步骤 需要注意:对封装的属性不一定要通过get/set方法,其他方法也可以对封装的属性进行操作.当然最好使用get/set方法,比较标准. A.访问修饰符 从表格可以看出从上到下封装性越来越差. B.this关键字 1.this关键字代表当前

JavaScript基础--面向对象三大特性(八):继承封装多态

一.构造函数基本用法:function 类名(参数列表){属性=参数值} 1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 } 5 6 //创建Person对象的时候,可以直接给名字和年龄 7 var p1 = new Person('abc',80); 8 window.alert(p1.name); 9 var p2 = new Person('hello',9); 10 window.alert(p2.