• python0.16------构造函数/析构函数/self详解/重写/访问限制/对象属性和类属性/@property/运算符重载


    构造函数:__init__()
    引子:因为每个人一出生都是不一样的。因此,如果在Person类中直接给类元素赋值有问题,它会导致每个人的初始状态相同,这不符合大自然的逻辑。应该根据每个人的特点,给每个出生的人不一样的特性。可以通过构造函数实现这个想法。__init__()函数在使用类创建对象自动调用。注意:如果不显式写出构造函数,默认会添加一个空的构造函数。 

    使用构造函数:
    def __init__(self,name,age,height,weight):#一般定义属性在构造函数里面定义。
      self.name=name #self.name表示给当前对象创造一个属性。
      self.age=age #self.age表示给当前对象创造一个属性。
      self.height=height #self.height表示给当前对象创造一个属性。
      self.weight=weight #self.weight表示给当前对象创造一个属性。
      #当在person后面加实参时,实际上是调用了__init__()函数。

    #调用

    per1=Person('qie',18,180,60)。
    per2=Person('bob',22,170,65)。
    这样,per1和per2在出生的时候就不一样了。


    析构函数:(编程时用得很少)
    __del__() 表示释放对象时自动调用。
    对象释放的原理:引用计数器原理。在创建对象的时候,有一个属性num=1,当有一个地方要用它,就有一个强指针指向它,num+1,释放一个强指针,num-1。当num为0时,系统自动释放这个对象。然后会调用析构函数。
    当程序结束时,对象会被释放,会调用析构函数。
    若强制释放对象,用del指令。然后系统会调用析构函数。
    再函数里面定义的对象,会在函数结束时自动释放,这样可以用来减少内存空间的浪费。然后调用析构函数。

    self详解:
    self不是关键字,self可以由任何标识符代替,但是一般都用self。
    self代表类的实例而非类。
    哪个对象调用方法,那么该方法中的self就代表哪个对象。
    self.__class__ 代表类名,只能在类的定义里面使用哦
    例如:
    def run(self):
    per=self.__class__('bob',1,1,1)
    print(per)
    表示在run方法里面创建一个对象叫做per。


    重写:将类定义的方法重新写一遍。

    引子:如果一个对象,有100个属性,想把它们都打印出来,那么一般来说应该写成:print(per.a,per.b,per.c,per.d,..........,per.n100)。但是属性太多,这样输出写代码很累。如果能够用print(per)直接打印出所有属性就好了。因此,重写__str__()和__repr__()就能够满足要求.

    例如:重写__str__()和__repr__()方法
    __str__()方法  #它是给程序员用的,在调用执行print(对象名)时会被自动调用。
    __repr__() 方法  #它是给机器用的,在python解释器里直接敲对象名后回车调用的。例如:在黑屏终端里面,直接敲per对象,就会调用__repr__()。

    注意:1: __str__(),__repr__()需要返回值,返回值直接取代print里面的per!!!同时,若是没有定义__str__()方法,只定义了__repr__()方法,那么调用print(per)时会调用__repr__()方法。

    访问限制:
    如果我这个对象有100块钱的属性,如果在类的外面可以直接修改,那么别人可以轻松篡改我的零钱金额。这样显然不合理.要让对象的属性不在外部直接访问.那么可以在属性前面加上两个下划线。在python中如果在属性前面加上两个下划线,那么这个属性就相当于变成了私有属性(private)。在外部不能访问私有变量,在类内部可以访问私有变量。
    可以在类里面更改money,通过自定义的方法对私有属性赋值和取值:
    例如:一个类有一个私有变量__money
    def getMoney(self):
      return __money
    def setMoney(self,money):
      if money<0:
        self.__money=0
      else:
        self.__money=money

    不能直接访问 per.__money 是因为python解释器把 __money 解释成了 __Person__money ,若直接访问__Person__money,就可以成功。但是强烈建议不要这么做。而且不同版本的解释器可能存在解释的变量名不一致的忧患。

    在python中 __XXX__ 属于特殊变量,不是私有变量,特殊变量的值可以直接访问。表示系统已经写好了,有一些特殊的含义。

    在python中 _XXX 变量,外部也是可以访问的。但是,按照约定的规则,当我看到这样的变量时。意思是‘虽然我可以被访问,但是请把我视作为私有变量,不要直接访问我。

    对象属性和类属性:

    类属性:
    class Person(object):
      name="person" #类属性
      def __init__(self,name):
        self.name=name #对象属性

    对象属性的优先级高于类属性。不要将对象属性与类属性同名。因为对象属性会屏蔽掉类属性。但是当删除对象属性后,再使用又会调用类属性。这样类属性就不可控。

    可以动态的给对象添加对象属性,只针对当前对象生效,对于类创建的其它对象没有作用。
    例如:
    class Person:
      pass
      person=Person()
    #动态添加属性:
    person.name='bob'

    #动态添加方法:
    先引入types类的 MethodType()方法
    from types import MethodType() #偏函数,相当于将对象自己传进去
    def say(self):
      print('my name is '+self.name)
    per.speak=MethodType(say,per) #此时per对象就有了speak方法。其实MethodType()函数就是一个偏置函数,让say函数self默认赋值为对象名,再将修改后的函数赋值给speak变量。

    注:如果想要限制实例的属性只允许为name,age,weight,其它的属性不能添加。那么在定义类的时候,可以定义一个特殊的属性(__slots__)。可以限制动态添加的属性。
    例如:
    class Person:
      __slots__=('name','age') #这样只能动态地增加name,age两个属性,包括方法。例如:人不会飞,因此不能给人飞的方法。

    property:
    用 对象.属性 访问和改变对象属性 比 对象.方法() 去改变和访问对象的属性要方便。
    例如:
    class Person:
      def __init__(self,age):
        self.__age=age
    @property #访问
    def age(self):
      return self.__age
    @age.setter #修改
    def age(self):
      if self.__age<0
        self.__age=0
      else:
        self.__name=age

    print(per.age)   #相当于getAge()
    per.age=1   #相当于SetAge(1)
    注意,这并不等于直接操作私有变量,因为私有变量的赋值是有限制的。

    运算符重载(‘+’运算符重载最常用):

    引子:print(1+2) 输出3
    print('1'+'2') 输出‘12’  #说明不同类型用加法会有不同的解释,也就是'+'运算符在不同类型的对象中有不同的作用,即'+'运算符在每个类里面都进行了重载。

    #然而,新建一个自定义的类person的实例,却不能进行相加,为什么呢?因为没有进行运算符重载!!!
    per1=person(1)
    per2=person(2)
    print(per1+per2)   #输出错误,因为'+'没有对person类型的解释。

    #解决方法:

    def __add__(self,other):
      return Person(self.num+other.num)   #运算符重载,记住一定要返回一个值哦,这里返回的是一个初始值为3的对象哦。
    def __str__(self):
      return 'num='str(self.num)    #重写__str__()方法,目的是当调用print(对象)时,直接打印有关对象的一些值。

    调用:print(per1+per2)等价于print(per1.__add__(per2))

     

     

  • 相关阅读:
    [Effective JavaScript 笔记] 第7条:视字符串为16位的代码单元序列
    [翻译]CSS模块-未来的编码方式
    [Effective JavaScript 笔记] 第6条:了解分号插入的局限
    [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
    [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
    [翻译]理解CSS模块方法
    [翻译]纠正PostCSS的4大认识误区
    [翻译]Gulp.js简介
    [Effective JavaScript笔记]第3条:当心隐式的强制转换
    [翻译]在gulp构建工具中使用PostCSS
  • 原文地址:https://www.cnblogs.com/yulianggo/p/9219288.html
Copyright © 2020-2023  润新知