zoukankan      html  css  js  c++  java
  • 面向对象初接触(上)

    面向对象是一种认知世界,分析世界的方法论,将万事万物抽象为类
    类class :类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合,在计算机语言里就是 属性和方法的集合
     
    对象instance object
    对象是类的具象,是一个实体
     
    属性,他是对象状态的抽象,用数据结构来描述
    操作,他是对象行为的抽象,用操作名和实现该操作的方法来描述
     
    哲学:
    一切皆对象
     
    对象是数据和操作的封装
     
    对象是独立的,但是对象之间可以相互作用
     
     
    目前OOP是最接近人类认知的编程方式
     
     
     
    面向对象3要素
    1,封装
         组装将数据和操作组装到一起
         隐藏数据:对外只暴露一些接口,通过接口访问对象
     
    2,继承
         多复用,继承来的就不用自己在写
         多继承少修改,OCP,     使用继承来改变,来体现个性
     
    3,多态
         面向对象编程最灵活的地方,动态绑定
     
    python的类
    定义 class ClassName :
         语句块
    1,必须使用class关键字
    2,类名必须是大驼峰命名
    3,类定义完成后,就产生了一个类对象,绑定到了ClassName上
     
    例子(1,0)
    class MyClass : 
         """ A example class"""
         x = 'abc'          #类属性
         def foo(self) :      #类属性foo 也是方法
              return 'My Class'
    print(MyClass.x)
    print(MyClass.foo)
    print(MyClass.__doc__)
     
    类对象及类属性
         类对象,类的定义就会生成一个类对象     
         类的属性, 类定义中的变量和类中定义的方法都是类的属性
         类变量,x是MyClass的变量
     
    MyClass中,x,foo都是类的属性,__doc__也是类的属性
     
    foo方法是类的属性,需要实例的调用才能使用
     
    foo是method方法对象,不是普通的函数对象function了,他至少有一个参数,且第一个参数必须是self(self可以换名字),整个参数位置就留给了self
     
    self      指代当期实例本身
     
    实例化
     
    a = MyClass(  ) #实例化
     
    使用这个语法就 在类对象名称后面加上一个括号,就调用类的实例化方法,完成实例化
     
    实例化就真正创建一个该类的对象(实例),例如 tom jerry
     
    实例化后获得的实例,是不同的实例,即使是使用同样的参数实例化,也得到不同的对象
     
    python类实例化后,会自动调用__init__方法,整个方法第一个参数必须留给self , 其他参数任意
     
     
    例子(1,1):
     
    class Person:                            #定义类
     
       age = 20                              #类的属性
     
       def __init__(self,name):          #初始化属性值,也是类的方法or属性
            self.name = name
     
       def foo(self):                        #类的方法
            return 'Person'
     
    Person.age = 353                    #可在外部通过类直接修改其内部的属性
     
    tom = Person('tom')               #实例化!!!!!!!!!
     
    jerry = Person('jerry')              #实例化 , 不是一个对象,它们的id不一样
     
    print(tom.age ,jerry.age)         #若初始化后没有age整个元素,那么就会去类的内部查找;
     
                                                 # 若类里没有,会直接new一个类属性到类的属性字典中
    #print(Person.name)              #类没有名字
     
    print(Person.__dict__)             #查看Person类的属性字典
     
    print(tom.foo())                     #如何去调用一个类里面的类的方法
     
    Pe = Person( )                       #会 调用__init__
     
    __init__方法
    例子(1,1)中 : 
     
    Pe实际上调用的是__init__(self)方法,可以不定义,如果没有定义,会在实例化后隐式调用
    他的作用: 对实例初始化
    !!!注意:
    初始化函数可以有很多的参数,但是第一个位置必须是 self,例如init(self,name,age)
    __init__( ) 方法不能有返回值,也就是说只能是None!
     
    实例对象instance
     
    类实例化后一定会获得一个对象,就是实例对象
    (1,1)中,tom jerry就是Person类的实例
     
    __init__方法的第一参数self就是指代某一个实例
     
    类实例化出一个实例对象,实例对象会绑定方法,调用对象时会采用 jerry.showage( )的方式
     
    定义的showage(self)这个self就是jerry,python会把方法的调用者作为第一参数self的实参传入
     
    self.name就是jerry对象的name , name是保存在了jerry对象上,而不是在Person类上,所以称为实例变量
     
    self
    class Person:
       def __init__(self):
            print('{}'.format(id(self)))
     
    c = Person()     #会调用__init__
    print('c ={}'.format(id(c)))
    打印结果为:
    2322420470280
    c =2322420470280
    上例说明,self就是调用者,就是c对应的实例对象
    self 整个名字只是一个管理,它可以修改,为了代码的可读性,不要去修改
     
    实例变量和类变
     
    实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法
     
                                                特殊属性
                                               含义
    __name__
    对象名
    __class__
    对象的类型
    __dict__
    对象的属性的字典
    __qualname__
    类的限定名
     
    举例
    class Person:
         age =3
         height =170
         def __init__(self,name,age=18):
              self.name = name
              self.age = age
     
    tom = Person('tom')
    jerry = Person('jerry',20)
    Person.age = 30
    print(Person.age,tom.age,jerry.age)
    print(tom.height,jerry.height,Person.height)
    jerry.height = 175 #修改jerry字典中的数据
    print(Person.height,tom.height,jerry.height)
    tom.height += 10
    print(Person.height,tom.height,jerry.height)
    Person.height +=15
    print(Person.height,tom.height,jerry.height)
    Person.weight = 70
    print(Person.weight,tom.weight,jerry.weight)
     
    print(tom.__dict__['height'])
    print(tom.__dict__['weight']) #weight属于类的字典里的属性,不属于tom的字典里的属性,所以会出错
    class Person:
       age =3
       height =170
       def __init__(self,name,age=18):
            self.name = name
            self.age = age
     
    tom = Person('tom')
    jerry = Person('jerry',20)
    Person.age = 30
    print(Person.age,tom.age,jerry.age)
    print(tom.height,jerry.height,Person.height)
    jerry.height = 175 #修改jerry字典中的数据
    print(Person.height,tom.height,jerry.height)
    tom.height += 10
    print(Person.height,tom.height,jerry.height)
    Person.height +=15
    print(Person.height,tom.height,jerry.height)
    Person.weight = 70
    print(Person.weight,tom.weight,jerry.weight) #tom和jerry的属性字典里没有weight元素,会在类的属性里查找
     
    print(tom.__dict__['height'])
    print(tom.__dict__['weight']) #weight属于类的字典里的属性,不属于tom的字典里的属性
    #总结
    #是类的,也是这个类所有实例的,其实例都是可以访问到的;是实例的,就是这个实例自己的,通过类访问不到
    #类的变量,类下的方法都可以拿来用,但是不存在于类下的方法字典
    #类变量是属于类的变量,这个类的所有实例可以共享这个变量
    #实例可以动态的给自己增加一个属性。实例.__dict__[变量名]和实例.变量名都可以访问到
    #实例的同名变量会隐藏这类变量,或者说是覆盖了这个类变量
     
    实例属性的查找顺序
     
    #指的是实例使用.来访问属性,会先找自己的__dict__,如果没有,通过属性__class__找到自己的类,再去类的.__dict__中找
    #如果实例 使用__dict__[变量名]访问变量,就不会按照上面的查找顺序找变量了
    #一般来说 , 类变量使用全大写来命名
     
    #装饰一个类
    #增加类的变量
    # def add_name(name,clz):
    #       clz.NAME = name #动态增加属性
    #改成装饰器
    # def add_name(name):
    #         def add_arg(clz):
    #             clz.NAME = name
    #             return clz
    #         return add_arg
    #
    # @add_name('tom')
    # class Person:
    #         AGE = 3
    #
    # print(Person.__dict__)
    #之所以能够装饰,本质上是为类对象动态的添加了一个属性,而Person这个标识符指向这个类对象
     
    #类方法和静态方法
    #前面的例子中定义的__init__等方法都是类的属性第一个参数必须是self。而self必须指向一个对象,也就是类必须实例化之后,由实例来调用这个方法
     
    #普通函数:
    class Person:
       def normal_method(self):
       print('nomal')
     
    print(Person.__dict__)
     
    Person.normal_method()
    #这个方法只是被Person这个名词空间管理的一个普通的方法,normal_method这是Person的一个属性而已
    #由于normal_method 在定义的时候没有指定self,所以不能完成实例对象的绑定,不能用Person().normal_method()调用
    # !虽然语法没问题,但是没人这么写,所以禁止这样写
     
    # 类方法
     
    class Person:
       @classmethod
       def class_method(cls):
             print('class={0.__name__}{0}'.format(cls))
             cls.HEIGHT = 170
     
    Person.class_method()
    print(Person.__dict__)
    #类方法
      #1,在类定义中,使用@classmethod装饰器修饰的方法
      #2,必须至少有一个参数,且第一个参数留给了cls,cls指代调用者即类对象自身
      #3,cls这个标识符可以是任意合法名称,但是为了易读,请不要修改
      #4,通过cls可以直接操作类的属性,但是不能操作类的实例
     
    #静态方法
    # class Person:
    #    @classmethod
    #     def class_method(cls): #cls是啥?
    #             print('class = {0.__name__}{0}'.format(cls))
    #             cls.HEIGHT = 170
    #
    #         @staticmethod #静态方法
    #         def static_methd():
    #             print(Person.HEIGHT)
    #Person.class_method()
    #Person.static_methd()
    #print(Person.__dict__)
    #静态方法
    # 在类定义中,使用@staticmethod装饰器修饰的方法
    # 调用时,不会隐式的传入参数
      #静态方法,定位于类定义的命名空间中,他不会对任何实例类型进行操作,类对象和实例都可以调用静态方法
     
    #方法的调用
    #怎么去调用一个类方法
    # class Tu:
    #      def __init__(self,name,age =18):
    #             self.name = name
    #             self.age = age
    #         def hi(self): #实例方法会去外部调用缺省的参数
    #             print(self.name)
    # print(1,Person.normal_method()) #可以调用,并执行normal_method()方法,
    # print(2,Person.method()) #需要一个实例参数
    # print(3,Person.class_method()) #可以调用,因为动态方法,将其类本身传给了这个方法
    # print(4,Person.static_methd()) #静态属性不能调用类或者实例的方法
    # x = Tu('heihei')
    # print(x.hi())
    类对象可以调用类方法,类对象不能调用实例的方法;
    实例对象可以调用类方法,和实例的方法
    实例方法,第一个参数必须默认传实例对象,一般习惯用self
    静态方法,参数没有要求     静态方法可以在其内部定义需要做的操作,因此可以不需要特定的去传参数
    类方法,第一个参数默认必须是传 类 ,一般习惯用cls
     
    #访问控制
    #私有属性
    # class Person:
    #         def __init__(self,name,age=18):
    #             self.name = name
    #             self.age = age
    #         def group(self,i = 1):
    #             if i >0 and i < 150: #控制逻辑
    #                 self.age += i
     
    # p1 = Person('tom')
    # p1 .group(20) #正常的范围
    # p1.age = 160 # 超过了范围,并绕过了控制逻辑
    # print(p1.age)
     
    #本来是想控制属性范围,结果在外界直接就被绕过逻辑直接改了,这样非常危险。但是python给我们提供了相关的解决办法
     
    #私有属性
    #使用双下划线开头的属性名,就是私有属性
    # class person:
    #         def __init__(self,name,age= 18):
    #             self.name = name
    #             self .__age = age
    #         def group(self,i = 1):
    #             if i >0 and i<150:
    #                 self.__age += i
    # p1 = person('tom')
    # p1.group(20)
    # print(p1.__age)
    #外部已经访问不到__age了,怎么访问这个变量呢?
    # class Person:
    #         def __init__(self,name,age=18):
    #             self.name = name
    #             self.__age = age
    #         def group(self,i=1):
    #             if i > 0 and i<150:
    #                 self.__age+=i
    #         def getage(self):
    #             return self.__age
    #
    #
    # print(Person.getage.__dict__)
    #如何动态的增加一个看不到的参数呢?
    # class Person:
    #         def __init__(self,name,age =18):
    #             self.name = name
    #             self.__age = age
    #
    #         def growup(self,i=1):
    #             if i> 0 and i <150:
    #                 self.__age += i
    #         def getage(self):
    #
    #             return self.__age
    #
    # p1 =Person('tom')
    # print(p1.growup(20))
    # p1.__age = 28
    # print(p1.__age)
    # print(p1.getage())
    # print(type(p1))
    # print(p1.__dict__)
    #私有变量的本质
    #类定义的时候,如果声明一个实例变量的时候,使用双下划线,Python解释器会将其改名,转换名称为_类名__变量名的名称,所以用原来的名字访问不到
    #但是直到了私有变量的名称后,通过实例还是可以对其的属性进行修改
     
    #保护变量
    #在变量名前使用一个下划线,称为保护变量
    # class Person:
    #         def __init__(self,name,age = 18):
    #             self.age = age
    #             self._name =name #保护变量
    #
    # tom = Person('tom')
    # print(tom._age)
    # print(tom.__dict__)
    #可以看出,这个_age属性根本就没有改变名称,和普通的属性一样,解释器不做任何处理,是开发者的约定
     
    #私有方法
    #和保护变量差不多,多了双下划线命名
    class Person:
      def __init__(self,name,age=18):
      self.name = name
      self._age = age
     
      def _getname(self):
      return self.name
     
      def __getage(self):
      return self._age
    tom = Person('tom')
    # print(tom._getname()) #没改名4
    # print(tom.__getage()) #没有这个属性
    print(tom.__dict__)
    print(tom.__class__.__dict__)
    print(tom._Person__getage()) #改名了
    #私有方法的本质,单下划线的方法只是开发者之间的约定,解释器不做任何结婚死
    #双下划线的方法,是私有方法,解释器会改名,改名策略和私有变量有关,_类__变量名
    #方法变量都可以在类的__dict__中找到
     
    #总结:
    #在Python中使用_单下划线或者__双下划线来标识一个成员被保护,或者被私有化隐藏了起来
    #Python没有绝对的安全的保护成员或者私有成员,并不能真正的阻止用户修改类的成员
    #前导的下划线只是一种警告或者提醒,一般都是遵守约定,除非真有必要,不要修改或者使用保护成员或者私有成员
    相关参考网站:
    https://github.com/pythonpeixun/article/blob/master/python/python_classmethod_staticmethod.md#%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E7%B1%BB%E6%96%B9%E6%B3%95%E4%BD%BF%E7%94%A8%E5%8C%BA%E5%88%AB%E6%88%96%E8%80%85%E8%AF%B4%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF
    面对对象多态参考网站:
    blog.csdn.net/shangzhihaohao/article/details/7065675
  • 相关阅读:
    POJ 3259 Wormholes【BellmanFord】
    POJ 2960 SNim【SG函数的应用】
    ZOJ 3578 Matrixdp水题
    HDU 2897 邂逅明下【bash博弈】
    BellmanFord 算法及其优化【转】
    【转】几个Java的网络爬虫
    thinkphp 反字符 去标签 自动加点 去换行 截取字符串 冰糖
    php 二维数组转 json文本 (jquery datagrid 数据格式) 冰糖
    PHP 汉字转拼音(首拼音,所有拼音) 冰糖
    设为首页与加入收藏 兼容firefox 冰糖
  • 原文地址:https://www.cnblogs.com/spidermansam/p/7822198.html
Copyright © 2011-2022 走看看