一、创建类
class Student:
name = "jack"#属性
age = 18 #公有属性
__private_sttrs = ""#两个下划线开头,声明该属性为私有
def __init__(self,age):#__init__是构造方法
self.age = age
print ("init")
def __private_method(self):#两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用
print "private method"
def setName(self,name):#方法
self.name = name
print("setName")
stu = Student(20)#创建实例对象
stu.setName("jim")#调用方法
print stu.name
print stu.age
self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
self 不是 python 关键字,只是习惯用这个命名表示类的实例,我们把他换成 runoob 也是可以正常执行
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
二、添加,删除,修改类的属性
stu.gender = "male" #类中没有gender属性,直接添加属性
stu.gender = "female"#修改属性
del stu.gender #删除属性
三、访问属性的函数方法
你也可以使用以下函数的方式来访问属性:
getattr(obj, name[, default]) : 访问对象的属性。
hasattr(obj,name) : 检查是否存在一个属性。
setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
delattr(obj, name) : 删除属性。
hasattr(stu, "age") # 如果存在 'age' 属性返回 True。
getattr(stu, "age") # 返回 'age' 属性的值
setattr(stu, "age", 8) # 添加属性 'age' 值为 8
delattr(stu, "age") # 删除属性 'age'
四、Python内置类属性
dict : 类的属性(包含一个字典,由类的数据属性组成)
doc :类的文档字符串
name: 类名
module: 类定义所在的模块(类的全名是'main.className',如果类位于一个导入模块mymod中,那么 className.module 等于 mymod)
bases : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
print Student.__dict__
print Student.__doc__
print Student.__name__
print Student.__module__
print Student.__bases__
输出结果:
{'__module__': '__main__', 'name': 'jack', 'setName': <function setName at
0x1096c37d0>, 'age': 18, '__doc__': None, '__init__': <function __init__ at
0x1096c3758>}
None
Student
__main__
()
五、类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。
需要注意的地方:继承语法 class 派生类名(基类名)://... 基类名写在括号里,基本类是在类定义的时候,在元组之中指明的。
在python中继承中的一些特点:
1:在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数
3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
class SubClassName (ParentClass1[, ParentClass2, ...]):
'Optional class documentation string'
class_suite
class Parent: # 定义父类
parentAttr = 100
def __init__(self):
print "调用父类构造函数"
def parentMethod(self):
print '调用父类方法'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "父类属性 :", Parent.parentAttr
class Child(Parent): # 定义子类
def __init__(self):
print "调用子类构造方法"
def childMethod(self):
print '调用子类方法'
c = Child() # 实例化子类
c.childMethod() # 调用子类的方法
c.parentMethod() # 调用父类方法
c.setAttr(200) # 再次调用父类的方法 - 设置属性值
c.getAttr() # 再次调用父类的方法 - 获取属性值
六、多继承
class P1(object):
def foo(self):
print 'p1-foo'
class P2(object):
def foo(self):
print 'p2-foo'
def bar(self):
print 'p2-bar'
class C1(P1, P2):
pass
class C2(P1, P2):
def bar(self):
print 'C2-bar'
class D(C1, C2):
pass
对经典类和新式类来说,属性的查找顺序是不同的。现在我们分别看一下经典类和新式类两种不同的表现
1、经典类
d = D()
d.foo() # 输出 p1-foo
d.bar() # 输出 p2-bar
实例d调用foo()
时,搜索顺序是
D = > C1 = > P1
实例d调用bar()
时,搜索顺序是
D = > C1 = > P1 = > P2
换句话说,经典类的搜索方式是按照“从左至右,深度优先”的方式去查找属性。d先查找自身是否有foo方法,没有则查找最近的父类C1里是否有该方法,如果没有则继续向上查找,直到在P1中找到该方法,查找结束。
2、新式类
使用新式类要去掉第一段代码中的注释
d = D()
d.foo() # 输出 p1-foo
d.bar() # 输出 c2-bar
实例d调用foo()
时,搜索顺序是
D = > C1 = > C2 = > P1
实例d调用bar()
时,搜索顺序是
D = > C1 = > C2
可以看出,新式类的搜索方式是采用“广度优先”的方式去查找属性。
可以调用类的mro属性来查看查找顺序
七、方法重写
class Parent: # 定义父类
def myMethod(self):
print '调用父类方法'
class Child(Parent): # 定义子类
def myMethod(self):
print '调用子类方法'
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
单下划线、双下划线、头尾双下划线说明:
foo: 定义的是特殊方法,一般是系统定义名字 ,类似 init() 之类的。
_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。