Python之路(第二十二篇) 面向对象初级:概念、类属性

一、面向对象概念

1. "面向对象(OOP)"是什么?

简单点说,“面向对象”是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式。俗话说,条条大路通罗马,也就说我们使用不同的方法都可以达到最终的目的,但是有些办法比较快速、安全且效果好,有些方法则效率低下且效果不尽人意。同样,编程也是为了解决问题,而解决问题可以有多种不同的视角和思路,前人把其中一些普遍适用且行之有效的编程模式归结为“范式”。常见的编程范式有:

  • 面向过程编程:OPP(Procedure Oriented Programing)

  • 面向对象编程:OOP(Object Oriented Programing)

  • 函数式编程:(Functional Programing)

面向过程编程的步骤:

1)分析出解决问题所需要的步骤;

2)用函数把这些步骤一次实现;

3)一个一个地调用这些函数来解决问题;

面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式。

优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单)

缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。

应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

面向对象编程的步骤:

1)把构成问题的事务分解、抽象成各个对象;

2)结合这些对象的共有属性,抽象出类;

3)类层次化结构设计--继承 和 合成;

4)用类和实例进行设计和实现来解决问题。

面向对象的程序设计:核心是对象二字,,对象是特征与技能的结合体,基于面向对象设计程序就好比在创造一个世界,你就是这个世界的上帝,存在的皆为对象,不存在的也可以创造出来,与面向过程机械式的思维方式形成鲜明对比,面向对象更加注重对现实世界的模拟,是一种“上帝式”的思维方式。

优点是:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护 .

缺点是:编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果。

应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。

2. 面向对象编程的特点

面向对象编程达到了软件工程的3个目标:重用性、灵活性、扩展性,而这些目标是通过以下几个主要特点实现的:

  • 封装: 可以隐藏实现细节,使代码模块化

  • 继承: 可以通过扩展已存在的类来实现代码重用,避免重复编写相同的代码

  • 多态: 封装和继承的目的都是为了实现 代码重用, 而多态是为了实现 接口重用,使得类在继承和派生的时候能够保证任何一个类的实例都能正确调用约定好的属性和方法。简单来说,就是为了约定相同的属性和方法名称。

3. 面向对象编程的使用场景

  • 场景1: 当多个函数需要传入多个共同的参数时,可以将这些函数封装到一个类中,并将这些参数提取为这个类的属性;

  • 场景2: 当需要根据一个模板来创建某些东西时,可以通过类来完成。

名词解释

类:一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型、模板。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法

属性:人类包含很多特征,把这些特征用程序来描述的话,叫做属性,比如年龄、身高、性别、姓名等都叫做属性,一个类中,可以有多个属性

方法:人类不止有身高、年龄、性别这些属性,还能做好多事情,比如说话、走路、吃饭等,相比较于属性是名词,说话、走路是动词,这些动词用程序来描述就叫做方法。

实例(对象):一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同

实例化:把一个类生产一个对象的过程就叫实例化

在软件系统运行时,类将被实例化成对象(Object),对象对应于某个具体的事物,是类的实例(Instance)

类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体。

在现实世界中:先有对象,再有类

在现实世界中:先有对象,再有类:世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念

在程序中:务必保证先定义类,后产生对象

这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类

不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象

例子:用嵌套函数来定义一个学校类

def school(name,addr,type):

    def init(name,addr,type):
sch = {
"name":name,
"addr":addr,
"type":type,
"enrol_students":enrol_students,
"exam":exam
}
return sch def enrol_students(school):
print("%s正在招生"%school["name"]) def exam(school):
print("%s正在考试"%school["name"]) return init(name,addr,type)
s1 = school("清华","北京","公立")
s1["enrol_students"](s1)

  

二、类属性

类有两种属性:数据属性和函数属性

对象只有数据属性,但是可以访问类的函数属性

1. 类的数据属性是所有对象共享的

2. 类的函数属性是绑定给对象用的

类中定义的函数(没有被任何装饰器装饰的)是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数。

类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法。

强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)

增删查改类的数据属性

  
  class Chinese:
country = "China"

def __init__(self,name):
self.name = name

p1 = Chinese("nick")
# 查看类数据属性
print(Chinese.country)

# 增加类数据属性
Chinese.minority = 56
print(Chinese.__dict__)
print(p1.country) #China
print(p1.minority) # 56 通过实例对象可以调用类的数据属性

# 修改类数据属性
Chinese.country = "CHINA"
print(Chinese.__dict__)



# 删除类数据属性
del Chinese.minority
print(Chinese.__dict__)

  

增删查改类的函数属性

  
  class Chinese:
country = "China"

def __init__(self,name):
self.name = name

def buy_house(self,house):
print("%s正在买%s"%(self.name,house))

p1 = Chinese("nick")
# 查看类函数属性
Chinese.buy_house(p1,"别墅")


# 增加类函数属性
def shopping(self,place):
print("%s正在%s买买买"%(self.name,place))

Chinese.shopping = shopping
p1.shopping("巴黎")


# 修改类函数属性
def test(self,msg):
print("test")
Chinese.buy_house = test
p1.buy_house("msg")


# 删除类函数属性
print(Chinese.__dict__)
del Chinese.buy_house
print(Chinese.__dict__)

  

增删查改对象的属性

  
  class Chinese:
country = "China"

def __init__(self,name,age):
self.name = name
self.age = age

def buy_house(self,house):
print("%s正在买%s"%(self.name,house))

p1 = Chinese("nick",18)
# 查看对象属性
print(p1.age)
print(p1.buy_house) #对象与类的函数方法绑定了

# 增加对象的属性
p1.gender = "male" #增加对象的数据属性
print(p1.__dict__)

def shopping(self,place):
# 增加对象的函数属性,对象原本只有数据属性,这里增加的函数属性需要自己调用自己,无法用到类的__init__方法。
print("%s正在%s买买买"%(self.name,place))
p1.shopping = shopping
p1.shopping(p1,"巴黎")
print(p1.shopping) #只是普通函数,不是对象的绑定方法,每个对象需要存储函数属性,无法实现类的方法优化
print(p1.__dict__)

# 修改对象属性
p1.age = 20 #修改对象的数据属性
print(p1.age) #20

# 不要修改对象的底层字典
p1.__dict__["age"] = 21
print(p1.age)


# 删除类函数属性
del p1.age
print(p1.__dict__)

  

注意

例子1

  
  class Chinese:
country = "China"
li = ["a"]
def __init__(self,name,age):
self.name = name
self.age = age

def buy_house(self,house):
print("%s正在买%s"%(self.name,house))

p1 = Chinese("nick",18)
p1.li = [12,3] #这里修改的是对象p1的l数据属性,相当于新增加p1的li数据属性
print(p1.__dict__)
p1.li.append("b") #由于p1自己没有li数据属性,这里增加的是类的数据属性
print(p1.__dict__)
print(Chinese.__dict__)

  


例子2

  
  country = "中国"
class Chinese:
country = "China"

def __init__(self,name,age):
self.name = name
self.age = age
print("---",country) #这里的country调用的结果是“中国”,而非"China",这里的这个country,只是一个普通的变量
def buy_house(self,house):
print("%s正在买%s"%(self.name,house))

p1 = Chinese("nick",18)

  

Python内置类属性

  
  __dict__ : 类的属性(包含一个字典,由类的数据属性组成),一个字典,保存类的所有的成员(包括属性和方法)或实例对象中的所有成员属性

__doc__ :类的文档字符串,类的描述信息

__name__: 类名

__module__: 类定义所在的模块(类的全名是'main.className',如果类位于一个导入模块mymod中,那么className.module 等于 mymod)。表示当前操作的对象对应的类的定义所在的模块名

__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

  

构造方法

__init__(...)被称为 构造方法或初始化方法,在例实例化过程中自动执行,目的是初始化实例的一些属性。每个实例通过__init__初始化的属性都是独有的

主要作用是实例化时给实例一些初始化参数,或执行一些其它的初始化工作,总之,因为这个__init__只要一实例化,就会自动执行。

普通方法

定义类的一些正常功能,就是类中没有任何装饰器的普通自定义函数。

或者这样分类

类的成员可以分为三大类:字段、方法和属性

(一)字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,

  • 普通字段属于对象

  • 静态字段属于

  
  class Province:

# 静态字段
country = '中国'

def __init__(self, name):

# 普通字段
self.name = name


# 直接访问普通字段
obj = Province('河北省')
print obj.name

# 直接访问静态字段
Province.country

  

  字段的定义和使用

分析:由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。

  • 静态字段在内存中只保存一份

  • 普通字段在每个对象中都要保存一份

(二)方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;(就是类中没有任何装饰器的函数)

  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls

  • 静态方法:由调用;无默认参数;

  
  class Foo:

def __init__(self, name):
self.name = name

def ord_func(self):
""" 定义普通方法,至少有一个self参数 """

# print self.name
print '普通方法'

@classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """

print '类方法'

@staticmethod
def static_func():
""" 定义静态方法 ,无默认参数"""

print '静态方法'


# 调用普通方法
f = Foo()
f.ord_func()

# 调用类方法
Foo.class_func()

# 调用静态方法
Foo.static_func()

  


方法的定义和使用

(三)属性

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器(装饰器方式:在类的普通方法上应用@property装饰器)

  • 静态字段 即:在类中定义值为property对象的静态字段


例子

  
  class Goods(object):

@property
def price(self):
print '@property'

obj = Goods()
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值

  

参考链接

[1]http://www.cnblogs.com/yyds/p/7591804.html

[2]http://www.cnblogs.com/linhaifeng/articles/6182264.html

[3]https://www.cnblogs.com/wupeiqi/p/4766801.html

上一篇:Python之路(第二十九篇) 面向对象进阶:内置方法补充、异常处理


下一篇:pv命令监控Linux命令的执行进度