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))

 

 

猜你喜欢

转载自www.cnblogs.com/yulianggo/p/9219288.html