zoukankan      html  css  js  c++  java
  • Python-面向对象之基本概念,封装

    1、语言分类

      三大范式:(即方法论)

        面向机器:抽象成机器指令,机器容易理解,代表:汇编

        面向过程:做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现A情况,做什么处理。

          问题规模小,可以步骤化,按部就班处理

          代表:c语言

        面向对象:OOP,随着计算机需要解决的问题的规模扩大,情况月复杂,需要很多人,很多部门协作,面向过程编程不太社和了

          代表:c++, java, Python

    2、面向对象:

      面向对象:一种认识世界,分析世界的方法论,将万事抽象为类Class

      类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合

      用计算机语言来描述类,就是属性和方法的集合

      对象instance,object,对象是类的具体,是一个实体。

      哲学思想:

          一切皆对象,包括类也是对象

          对象是数据和操作的封装

          对象是独立的,但是对象之间可以互相作用

          目前OOP 是最接近人类认知的编程范式

    3、面向对象的3要素:

      ① 封装

        - 组装:将数据和操作组装到一起

        - 隐藏数据:对外只暴露一些借口,通过接口访问对象

      ② 继承

        - 多复用,继承来的就不用自己写了

        - 多继承,少修改,OCP(Open-closed Principle)开闭原则,使用继承来改变,来体现个性

        - 可以多继承,Java不支持,C++ 支持

      ③ 多态

        -面向对象编程最灵活的地方,动态绑定

    4、Python的类

      定义:   

    1 class ClassName:
    2     pass
       必须使用class关键字
      类名必须是用大驼峰命名
      类定义完成后,就产生了一个类对象,绑定到了标识符ClassName上
    1 class MyClass:
    2     ''' A example class'''
    3     x = 'abc'
    4     def foo(self):
    5         return 'My Class'
    6     
    7 print(MyClass.x)
    举例

    5、类对象及类属性

      类对象:类的定义就会生成一个类对象,也就是说MyClass 就是一个对象

      类的属性:类定义中的变量和类中的方法都是类的属性

      类变量:举例中X 就是类MyClass的变量

         MyClass中x, foo 都是泪的属性,MyClass.__doc__,__doc__也是类的属性
         foo方法是类的属性,也叫方法,在类中 叫 method,普通函数 叫function,foo(self)中的self是一个惯用标识符,可以换别的,但是使用惯例,self指当前实例本身。

    实例化:
    1、a = MyClass() 每一次实例化,只能生产该类的一个对象
         2、使用上面的语法,在类对象名称后面加上一个括号,就调用类的实例化方法,完成实例化。
         3、实例化就真正创建一个该类的对象(实例)

    4、每次实例化,产生的都是不同的对象
    -----内存地址都不一样的对象
    1 a = MyClass()
    2 print(id(a)) # 43808192
    3 a = MyClass()
    4 print(id(a)) # 43808248
         5、Python类实例化后,会自动调用__init__ 方法,对实例初始化的方法:其他语言,也叫构造方法

    第一个参数,必须要留给self,是可以修改名字,但是习惯用self
    self:某个具体实例的本身,谁调用,就是谁!!!!!
    java中用的是this

    6、Python类实例化,一定调用__init__ 方法,可以定义,可以不定义,会隐式的调用父类的,自己定义,就是个性化
             作用:初始化
    先实例化,在初始化:
    类 --》 对象
    __new__ 是实例化,现在不用管
    对象 --》 给一个设定,比如颜色之类的,修饰
    __init__
    也就是说,实例化后,才能调用__init__ 方法

    ClassName() ---- 认为实例化和初始化是接近着的,实例化,马上自动初始化!!!

    7、__init__不能返回任何值,默认返回None

    6、实例对象instance
     1 class Person:
     2     x = 13 # 类属性
     3 
     4     # 方法是属于类的
     5     def __init__(self, name, age):  # Python解释器送过来的,也可以手动
     6         print('init',hex(id(self)))
     7         self.name = name # 实例属性
     8         self.age = age
     9 
    10     # 方法是属于类的
    11     def showage(self):
    12         return self.age
    13 
    14 print(Person)
    15 print('+++++++++++++++++++++++++++++++++++++++++++++++++')
    16 tom = Person('tom', 12)
    17 print(tom, hex(id(tom)))
    18 print(tom.name, '-------')
    19 print(tom.age)
    20 tom.age += 20
    21 print(tom.age)
    22 print(tom.showage(), '---------')
    23 print('++++++++++++++++++++++++++++++++++++++++++++++++++')
    24 jerry = Person('jerry', 16)
    25 print(jerry, hex(id(jerry)))
    26 print(jerry.name, '-----')
    27 print(jerry.age)
    28 jerry.age += 20
    29 print(jerry.age)
    30 print(jerry.showage(), '---------')
    31 
    32 
    33 # print(tom.showage())  == print(Person.showage(tom)) 等价
      类实例化后 一定会获得一个对象,就是实例对象
      类实例化后,得到一个实例对象,实例对象 会 绑定 方法,调用 方法时采用实例.方法名 的方式。
      但是函数签名是showage(self),这个self就是jerry,Python会吧方法的调用者作为第一参数seld的实参传入。
      self.name就是jerry 对象的name,name是保存在了jerry对象上,而不是Person类上,所以,称为实例变量

      


    7、实例变量和类变量:
        实例变量是每个实例自己的变量,是自己独有的:
        类变量是类的变量,是类的所有实例共享的属性和方法

                特殊属性:
    __name__:对象名
    类名, Person.__name__
    对象是没有的,但是 tom.__class__.__name__

    type() 等价 __class__
    ----所以 type('tom').__name__

                __class__:对象的类型


    ___dict__: 对象的属性的字典

    __qualname__:类的限定名
          注:
    对象可以调用类属性,类不能调用对象属性
           Python中每一种对象都拥有不同的属性,函数,类都是对象,类的实例也是对象。
      __dict__举例:
     1 class Person:
     2     age = 3
     3     def __init__(self, name):
     4         self.name = name
     5 
     6 
     7 print('-----class----')
     8 print(Person.__dict__)
     9 # {'__module__': '__main__', 'age': 3, '__init__': <function Person.__init__ at 0x000000000299F268>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    10 print(sorted(Person.__dict__.items()))
    11 # [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x000000000299F268>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]
    12 
    13 tom = Person('tom')
    14 print('------istance tom ------')
    15 print(tom.__class__)
    16 # <class '__main__.Person'>
    17 print(sorted(tom.__dict__.items()))
    18 [('name', 'tom')]
    19 
    20 print('---tom class---')
    21 print(tom.__class__.__name__)
    22 # Person
    23 print(sorted(tom.__class__.__dict__.items()))
    24 # [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', None), ('__init__', <function Person.__init__ at 0x000000000299F268>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 3)]
      注: 可以看到 类属性保存在类的__dict__ 中,实例属性保存在实例的__dict__ 中,如果从实例访问类的属性,就需要借助__class__找到所属的类

      举例:
     1 class Person:
     2     age = 3
     3     height = 170
     4 
     5     def __init__(self, name, age=1):
     6         self.name = name
     7         self.age = age
     8 
     9 tom = Person('tom')
    10 jerry = Person('jerry', 20)
    11 
    12 Person.age = 30
    13 print(Person.age, tom.age, jerry.age) # 30 1 20
    14 
    15 print(Person.height, tom.height, jerry.height) # 170 170 170
    16 jerry.height = 175
    17 print(Person.height, tom.height, jerry.height) # 170 170 175
    18 
    19 tom.height += 10
    20 print(Person.height, tom.height, jerry.height) # 170 180 175
    21 
    22 Person.height += 15
    23 print(Person.height, tom.height, jerry.height) # 185 180 175
    24 
    25 Person.weight = 70
    26 print(Person.weight, tom.weight, jerry.weight) # 70 70 70
    27 
    28 print(tom.__dict__['height'])
    29 print(tom.__dict__['weight']) # 报错,实例字典中没有这个key
    
    

      总结:

        是类的,也是这个类所有实例的,其 实例 都是可以访问到

        是实例的,就是这个实例自己的,通过类访问不到

        类变量是属于类的变量,这个类的所有实例可以共享这个变量

        对象(实例 或 类)可以动态的给自己增加一个属性,实例.__dict__[变量名] 和实例.变量名 都可以访问到

        实例的同名变量会隐藏掉类变量,或者说覆盖了这个类变量

     实例属性的查找顺序:
       指的是实例 使用. 点号来访问属性,会先找自己的__dict__, 如果没有,然后通过属性__class__找到自己的类,在去类的__dict__中找
       注意:如果实例 使用 __dict__[变量名]访问变量,将不会按照上面的查找顺序找变量了,这是指明使用字典的key查找,不是属性查找
          一般来说,类变量可使用全大写来命名



    8、装饰一个类(区别类装饰器)
     1 # no 1
     2 def foo(cls, name='jerry'):
     3     cls.NAME=name
     4     return cls
     5 @foo
     6 class Person1:
     7     AGE = 20
     8 print(Person1.__dict__['NAME'])
     9 
    10 # no 2
    11 def foo(name='jerry'):
    12     def wrapper(cls):
    13         cls.NAME=name
    14         return cls
    15     return wrapper
    16 
    17 @foo(name='tom') # Person=foo(name='tom)(Person)=wrapper(Person)
    18 class Person1:
    19     AGE = 20
    20 print(Person1.__dict__['NAME'])
      之所以能够装饰,本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象。         

    9、静态方法和类方法


        总结:
          类方法:
            1、在类定义中,使用@classmethod 装饰器修饰的方法
            2、必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象本身
            3、cls这个标识符可以是任意合法名称,但是不要改
            4、通过cls可以直接操作类的属性
              注意:无法通过cls操作类的实例,有类不一定有实例
          静态方法:
            1、在类定义中,使用@staticmethod装饰器修饰的方法
            2、调用时,不会隐式的传参
            3、只是表明这个方法属于这个名词空间,函数跪在一起,方便组织管理


    10、方法的调用
      

      
      总结:
        类几乎可以调用所有内部定义的方法,但是调用普通方法 时会报错,原因是第一参数必须是类的实例
        实例也几乎可以调用所有的方法,普通函数的调用一般不可能出现,因为不允许这么定义
        
        类除了普通方法都可以调用,普通方法需要对象的实例作为第一参数
        实例可以调用所有类中定义的放到(包括类方法,静态方法),普通方法传入实例自身,静态方法和类方法需要找到实例的类



    11、访问控制:
      1、私有属性(Private)
     1 # no1 原本是想通过控制方法,控制age,
     2 class Person:
     3     def __init__(self, name, age):
     4         self.name = name
     5         self.age = age
     6 
     7     def growup(self, i=1):
     8         if i>0 and i<100:
     9             self.age += 1
    10 
    11 p1 = Person('tom',12)
    12 p1.growup(20)
    13 p1.age = 160 # 但是超界了,还是会修改
    14 print(p1.age)
    15 
    16 # no2  __age 作为私有,双下划线
    17 class Person:
    18     def __init__(self, name, age):
    19         self.name = name
    20         self.__age = age
    21 
    22     def growup(self, i=1):
    23         if i>0 and i<100:
    24             self.__age += 1
    25 
    26 p1 = Person('tom',12)
    27 p1.growup(20)
    28 # print(p1.__age) # 获取不到,根本没有这样的一个属性,报错
    29 
    30 
    31 
    32 class Person:
    33     def __init__(self, name, age):
    34         self.name = name
    35         self.__age = age
    36 
    37     def growup(self, i=1):
    38         if i>0 and i<100:
    39             self.__age += 1
    40 
    41     def getage(self):
    42         return self.__age
    43 
    44 p1 = Person('tom',12)
    45 p1.__age = 1000 # 这个是自己另外给p1实例增加了一个__age 属性,并不是私有的属性
    46 print(p1.__age) # 1000
    47 print(p1.getage()) # 12
    48 
    49 
    50 print(p1.__dict__)
    51 # {'name': 'tom', '_Person__age': 12, '__age': 1000}
    52 # 看字典就明白了
    53 # 事实上,私有的是修改了名字, _Person__age
    54 # 知道了这个名字 可以直接修改了
    55 p1._Person__age = 10
    56 print(p1.getage()) # 10
      2、保护变量:
     1 class Person:
     2     def __init__(self, name, age):
     3         self.name = name
     4         self._age = age
     5 
     6     def growup(self, i=1):
     7         if i>0 and i<100:
     8             self.age += 1
     9 
    10 tom = Person('tom',12)
    11 print(tom._age) # 12
    12 print(tom.__dict__) # {'name': 'tom', '_age': 12}

          可以看出,这个_age 属性根本就有没改变名称,和普通的属性一样,解释器不做任何特殊处理,这只是开发者共同的约定,不要直接使用

    12、私有方法:类似私有属性

     1 class Person:
     2     def __init__(self, name, age):
     3         self.name = name
     4         self.age = age
     5 
     6     def _getname(self):
     7         return self.name
     8 
     9     def __getage(self):
    10         return self.age
    11 
    12 
    13 tom = Person('tom',12)
    14 # print(tom.__getage()) #报错,没有
    15 print(tom._getname())
    16 print(tom.__dict__)
    17 print(tom.__class__.__dict__)
    18 print(tom._Person__getage())
    19 
    20 # tom
    21 # {'name': 'tom', 'age': 12}
    22 # {'__module__': '__main__', '__init__': <function Person.__init__ at 0x000000000297C8C8>, '_getname': <function Person._getname at 0x00000000029402F0>, '_Person__getage': <function Person.__getage at 0x0000000002992840>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
    23 # 12

    13、补丁:

      可以通过修改或者替换类的成员,使用者调用的方式没有改变,但是,类提供的功能可能已经改变了

      猴子补丁(Monkey Patch)

      在运行时,对属性,方法,函数等进行动态替换

      其目的往往是为了通过替换,修改来增强,扩展原有代码的能力

      慎用!!!!!!

        之前:

        之后:

    14、属性装饰器:

      一般好的设计是:把实例的属性保护起来,不让外部直接访问,外部使用getter读取属性和setter方法设置属性

     1 # 普通方式
     2 class Person:
     3     def __init__(self, name, age=18):
     4         self.name = name
     5         self.__age = age
     6 
     7     def age(self):
     8         return self.__age
     9 
    10     def set_age(self, age):
    11         self.__age = age
    12 
    13 tom = Person('tom')
    14 print(tom.age()) # 18
    15 tom.set_age(20)
    16 print(tom.age()) # 20
    17 
    18 # 装饰器方式
    19 class Person:
    20     def __init__(self, name, age=18):
    21         self.name = name
    22         self.__age = age
    23 
    24     @property
    25     def age(self):
    26         return self.__age
    27 
    28     @age.setter
    29     def age(self, age):
    30         self.__age = age
    31 
    32     @age.deleter
    33     def age(self):
    34         print('del')
    35 
    36 tom = Person('tom')
    37 print(tom.age) # 18
    38 tom.age = 30
    39 print(tom.age) # 30

      特别注意:使用property装饰器的时候这三个方法同名

        其他写法:

        还可以如下:使用了匿名函数,但是set没办法,因为匿名函数条件不能出现等号

    15、对象销毁

      类中可以定义__del__ 方法,称为析构方法(函数)

      作用:销毁类的实例的时候调用,以释放占用的资源,其中就放些清理资源的代码,比如释放链接,关闭文件句柄

      注意这个方法不能疫情对象的真正的销毁,只是对象销毁的时候会自动调用它.

      使用del 语句删除实例,引用计数减1, 当引用计数为0 时,会自动调用__del__方法。

      由于Python实现了垃圾回收机制,不能确定对象何时执行垃圾回收

      注:由于垃圾回收 对象销毁时,才会真正清理对象,还会在回收对象之前自动调用__del__ 方法,除非你明确自己的目的,建议不要手动嗲用这个方法

    16、方法重载(overload)

      在Java,等语言中,会有重载的概念

      所谓重载 ,就是同一个方法名,但是参数数量,类型不一样,就是同一个方法的重载。

      Python没有重载,也不需要重载,*args可以解决多参,且强类型,动态语言,不需要指定参数类型

    17、封装

      面向对象的三要素之一,封装Encapsulation

      封装:

        将数据和操作组织到类中,即属性和方法

        将数据隐藏起来,给使用者提供操作(方法), 使用者通过操作就可以获取或者修改数据,getter和setter。

        通过访问控制,暴露适当的数据和操作给用户,该隐藏的隐藏起来。

    为什么要坚持,想一想当初!
  • 相关阅读:
    WinForm简单进度条
    金庸群侠传 3小时爆机
    One Day
    css组件化
    PHP判断端口是否打开的代码
    PHP下像JQUery下查找修改HYML元素的类PHP Simple HTML DOM Parser
    兼容IE和FF的添加收藏和设为主页代码
    注册成功啦,终于在博客园注册成功了,以后要更加努力的学习技术啊!
    ppz css栅格框架
    使用live writer 发布一下日志
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9643857.html
Copyright © 2011-2022 走看看