简介
到目前为止, 我们的编程都是根据数据的函数和语句块来设计的, 面向过程的编程. 还有一种我们将数据和功能结合起来使用对象的形式, 使用它里面的数据和方法这种方法叫做面向对象的编程.
类和对象是面向对象编程的两个重要方面. 对于类和对象的关系, 举个例子就像学生和小明同学的关系一样. 学生 (类) 是一个拥有共同属性的群体, 小明同学 (对象) 是其中一个有自己特性的个体.
对于一个对象或类的变量被称为域, 函数被称为类或对象的方法.
域有两种类型 -- 属于每个对象或属于类本身, 分别成为实例变量和类变量.
类使用 class 关键字创建, 类的域和方法被列在一个缩进块中.
self
类的方法与普通的函数只有一个特别的区别 -- 它们必须有一个额外的第一个参数名称, 但是在调用这个方法的时候你不为这个参数赋值, Python 会提供这个值. 这个特别的变量指对象本身, 按照惯例它的名称是 self.
虽然你可以给这个参数任何名称, 但是 强烈建议 你使用 self 这个名称 -- 其他名称都是不赞成你使用的. 使用一个标准的名称有很多优点 -- 你的程序可以迅速识别它, 如果使用 self 的话, 还有些 IDE(集成开发环境)也可以帮助你.
给 C++/Java/C# 程序员的注释
Python 中的 self 等价于 C++ 中的 self 指针和 Java,C# 中的 this 参考.
你一定很奇怪 Python 如何给 self 赋值以及为何你不需要给它赋值. 举一个例子会使此变得清晰. 假如你有一个类称为 MyClass 和这个类的一个实例 MyObject. 当你调用这个对象的方法 MyObject.method(arg1,
arg2)的时候, 这会由 Python 自动转为 MyClass.method(MyObject, arg1,
arg2)-- 这就是 self 的原理了.
这也意味着如果你有一个不需要参数的方法, 你还是得给这个方法定义一个 self 参数
(这个概念好长啊......)
类
class 类名():
代码块
- '''the first class
- from liu
- 我们使用 class 语句后跟类名, 创建了一个新的类. 这后面跟着一个缩进的语句块形成类体. 在这个例子中, 我们使用了一个空白块, 它由 pass 语句表示.
- 接下来, 我们使用类名后跟一对圆括号来创建一个对象 / 实例.(我们将在下面的章节中学习更多的如何创建实例的方法). 为了验证, 我们简单地打印了这个变量的类型. 它告诉我们我们已经在__main__模块中有了一个 Person 类的实例.
- 可以注意到存储对象的计算机内存地址也打印了出来. 这个地址在你的计算机上会是另外一个值, 因为 Python 可以在任何空位存储对象.
- '''
- class Person:
- pass # 空块
- p = Person()
- print (p)
- print(__doc__)
运行结果
我们使用 class 语句后跟类名, 创建了一个新的类. 这后面跟着一个缩进的语句块形成类体. 在这个例子中, 我们使用了一个空白块, 它由 pass 语句表示.
接下来, 我们使用类名后跟一对圆括号来创建一个对象 / 实例. 为了验证, 我们简单地打印了这个变量的类型. 它告诉我们我们已经在__main__模块中有了一个 Person 类的实例.
可以注意到存储对象的计算机内存地址也打印了出来. 这个地址在你的计算机上会是另外一个值, 因为 Python 可以在任何空位存储对象.
对象的方法
对象的方法其实就是一个函数, 只不过在这个函数会有一个特别的参数 self.
- class Person:
- def sayHi(self):
- print('Hello,how are you?')
- p = Person()
- p.sayHi()
运行结果
这个 self 感觉不到它的作用, 但是还是要在参数中定义这是为什么呢?
去掉 self
从报错中看出系统在调用这个类方法的时候默认给它传了一个参数, 所以我们必须要有这个 self, 不为别的, 因为报错......
__init__方法
init 是一个初始化块, 在对象被建立的同时运行这个代码块, 为你的对象初始化. 需要注意的是名称的开始和结尾都要有两个下划线.
- '''__init__方法
- __init__一个对象被建立的时候, 马上运行. 这个方法是对你的对象的初始化.
- 这个名称的开始和结尾都是双下划线.'''
- class Person:
- def __init__(self,name):
- self.name = name
- def sayHi(self):
- print('Hello,my name is',self.name)
- p = Person('happyLiu')
- p.sayHi()
运行结果
感觉效果不明显...
- class Person:
- def __init__(self,name):
- print('这是初始化块')
- self.name = name
- def sayHi(self):
- print('Hello,my name is',self.name)
- p = Person('happyLiu')
- p.sayHi()
这样就好啦.
类与对象的变量
类的变量 由一个类的所有对象 (实例) 共享使用.
对象的变量 由类的每个对象 / 实例拥有.
可以理解为类的变量是这个类下所有对象公用的, 而对象的变量是这个对象私有的.
一个很长的例子
- class Person:
- population = 0
- def __init__(self,name):
- self.name = name
- print('Initalizing %s' % self.name)
- Person.population += 1
- def __del__(self):
- print('%s says bye.' % self.name)
- Person.population -= 1
- if Person.population == 0:
- print('I am the last one.')
- else:
- print('There are still %d people left.' % Person.population)
- def sayHi(self):
- print('Hi, my name is %s.' % self.name)
- def howMany(self):
- if Person.population == 1:
- print('I am the only person here.')
- else:
- print('We have %d persons here.' % Person.population)
- happy = Person('happyLiu')
- happy.sayHi()
- happy.howMany()
- bob = Person('bob james')
- bob.sayHi()
- bob.howMany()
- del bob
- happy.sayHi()
- happy.howMany()
运行结果
像__init__方法一样, 还有一个特殊的方法__del__, 它在对象消逝的时候被调用. 对象消逝即对象不再被使用, 它所占用的内存将返回给系统作它用.
使用不同的对象的时候, 就会调用类的方法, 但是传的参数是这个对象自己的, 所以我们面向对象的编程是非常灵活的.
继承
class 子类(父类):
代码块
面向对象的编程带来的主要好处之一是代码的重用, 实现这种重用的方法之一是通过 继承 机制. 继承完全可以理解成类之间的 类型和子类型 关系.
人是父类, 男人是子类, 小明是对象(小明没有对象,(¬︿̫̿¬☆)).
一个子类型在任何需要父类型的场合可以被替换成父类型, 即对象可以被视作是父类的实例, 这种现象被称为多态现象.
另外, 我们会发现在 重用 父类的代码的时候, 我们无需在不同的类中重复它. 而如果我们使用独立的类的话, 我们就不得不这么做了.
举个栗子
- class SchoolMember:
- '''Represents any school member.'''
- def __init__(self,name,age):
- self.name = name
- self.age = age
- print('(Initialized SchoolMember: %s)'%self.name)
- def tell(self):
- '''Tell my details.'''
- print('Name:%s Age:%d'%(self.name,self.age))
- class Teacher(SchoolMember):
- '''Represents a teacher.'''
- def __init__(self,name,age,salary):
- SchoolMember.__init__(self,name,age)
- self.salary = salary
- print('(Initialized Teacher: %s)' % self.name)
- def tell(self):
- SchoolMember.tell(self)
- print('Salary:"%d"' % self.salary)
- class Student(SchoolMember):
- '''Represents a student.'''
- def __init__(self, name, age, marks):
- SchoolMember.__init__(self,name,age)
- self.marks = marks
- print('(Initialized Student: %s)' % self.name)
- def tell(self):
- SchoolMember.tell(self)
- print('Marks:"%d"'%self.marks)
- t = Teacher('Mr,Liu',25,3000)
- s = Student('Swaroop', 22, 75)
- print()
- members = [t,s]
- for member in members:
- member.tell()
运行结果
为了使用继承, 我们把基本类的名称作为一个元组跟在定义类时的类名称之后. 然后, 我们注意到基本类的__init__方法专门使用 self 变量调用, 这样我们就可以初始化对象的基本类部分. 这一点十分重要 --Python 不会自动调用基本类的 constructor, 你得亲自专门调用它, SchoolMember.__init__(self,name,age)就是它, 开始的时候无限报错的就是它.
小总结
我们已经研究了类和对象的多个内容以及与它们相关的多个术语. 通过本章, 你已经了解了面向对象的编程的优点和缺陷. Python 是一个高度面向对象的语言, 理解这些概念会在将来有助于你进一步深入学习 Python.
来源: https://www.cnblogs.com/liuhappy/p/10640952.html