Python - 面向对象
-
类和实例
面向对象最重要的概念就是类(Class)和实例(Instance)。类是对象抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都有相同的方法,但各自的数据可能不同。
Python类提供了面向对象编程的所有标准功能:类继承机制允许多个基类,派生类可以重写其基类或类的任何方法,并且方法可以调用具有相同名称的基类的方法
对象可以包含任意数量和种类的数据,与模块一样,类也具有Python的动态特性,它们是在运行时创建的,并且可以在创建后进一步修改。
对象:通过类定义的数据结构实例,对象包括两个数据成员(类变量和实例变量)和方法
-
定义类
#所有员工的基类 class Employee: #empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。可以在内部类或外部类只用Employee.empCount访问。 empCount=0 __cost=20000 #类的私有变量,只能在类中,通过调用行为使用 #方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法 def __init__(self,name,salary): self.name=name self.salary=salary Employee.empCount+=1 #self代表类的实例,self在定义类的方法时是必须有的,在调用时不必传入相应的参数(和this是一个性质,不是特质谁,是指当前特定时间内执行这个命令的对象) def displayCount(self): print("Total Employee %d"%Employee.empCount) print(self.__class__) def displayEmployee(self): print("Name:",self.name,",Salary:",self.salary) ee1=Employee('Nick',10000) #类名()构造方法,类似生产车间 ee1.displayCount() ee1.displayCount()
类属性使用 类名.属性名 的方式去访问,对象也可以访问。但是如果对象修改,则只对当前对象适用(因为这是其实是增加对象属性)
-
动态为对象添加,删除属性
只会影响到当前操作的对象
ee1.age=22 del ee1.name #ee1.displayEmployee() #'Employee' object has no attribute 'name' #print(ee2.age) #'Employee' object has no attribute 'age' print(hasattr(ee1,'age')) # 如果存在 'age' 属性返回 True print(getattr(ee1,'age')) #返回’age’属性的值 setattr(ee2,'age',8) #添加属性’age’值为8 delattr(ee1,'age') #删除属性’age' #类属性也可以通过del动态删除
注意:删除对象时要删除空间,不能用del ee1,没办法删一整块内存,只能删除引用,可以用ee1=None,让其指向None区域,系统发现没有用就会回收
-
析构函数
def __del__(self): #名字不能更改,对象销毁或被回收时调用 print('byebye {0}'.format(self.name))
-
内置属性
def setSalary(obj): if isinstance(obj,Employee): #判断obj是否是Employee的派生类 print('pay : {0}'.format(obj.salary))
-
继承
-
在继承中积累的构造(init()方法)不会被自动调用,它需要在其他派生类的构造中亲自专门调用。
-
在调用基类的方法时,需要加上派生类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数
-
Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
class Boss(Employee): def __init__(self,name,salary,bouns): #不知道具体多少时用预留参数*arg以此实现重载 super(Boss,self).__init__(name,salary) self.bouns=bouns
python没有重载,因为函数名指向内存地址的变量。
-
-
多重继承
class A(object): __scope='a scope' def __init__(self, a): print('init A...') self.a = a def show(self): print('i am A') class B(A): def __init__(self, a): super(B, self).__init__(a) print( 'init B...') def show(self): super(B,self).show() print(' and i am B too') class C(A): def __init__(self, a): super(C, self).__init__(a) print('init C...') def show(self): super(C, self).show() print(' and i am C too too') class D(B, C): #先调用c再调用b def __init__(self, a): super(D, self).__init__(a) print('init D...') def show(self): super(D, self).show() print(' and i am D too too...') d=D(12) d.show()
-
使用接口的思想设计多重继承
整体可以分为类型类和功能类两种类,类型类实现主体继承树形结构,功能类作为独立的功能接口存在。
# 多重继承 class Animal(object): def __init__(self,age): self.age=age # 大类: class Mammal(Animal): def __init__(self,age,foot): super(Mammal,self).__init__(age) self.foot=foot class Bird(Animal): def __init__(self,age,fly): super(Bird,self).__init__(age) self.fly=fly class RunnableMixIn(object): def run(self): print('Running...') class FlyableMixIn(object): def fly(self): print('Flying...') # 各种动物: class Dog(Mammal,RunnableMixIn): def __init__(self,age,foot,gender): super(Dog,self).__init__(age,foot) self.gender=gender def show(self): print('dog age is:',self.age,'ang have ',self.foot) class Bat(Mammal): pass class Parrot(Bird): pass class Ostrich(Bird): pass dog=Dog(3,4,'male') dog.show()
-
动态添加对象
python可以动态为对象绑定属性,但是不会影响到同类的其他对象
class Person: pass p1=Person() p2=Person() p1.gender='male' print(p1.gender) print(p2.gender) #'Person' object has no attribute 'gender'
动态为对象绑定方法
from types import MethodType class Person: pass def displayMe(self): print('my genderis:', self.gender) # 给一个实例绑定的方法,对另一个实例是不起作用的: p1=Person() p2=Person() p1.dispalyMe=MethodType(displayMe,p1) p2.dispalyMe()
通过动态给雷增加属性和方法,可以实现所有对象都增加了属性和方法
Person.gender='male' def displayMe(self): print('my genderis:', self.gender) Person.displayMe=displayMe
from types import MethodType class Student(): pass def set_age(self,age): self.age=age Student.set_age=MethodType(set_age,Student) Student.set_age=22 #让set_age指向变量22,此时函数会被回收掉 print(Student.set_age) Student.set_age=MethodType(set_age,Student) #把Student添加一个行为 Student.set_age(23) #调用行为 print(Student.age) s1=Student() print(s1.age)
使用__slots__限制实例的属性,比如,只允许对Student实例添加name和age属性
class Person(object): __slots__=('name','age') p1=Person() print(dir(p1)) # 这是看到p1对象里已经存在name和age属性了 try: p1.gender = 'female' except Exception: print('使用__slots__限制实例的属性')
-
私有属性
1、 _xx 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问,同一个包内的也可以。若内部变量标示,如: 当使用“from M import”时,不会将以一个下划线开头的对象引入 。
2、 __xx 双下划线的表示的是私有类型的变量。只能允许这个类本身进行访问了,连子类也不可以用于命名一个类属性(类变量),调用时名字被改变(在类FooBar内部,__boo变成_FooBar__boo,如self._FooBar__boo)
3、 __xx__定义的是特例方法。用户控制的命名空间内的变量或是属性,如init , __import__或是file 。只有当文档有说明时使用,不要自己定义这类变量。 (就是说这些是python内部定义的变量名)
python默认的成员函数和成员变量都是公开的,没有像其他类似语言的public,private等关键字修饰.但是可以在变量前面加上两个下划线"",这样的话函数或变量就变成私有的.这是python的私有变量轧压(这个翻译好拗口),英文是(private name mangling.) **情况就是当变量被标记为私有后,在变量的前端插入类名,再类名前添加一个下划线"",即形成了_ClassName__变量名.
class pub(): # protected类型的变量和方法 在类的实例中可以获取和调用 _name = 'protected类型的变量' __info = '私有类型的变量' def _func(self): print("这是一个protected类型的方法") def __func2(self): print('这是一个私有类型的方法') # 如果想要在实例中获取到类的私有类形变量可以通过在类中声明普通方法,返回私有类形变量的方式获取 def get(self): return(self.__info) p=pub() p.__info # error 因为__info是私有变量只有在类内部才可见,所以要用内部方法
-
属性
-
python内置类属性
dict : 类的属性(包含一个字典,由类的数据属性组成)
doc :类的文档字符串
module: 类定义所在的模块(类的全名是’main.className’,如果类位于一个导入模块mymod中,那么className.module 等于 mymod)
bases : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
-
只读属性
@property :把访问行为变为访问属性
class Car: __wheels = 4 __voice = 'didi' def __init__(self, color): self.color = color self.speed = 80 @property def run(self): print('i can run %d speed' % self.speed) @run.setter def run(self, wh): self.speed = wh car1 = Car('blue') print(car1.color) car1.run = 120 car1.run #i can run 120 speed
这个属性是不可以通过del car1.run 来删除的。因为他本来就不是一个属性
@run.deleter def run(self): del self.speed print("你的车轮已经被拆除...")
-
静态方法
普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法。
class Car: __wheels=4 __voice='didi' def __init__(self,color): self.color=color @property def wheels(self): return self.__wheels #静态方法在类中也不需要传入 self参数 @staticmethod def wash(): print('i am washing')
-
类方法
通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
class Car: __wheels=4 __voice='didi' def __init__(self,color): self.color=color @property def wheels(self): return self.__wheels @classmethod def dudu(cls): print(cls.__voice) @staticmethod def wash(): print('i am washing')
-