编程思想:
- 面向过程:问题比较简单,可以用线性的思维解决
- 面向对象:问题较为复杂,使用简单的线性思维无法解决
两种编程思想都是解决问题的方式,并不对立,通过面向对象的方式便于我们从宏观上把握事物之间的复杂关系、便于我们分析整个系统。本质仍然使用面向过程的方式来处理。
面向对象的程序设计强调把数据和操作结合为一个不可分割的系统单位(即对象),对象的外部只需要知道它在做什么,而不需要知道怎么做。
类和对象:
类是抽象的模板,而实例是根据类创建出来的一个个具体的 ”对象“ ,每个对象都拥有相同的方法,但各自的数据可能不相同。
类:
类是多个类似事物组成的群体的总称。能够帮助我们快速理解和判断事物的性质。
1 class 类名( object ): # 类名有一个或多个单词构成,每个单词首字母大写其余小写,用下划线连接 2 pass
Tip : object 表示该类是从哪个类继承(后补充)下来的,通常,如果没有合适的继承类,就使用 object 类,这是所有类都会继承的类。
数据类型:
- 不同的数据类型属于不同的类。
- 可以使用 type() 函数来查看变量的数据类型。
对象:
对象是类的具体实例(instance),python 中一切皆对象。
类是一种数据结构,类定义数据类型的数据(属性 )和行为(方法)。对象是类的具体实体,也可以称为类的实例。需要注意,类的实例和实例对象有时不那么容易区分但又不是同一个东西。在在用class 关键字创建自定义的类对象的时,创建的是类的实例;而后者是用类对象创建实例对象。
Python中一切皆对象;类定义完成后,会在当前作用域中定义一个以类名为名字,指向类对象的变量(名字)。
属性:
Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class:
类数据属性:
类属性是某个类所有实例共享的属性,在创建实例对象时,每个实例都会拥有类数据属性的一个拷贝。
实例变量属性:
由类中__ init __() 方法定义的属性(变量)。通过 “ . ”来访问。在每个实例对象初始化时都会赋予独有的数据。
举几个栗子:
1 class Student: 2 3 school = JXNU # class variable shared by all instances 4 5 def __init__(self, name): 6 self.name = name # instance variable unique to each instance
1 class Student: 2 school = 'JXNU' 3 4 def __init__(self, name): 5 self.name = name 6 7 8 stu1 = Student('Zhang') 9 stu2 = Student('Li') 10 11 print(stu1.school) # =>JXNU 12 print(stu2.school) # =>JXNU 13 14 print('-'*20) 15 Student.school = 'SDJU' 16 print(stu1.school) # =>SDNU 17 print(stu2.school) # =>SDNU 18 19 print('-'*20) 20 stu1.school = 'ZJNU' 21 print(stu2.school) # =>SDNU 22 print(stu1.school) # =>ZJNU 23 24 print('-'*20) 25 Student.school = 'PJNU' 26 print(stu1.school) # =>ZJNU 27 print(stu2.school) # =>PJNU
- 所有的实例初始化时都创建了一个指向同一个类属性的指针。用类名Student修改类属性school时,实例中的school也会发生改变。而用实例 stu1 修改对应的 school 时,指针将不指向原来的类属性了,而是指向其他的变量。
- 类 Student 中,类属性 school 为所有实例共享;实例属性 name 为每个 Student 的实例独有。
- 实例属性是不能用类名访问的属性,必须由实例名 + ‘ . ' 来访问。且每个实例对应一套。
私有属性和公有属性:
通常约定以两个下划线开头而不以两个下划线结尾的变量为私有变量,其他的为公有变量。不能直接访问私有变量,但可以在方法中访问。
特殊属性:
类属性 |
含义 |
__name__ |
类的名字(字符串) |
__doc__ |
类的文档字符串 |
__bases__ |
类的所有父类组成的元组 |
__dict__ |
类的属性组成的字典 |
__module__ |
类所属的模块 |
__class__ |
类对象的类型 |
方法:
实例方法:
一般需要传递 self 参数用于调用实例的实例属性(变量),且只能由实例访问。没有矛盾和冲突点不做赘述。
类方法:
- 用 @classmethod 修饰的方法,可以用类名直接访问。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)。
- 原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。
静态方法:
- 用 @staticmethod 修饰的方法,可以用类名直接访问。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)。
- 静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
- 静态方法更像是可以写在类外的函数,但这样是为了在逻辑上与类保持一定联系,不破坏类的逻辑性。
类方法和静态方法的用途有时会混淆。
举几个栗子:
* 类方法栗子
1 情景: 2 假设我有一个学生类和一个班级类,想要实现的功能为: 3 执行班级人数增加的操作、获得班级的总人数; 4 学生类继承自班级类,每实例化一个学生,班级人数都能增加; 5 最后,我想定义一些学生,获得班级中的总人数。 6 7 class ClassTest(object): 8 __num = 0 9 10 @classmethod 11 def addNum(cls): 12 cls.__num += 1 13 14 @classmethod 15 def getNum(cls): 16 return cls.__num 17 18 # 这里我用到魔术方法__new__,主要是为了在创建实例的时候调用累加方法。 19 def __new__(self): 20 ClassTest.addNum() 21 return super(ClassTest, self)