python 面向对象编程
1. 类的 __new__() 方法
定义一个类时,可以用__init__函数来设置类具有的属性,但实际上最先执行的是 __new__ 函数,通过该函数,返回一个
类的实例,这也是为什么init函数有self参数的原因。
class Animal(object):
def __new__(cls,*args,**kw):
return Animal.__new__(cls,*args,**kw)
2. 类的 __del__方法
在该对象被销毁时自动调用__del__方法,可重写print试试。但是实际上,用cmd和sublime,pycharm编译器执行脚本时,并非
销毁对象时执行__del__,而是在实例化对象时执行的;只有在python自带的IDE中才会在销毁对象时执行,我也不知道为什么。
3. 公有和私有属性,方法
python 的类中,如果有一些属性不想给外部权限来访问或者修改,可以在属性或者方法的名字前加俩下划线__,声明为
私有属性。则在外部调用该属性时返回ValueError.
使用场景:如果想只给外部访问的权限,不给修改的权限。可以在类里头定义一个 返回 属性的函数class girl(object) def __init__(self,name,phone): self.name = name self.__phone = phone Mary = girl("马力",110)
class girl(object) def __init__(self,name,phone): self.name = name self.__phone = phone def want_her_phone(self): print(self.__phone) Mary = girl("马力",110) Mary.want_her_phone() >> 110
使用场景2:给与外部访问与修改权限,但修改值应按照设计的范围来。
另外:实际上私有变量的工作原理是将变量名改为: _类名__变量名,仍可以通过这个来调用。class girl(object): def __init__(self,name): self.name = name self.__phone = 12312312312 def want_her_phone(self): print(self.__phone) return self.__phone def change_phone(self,new): if len(str(new)) != 11 or str(new)[:3] not in ['153','138','157','183']: raise ValueError('you cheat me!') self.__phone = new Mary = girl("玛丽") Mary.change_phone(15734567654) >> 修改phone 属性
在属性名前只加一个下划线 _ 也算私有属性,但仍然能访问和修改,但尽量别改。class girl(object) def __init__(self,name,phone): self.name = name self.__phone = phone Mary = girl("马力",110) print(Mary._girl__phone)
4. 注解 @property
从上几个例子可以看出,想要对对象的属性值设定一定的范围,就得用到函数,修改时要 obj.method(),代码很长很不爽,此时
使用装饰器@property可以让你直接跟用属性一样,直接点 . obj.attr = x。
语法是:先定义两个函数,函数名为属性名,第一个函数返回属性值,第二个函数修改属性值。然后在第一个函数头上写个
@property, 在第二个函数头上写个 @属性名.setter就行
5. 类的打印信息class girl(object): def __init__(self): self.__age = 30 @property def age(self): return self.__age @age.setter def age(self,value): if not isinstance(value,int): raise ValueError('must be int!') if value > 28 or value < 18: raise ValueError("Is it not pretty enough for you?") self._age = value a = girl() a.age = 35 # 不符合范围,报错 print(a.age)
如果类直接打印 print(girl()) 会出现一个内存地址,不仅没用而且让人看起来很迷惑。我们可以使用 __str__函数来修改
类的打印信息,打印出我们想让它显示的内容。
6. 引用统计class girl(object): def __str__(self): return "这是一个类" print(girl()) >>这是一个类
先引入sys模块,import sys。然后sys.getrefcount(obj),返回被引用的次数。
7. 类方法,静态方法import sys print(sys.getrefcount(int))>>69次sys模块里
@staticmethod
通常情况下,在类中定义的所有函数都是对象的绑定方法,对象在调用绑定方法时会自动将自己作为
参数传递给方法的第一个参数。但是静态方法就不会把自己传进去,相当于一个全局函数样的:
@classmethodclass A(object): @staticmethod def fn1(): print("haha") A.fn1() >> haha a = A() a.fn1() >> haha
与实例方法相似,只不过首个参数会自动接收类对象,类对象可以调用。但实际上,实例对象也能用,
会把自己的父类传入第一个参数。
另外,类中定义的实例方法,即正常定义的方法,类对象也能调用,只不过会当成一个普通函数,第一个参数并不会自动class A(object): @classmethod def fn2(cls,a,b): # cls跟self一样,只是为了语义化,可以用任意的字符 print(cls,a,b) A.fn2(1,2) >><class '__main__.A'> 1 2 a = A() a.fn2(3,4) >><class '__main__.A'> 3 4
接收实例对象,包括self,定义了几个参数,就要给几个参数。
4 三个特性class A(object): def fn3(self,a,b): print(self,a,b) A.fn3(1,2,3) >> 1,2,3 a = A() a.fn3(123,12) >> <__main__.A object at 0x007306F0> 123 12
面对对象的三个特性为: 封装,继承,多态。
封装: 应该注意到了,类的定义格式很像函数,将一大堆代码写在类的肚子里,如果有多个对象很多特征相似,可以
把这些特征封装进一个类中。
继承: 类有继承的功能,所谓继承就是从一个类里头实例化一个对象,你没写这个对象的属性方法,这个对象从他的类中
得到了所有的属性方法,可以直接调用。
class dog(object): def __init__(self) self.leg = 4 def attack_method(self): print("the dog is bitting!") gou = dog() # 实例对象gou 从类 dog 中继承了所有的属性和方法 gou.leg >> 4 gou.attack_method() >> the dog is bitting!
类也能继承,一个类定义的时候,括号中有个object参数,表示从 python 自带的object类中继承相应的属性以及方法。
同样的,也能从其他类中继承属性和方法
多重继承,有时候一个对象不仅有这个类的特性,还有那个类的特性,此时可以可以定义一个类,继承多个类。class animal(object): def __init__(self): self.look = "cute" class dog(animal): def looklike(self): print(self.look) # 调用了未定义的 look 属性 gou = dog() gou.looklike() >> cute gou.look >> cute # dog中未定义的属性
多态:class animal(object): def __init__(self,color): self.color = color class dog(object): def __init__(self,name): self.name = name def wang(self): print("汪!") class village_dog(animal, dog): pass # 从animal和dog中继承 gou = village_dog("黄色") gou.color >> "黄色" gou.wang() >> "汪!" # 要注意的是,animal和dog中都有 init 函数,init函数只会执行一个,就近选择,如果自身有用自己的,自己没,用参数里靠前的那个类的
多态这个特性是理所当然的,A类继承自B类,B类有继承自C类,C类甚至继承自D和E类。则从A类实例化后的对象,判断类型时,可以是 A,B,C,D,E 类,针对这些类定义的函数他都能用,这就是多态。
class animal(object): def __init__(self,color): self.color = color class dog(object): def __init__(self,name): self.name = name def wang(self): print("汪!") class village_dog(animal, dog): pass # 从animal和dog中继承 gou = village_dog("sdfa") isinstance(gou,dog) >> True isinstance(gou,animal) >> True # isinstan 判断是否为XX类型 如果用type 则只显示 village 类
4.实例属性和类属性
实例属性就是__init__绑定的那些属性,类属性是在类里头直接写:attr = value,就设置了一个类属性。
5 类的一些操作方法但是实例会继承类的这个属性,实例重写时覆盖。
dir(obj) 显示类的所有属性和方法修改/添加属性,方法 : 直接点 . obj.haha = "哈哈" obj.asdf = lambda x: return x+1hasattr(obj,attr)getattr(obj,attr,default) default为找不到时默认返回,不写的话,找不到时报错setattr(obj,attr,value)