一、class
Python中的class包含以下两点:
类的属性:类中所涉及的变量 类的方法:类中函数
如果类定义是这样的:
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
那么 i就是类的属性 和 f 就是类的方法。 __doc__ 也是一个有效的属性,将返回所属类的文档字符串: "Asimple example class"。
类的 实例化 是使用函数表示法。 可以相像类对象就是会返回一个新的类实例的不带参数的函数。 举例来说(假设使用上述的类):
x = MyClass()
二、init函数(方法)
在python中创建一个新式类时,一般都会定义一个 __init__ 方法,用来对类的实例进行初始化。但是 __init__ 方法并不是类的构造方法 .(或者说在python3以后 __init__不是类的构造方法,只是类的初始化方法,python3类的构造方法变成了__new)不用init()方法定义类
定义一个矩形的类,目的是求周长和面积。
class Rectangle():
def getPeri(self,a,b):
return (a + b)*2
def getArea(self,a,b):
return a*b
rect = Rectangle()
print(rect.getPeri(3,4))
print(rect.getArea(3,4))
print(rect.__dict__)
得到结果:14 12 {}
从上例中可以看到,我们在类中并没有定义init()方法,但是也能够得到类似的要求,结果返回了矩形实例rect的周长及面积。 但是,我们通过print(rect.dict)来看这个实例的属性,竟然是空的,我定义了一个矩形,按理来说它的属性应该是它的长、宽。但是它竟然没有。这就是没有定义init()的原因了。 并且,在实例化对象的时候,rect = Rectangle()参数为空,没有指定a、b的值,只有在调用函数的时候才指定了。且类中定义的每个方法的参数都有a、b,这显然浪费感情,在类中直接指定方法就可以了。 因此吧,需要在类中定义init()方法,方便创建实例的时候,需要给实例绑定上属性,也方便类中的方法(函数)的定义。
2、用init()方法定义类
init函数(方法)的第一个参数必须是 self(self为习惯用法,也可以用别的名字),后续参数则可 以自由指定,和定义函数没有任何区别
class Rectangle():
def __init__(self,a,b):
self.a = a
self.b = b
def getPeri(self):
return (self.a + self.b)*2
def getArea(self):
return self.a * self.b
rect = Rectangle(3,4)
print(rect.getPeri())
print(rect.getArea())
print(rect.__dict__)
结果
14 12 {'a': 3, 'b': 4}
上述同样的例子,采用init()方法定义类,如下:
定义完init()后,创建的每个实例都有自己的属性,也方便直接调用类中的函数。
三、私有成员变量
Python的类并不使用关键字区分是私有成员和共有成员,但是为啥私有成员变量外面还是访问不到呢?
首先说一下,带有两个下划线开头的函数是声明该属性为私有,不能在类地外部被使用或直接访问。
class Students:
def __init__(self,sex,name,age,scores):
self.__sex = sex
self.age = age
self.name =name
self.scores = scores
def get_data(self):
return self.name,self.age,self.scores,self.__sex
stu = Students('男','taon','23','90')
print(stu.__sex,stu.__dict__)
运行结果:
AttributeError: 'Students' object has no attribute '__sex'
其实还是可以被外部访问到的,只不过换了名字罢了。Python会在类的内部自动的把你定义的spam变量的名字替换成为 _classname__spam(注意,classname前面是一个下划线,spam前是两个下划线),Python把这种技术叫做“name mangling”。因此,用户在外部访问spam的时候就会提示找不到相应的变量。 )
于是将上面的代码改为:
class Students:
def __init__(self,sex,name,age,scores):
self.__sex = sex
self.age = age
self.name =name
self.scores = scores
def get_data(self):
return self.name,self.age,self.scores,self.__sex
stu = Students('男','tao','23','90')
print(stu._Students__sex,stu.__dict__)
运行结果:
男 {'name': 'tao', '_Students__sex': '男', 'age': '23', 'scores': '90'}
看上面实例的属性也知道,这不过sex的名字被换了而已。这样就变成私有了,哈哈哈哈。
四、新式类、经典类
由于自己是从Python3入门学习的,所以在类的声明时并未留意到基类object的书写与否 是否会对程序结果造成影响(事实上,并不会有所影响),但 是,在Python2中,基类object书写与否 会对结果造成影响。
在Python 3.x中取消了经典类,默认都是新式类,并且不必显式的继承object,也就是说
class Person(object):pass
class Person():pass
class Person:pass
三种写法并无区别
但是在Python2.x中,默认都是经典类,只有显式继承了object才是新式类,即:
class Person(object):pass 新式类写法
class Person():pass 经典类写法
class Person:pass 经典类写法
他们最明显的区别在于继承搜索的顺序发生了改变
经典类的MRO(method resolution order 基类搜索顺序)算法是采用深度优先搜索 : 先深入继承树左侧查找,然后再返回,开始查找右侧
新式类的MRO算法采用C3算法广度优先搜索 : 先在水平方向查找,然后再向上查找