在至今我们编写的所有程序中,我们曾围绕函数设计我们的程序,也就是那些能够处理数据的代码块。这被称作面向过程(Procedure-oriented) 的编程方式。还有另外一种组织起你的程序的方式,它将数据与功能进行组合,并将其包装在被称作“对象”的东西内。在大多数情况下,你可以使用过程式编程,但是当你需要编写一个大型程序或面对某一更适合此方法的问题时,你可以考虑使用面向对象式的编程技术。
类和对象是面向对象编程的两个主要方面,一个类(Class)可以创建一个新的类型(Type),而对象(Object)则是类的一个实例(Instance)。
对象可以使用从属于其的普通变量来储存数据,这种从属于对象或类的变量叫作“字段”;对象还可以使用属于类的函数来实现某些功能,这些函数则称为类的“方法”,而字段与方法统称为类的属性。
类方法与普通函数只有一种特定的区别——前者必须有一个额外的名字,这个名字必须添加到参数列表的开头,但是你不用在你调用这个功能时为这个参数赋值,Python 会为它提供。这种特定的变量引用的是对象本身,按照惯例,它被赋予 self 这一名称。
对于self,其表示的意思即为由这个类创建的实例本身。在下面的例子中,当我们在调用 p.say_hello() 时,python的解释器将其解释为 person.say_hello(p) 。因此,self 是一个必须要写的东西。
class person:
def say_hello(self):
print('How are you')
p = person()
p.say_hello()
也就是说,我们定义的方法“say_hello”在编译器中的名字是“self”,而对于用户自定义的类,我们仍旧需要记住冒号在python类中所需要出现的位置,并同时注意方法结尾处的 self 。好的编译器将会自动的给出 self ,但我们仍不能忽略掉他。
对于self而言,假设你有一个 MyClass 的类,这个类下有一个实例 myobject 。当你调用一个这个对象的方法,如 myobject.method(arg1, arg2) 时,Python 将会自动将其转换成 MyClass.method(myobject, arg1, arg2)
在python的类中,有很多方法拥有特殊的意义,__init__ 就是其中之一。此方法会在类的对象进行实例化时立即运行,我们以一个简单的程序作为例子:
class Person:
def __init__(self, name):
self.name = name
def say_hello(self):
print('Hello, my name is', self.name)
p = Person('Coulson')
p.say_hello()
在类 Person 中,__init__ 将会在实例化时直接运行,并将语句中传递过来的参数 'Coulson' 赋值给 self.name 。由于 self.name 可以作用于类下所有的方法,say_hello 将会输出传递的参数
字段即是绑定到类与对象的命名空间的普通变量。字段有两种类型,分别是类变量和对象变量,它们根据究竟是类还是对象拥有这些变量来进行分类。
类变量表示为共有的,即是所有类的对象都可以对其进行更改,当任意一个对象对其做出改动的时候,在其他所有对象中,这个类变量的数值都会进行更改,就像如下程序所显示的那样
class Coulson:
num = 0
def __init__(self, name):
self.name = name
print('This is', name, 'speaking')
def adding1(self):
Coulson.num += 1
def adding2(self):
Coulson.num += 1
def adding3(self):
Coulson.num += 1
def deleting(self):
Coulson.num -= 1
@classmethod
def how_many(self):
print("The num is", self.num)
try1 = Coulson('coulson1')
try1.adding1()
print(try1.num)
try2 = Coulson('coulson2')
try2.adding2()
print(try2.num)
try3 = Coulson('coulson3')
try3.adding3()
print(try3.num)
try3.deleting()
print(try3.num)
try3.how_many()
在以上的代码中,num属于Coulson类,因此它是一个类变量;而name属于一个对象(由self)进行分配,因此name是一个对象变量。
因此我们在引用的时候,采用 Coulson.num 而不是 self.num 来引用 num 变量;通过 self.name 而不是 Coulson.name 来引用。
在python中,如果你想让你的变量是私有的,不可受外界更改的,我们一般在你在类中定义的变量前加上两个单横线。这时,python将自动地将其解释为私有变量。
class student:
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_name(self):
print(self.__name)
def print_score(self):
print(self.__score)
这时如果你在控制台输入
stu3.__name
控制台将会提示 'student' object has no attribute '__name' ,也就是类中没有 __name 属性。这样,就不必担心类中的一些变量被用户所更改了。
面向对象编程的一大优点是对代码的重用(Reuse),重用的一种实现方法就是通过继承(Inheritance)机制。
例如你打算编写有关老师和学生的程序,老师和学生都拥有包括姓名、年龄等共同信息;但同时又拥有着例如薪水学费等不同的信息。在这时,继承就体现出其的重要性来。
我们设立一个拥有共同信息名叫 SchoolMember 的类,它也被称为基类(Superclass);设立 Student 和 Teacher 类,它们也被叫做子类(Subclass)。
我们在代码中设定了老师和学生两个子类,并给出年龄等一系列变量。
class SchoolMember():
'''代表任意学校中的成员'''
def __init__(self, name, age, sex, IDcard):
self.name = name
self.age = age
self.sex = sex
self.IDcard = IDcard
def tell(self):
print('The basic information of {} are {}, {}, {}'.format(self.name, self.age, self.sex, self.IDcard))
class Teacher(SchoolMember):
'''代表一位老师'''
def __init__(self, name, age, sex,IDcard, salary):
SchoolMember.__init__(self, name, age, sex, IDcard)
self.salary = salary
def tell_saraly(self):
print('{}\'s salary is {}'.format(self.name, self.salary))
在这里,我们给出老师作为子类,将 SchoolMember 设为父类,在继承时,只需要在子类后的括号中写入父类的代号即可。