python中所有数据都是以对象形式存在。对象既包含数据(变量),也包含代码(函数),是某一类具体事物的特殊实例。
面向对象的三大特性为封装、继承和多态。
1、定义类
#定义空类 class Person(): pass
#添加对象初始化方法 def Person(): def __init__(self): pass
self参数指向正在被创建的对象本身。
self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类。
#初始化方法中添加参数 def Person(): def __init__(self,name): self.name=name
2、创建实例
>>>hunter=Person('Elmer Fudd')
上一行做了以下工作:
- 查看Person类的定义
- 在内存中实例化(创建)一个新的对象调用对象的__init__方法,将这个新创建的对象作为self传入,并将另一个参数‘Elmer Fudd’作为name传入
- 将name的值存入对象
- 返回这个新的对象
- 将名字hunter和这个对象关联
3、访问属性
使用点号 . 来访问对象的属性
print(hunter.name)
一些内置类属性:
- __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
- __doc__ :类的文档字符串
- __name__: 类名
- __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
- __bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
4、继承
继承即从已有类中衍生出新的类,可以添加或修改部分功能。便于代码复用。
class Car(): pass class Yugo(Car): pass
5、类方法覆盖
新创建的子类会自动继承父类的所有信息。
class Car(): def exclaim(self): print("I'm a Car!") class Yugo(Car): pass t1=Car() t2=Yugo() >>>t1.exclaim() I'm a Car! >>>t2.exclaim() I'm a Car!
对继承的方法进行修改后会覆盖原有的方法。
class Car(): def exclaim(self): print("I'm a Car!") class Yugo(Car): def exclaim(self): print("I'm a Yugo!") t1=Car() t2=Yugo() >>>t1.exclaim() I'm a Car! >>>t2.exclaim() I'm a Yugo!
在子类中,可以覆盖父类的方法,包括__init__()方法
class MDPerson(Person): def __init__(self,name): self.name="Doctor" + name a=Person('Tom') b=MDPerson('Tom') >>>a.name Tom >>>b.name Doctor Tom
6、子类添加新方法
class Car(): def exclaim(self): print("I'm a Car!") class Yugo(Car): def exclaim(self): print("I'm a Yugo!") def push(self): print('need a push') a=Car() b=Yugo() >>>b.push() need a push
7、使用super()调用父类方法
class EPerson(Person): def __init__(self,name,email): super().__init__(name) self.email=email
我们应当使用super()来让父类完成其应当做的事情。并且,如果父类的定义以后发生改变,使用super()可以保证这些改变会自动反映到子类上,而不需要手动修改。
8、self参数作用
以下句代码举例:
>>>t1.exclaim()
- 查找t1对象所属的类Car
- 把t1对象作为self参数传给Car类所包含的exclaim()方法
相当于:
>>>Car.exclaim(t1)
9、使用property属性访问
property(fget,fset,fdel,doc)
class Duck(): def __init__(self,iname): self.hidden_name=iname def get_name(self): return self.hidden_name def set_name(self,iname): self.hidden_name=iname name=property(get_name,set_name)
最后一行将get_name,set_name定义为name属性。当访问name时,get_name()会被自动调用。当对name执行赋值操作时,set_name()方法会被调用。
tt=Duck('Howard') >>>tt.name 'Howard' >>>tt.name='Tom' >>>tt.name 'Tom'
也可以通过装饰器方式定义property。
- @property,用于指定getter方法
- @name.setter,用于指定setter方法
class Duck(): def __init__(self,iname): self.hidden_name=iname @property def name(self): return self.hidden_name @name.setter def name(self,iname): self.hidden_name=iname name=property(get_name,set_name)
property除指向类中存储的某一属性(如hidden_name),也可以指向计算结果值。
class Circle(): def __init__(self,radius): self.radius=radius @property def diameter(self): return 2*self.radius c=Circle(5) >>>c.radius 5 >>>c.diameter 10 >>>c.radius=7 >>>c.diameter 14
如果没有指定property的setter,将无法从类的外部对它的值进行设置。
与直接访问属性相比,如果改变某一属性的定义,只需要在类定义中修改代码,不需要在每一处调用修改。