• 面向对象初接触(上)


    面向对象是一种认知世界,分析世界的方法论,将万事万物抽象为类
    类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
  • 相关阅读:
    javascript中的时间控制函数
    javascript在事件监听方面的兼容性总结
    javascript程序库比较(二):事件处理
    又要开始了
    ASP.NET怎么防止多次点击提交按钮重复提交
    asp.net中ashx文件如何调用session
    Session超时和丢失,如何让Sessioon永不过期
    组件
    csss
    C# JSONHelper之Json转换方法大全
  • 原文地址:https://www.cnblogs.com/spidermansam/p/7822198.html
Copyright © 2020-2023  润新知