python之面向对象编程
__init__
通过在类中定义一个特殊的
__init__
方法,在创建实例的时候想要进行属性初始化,想要一些必要的属性的值绑上去时:class Person(object): def __init__(self, name, age): self.name = name self.age = age
__init__
方法的第一个参数要为self,self表示创建的实例本身.书写__init__
方法,在创建实例的时候,必须传入与__init__
方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去。__init__
方法的返回值总是None,不要试图给其返回其他的东西。__init__
方法并不是在创建实例时第一个被调用的方法,第一个被调用的是__new__(cls[,...])
方法,如果__new__
方法后面有参数,该方法会将参数传给__init__
方法 , 最终通常返回一个实例对象。一般不需要我们重写__new__
方法。
__new__
例子
class Upstr(str): def __new__(cls, string): string = string.upper() return str.__new__(cls,string)
上面通过定义自身
__new__
方法来实现字符串的大写转换:首先调用参数的大写化方法,后直接调用字符串本身的__new__
方法。当子类中不写
__new__
方法时,子类自动调用父类的__new__
方法。注意
__new__
方法需要返回一个实例对象,当不返回东西时,将不会再去调用__init__
方法。
__del__
当对象将要被销毁时,这个方法将自动调用。
del x
不等同与x.__del__()
当所有对某个实例的引用全都被del x时,才会去调用__del__
方法。
访问限制
如果想让内部属性封装起来,可以在属性的名称前加上两个下划线
__
,在Python中,实例的变量名如果以__
开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name
继承
当我们定义一个class的时候,可以从某个现有的class继承:可在新类右边的括号上添加继承的类名:
class New_str(str): def new(self): print('I am new str...')
在python中,当一个类什么类也不继承时,自动继承
object
类。python中一个类还可以继承多个类,实现不同层面的继承。继承可实现方法的覆盖class Animal: def __init__(self,name): self.name = name def hello(self): print 'animal' class Runnable: def __init__(self,speed): self.speed = speed def hello(self): print 'runnable' class Dog(Animal,Runnable): #重写构造方法后,将父类的构造方法覆盖掉了,解决方法:使用类方法 def __init__(self,name,speed,age): Animal.__init__(self,name) Runnable.__init__(self,speed) self.age = age def hello(self): print 'dog' c = Dog('Helen',113,13) c.hello() print c.__dict__ #返回一个字典
多态
a = Animal()
d = Dog()
>>> isinstance(c, Dog)
True
>>> isinstance(c, Animal)
True
由上我们可知,d不仅是Dog类的实例,还是Animal类的实例。所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来不行。
多态的好处在于:定义函数的参数类型的时候可以用父类的数据类型,这样继承父类的各个子类都是作为实参传入进去。
__str__
定义一个类时,我们可以给它添加
__str__
的魔法方法,这样打印(print)这个类的实例时,不会打印其地址,而是打印出我们想要的信息。如:class A: def __init__(self,name): self.name = name def __str__(self): return self.name a = A('Mary') print(a)
对象的属性
判断对象是否有某种属性
class MyObject(object): def __init__(self): self.x = 9 obj = MyObject() print hasattr(obj,'x') print getattr(obj,'x') # x属性不存在时,会出现异常。 # 这时可以传入一个default参数,如果属性不存在,就返回默认值 print getattr(obj,'y',19) setattr(obj, 'x', 19) print obj.x
对象的方法名和属性名不要相同。
给实例对象绑定属性
class Student(object): def __init__(self, name): self.name = name s = Student('Bob') s.score = 90 # 但类的属性中不存在score print s.score
给属性绑定方法
class A: # 定义一个类 pass a = A() def set_age(self, age): # 定义一个方法 self.age = age from types import MethodType a.set_age = MethodType(set_age, a) # 给实例a绑定方法,类还是不存在该方法 a.set_age(25) print a.age
限制实例的属性,不允许其添加新的属性:
class Student(object): __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称 s = Student() s.age = 12 s.name = 'xxx' s.score = 150 # 左边这样做会出现异常
类的属性
定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到:
class Student: school = 'xxxx' a = Student() print a.school # 访问的是类的school属性 b = Student() a.school = 'cccc' # 给对象a绑定了新属性school,这里的school并不是类的属性 del a.school # 删除对象a的新属性 print b.school print a.school
不要把实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
给类绑定新的方法
class B: pass b = B() def set_age(self, age): self.age = age from types import MethodType B.set_age = MethodType(set_age, B) # 给类绑定新的方法 b.set_age(12) print b.age
检查参数,使用@property
class Student:
@property # 定义属性
def score(self):
return self._score # 区分属性_score和方法score
@score.setter # 定义属性的set方法
def score(self,value):
if not (isinstance(int, value)):
raise ValueError('score must be an integer!')
elif value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value