一. 什么是面向对象?

1. 在了解面向对象之前,首先我们需要知道两个概念:
(1)什么是函数?
函数是对功能或动作的一种封装.
函数的语法结构如下:

def func(arg1):
'''函数的内部有函数体'''
print("这里是函数内部") func(arg2)

上面的结构中, func是函数名, arg1是形参, 在函数的内部是函数体. 在定义了函数以后, 我们只需要在下面 用函数名接上一个小括号( func() ) 就可以调用函数了, 小括号内部的 arg2 表示实参.

(2)什么是变量?
在程序设计中, 变量是一个可以存储值的字母或名称, 它是程序运行过程中产生的值, 被用来提供给后面的程序使用.  如 a = 10, 我们把 10 这个值赋给变量 a.

2. 面向过程与面向对象

在了解了以上两个概念以后, 我们现在可以开始讨论什么是面向对象了.

(1)从我们最初接触编程开始, 我们就使用一些关键词, 诸如 if, else, while 等等, 来帮助我们规范程序的逻辑, 按照我们的想法使程序运行下去. 实际上, 这种编程思想就是"面向过程", 我们可以用更加正式的语言来描述面向过程:

面向过程: 一切以事物的流程为核心. 根据业务逻辑(即事物的发展过程, 动作的先后顺序)从上到下写垒代码, 其核心在于"流程(过程)".

优点: 把一个事件步骤化,流程化, 程序编写相对简单.
缺点: 可扩展性差(甚至可以说是极差).

(2)于是我们现在引出一个概念 -- 面向对象.

面向对象: 一切以对象为中心. 对象是属性和动作的集合体. 面向对象就是指对函数进行分类和封装.

优点: 可扩展性强(体现在继承和多态上)
缺点: 编程的复杂程度高于面向过程

简单来说, 最开始接触编程时, 我们的思维,我们的思想是 专注于事物发展过程,动作先后顺序的. 然而, 面向对象却与之截然不同, 这种思维专注于事物这个对象本身, 处于这种思维之下, 可以认为世间万物皆是对象. 我们曾经关注的那些事物的动作和发展顺序, 在面向对象的思维中, 他们都是对象的属性, 于是, 无数包含着各种属性的对象就组成了我们的整个世界.

二. 什么是面向对象编程?

1. 类(Class)

类(Class): 用来描述具有相同的属性和方法的对象的集合体. 它定义了该集合体中每个对象所共有的属性和方法. 对象是类的实例.

class Foo:
pass # class -- 关键字, 表示创建类
# Foo -- 类名

2. 实例化

实例化:创建一个类的实例,类的具体对象

class Foo:

    def __init__(self, property1, property2)
self.property1 = property1
self.property2 = property2 obj = Foo("属性1", "属性2") # Foo() -- 类的实例化
# obj = Foo() -- 把Foo实例化为obj, obj被称为实例对象(简称为"对象")
# "属性1", "属性2" 分别被传给参数 property1, property2

3. 成员

成员: 在类中定义的变量和方法都被称为成员.
成员分类: 变量, 方法, 属性

class Foo:
class_variable = "这里是类变量" def __init__(self, property):
"""__init__用于初始化一个类"""
self.property = property
self.instance_variable = "实例变量"
"""这里的self.xxx都属于实例变量""" def instance_method(self):
"""实例方法必须有参数self"""
print("这里是实例方法") @classmethod
def class_method(cls):
"""类方法必须有参数cls,这里cls传递的是类名Foo"""
obj = cls("普通属性")
print("这里是类方法", obj) @staticmethod
def static_method():
"""静态方法对参数没有固定要求,根据实际需要即可"""
print("这里是静态方法") @property
def dynamic_property(self):
return "这里是动态属性"

举例说明

3.1 变量: 实例变量, 类变量(静态变量)

(1)实例变量

实例变量:定义在方法中的变量,只作用于当前实例的类.

class Foo:

    def __init__(self, property):
"""__init__用于初始化一个类,它是构造方法"""
self.property = property
self.instance_variable = "实例变量"
"""这里的self.xxx都属于实例变量""" obj = Foo("普通属性") # 类Foo实例化为对象obj
s = obj.instance_variable # 对象obj访问实例变量
print(s) # 输出结果为: 实例变量

(2)类变量(静态变量)

类变量:在Java中类变量也被称为静态变量. Python中类变量在整个实例化的对象中是公用的. 类变量定义在类中且在函数体之外. 约定俗成, 类变量通常不作为实例变量使用.

class Foo:
class_variable = "这里是类变量" obj = Foo() # 实例化
print(Foo.class_variable) # 这里用类名Foo去访问类变量class_variable # 输出结果:
# 这里是类变量

3.2 方法: 在类的内部定义的函数. 分为实例方法, 类方法和静态方法

(1)实例方法

定义: 第一个参数必须是实例对象, 该参数名一般约定为“self”, 通过它来传递实例的属性和方法(也可以传类的属性和方法)

调用: 约定俗成由实例对象调用

class Foo:

    def instance_method(self):
"""实例方法必须有参数self"""
print("这里是实例方法") obj = Foo() # 类Foo实例化为对象obj
obj.instance_method() # 实例对象调用实例方法 # 输出结果:
# 这里是实例方法

(2)类方法

定义:使用装饰器@classmethod. 第一个参数必须是当前类对象, 该参数名一般约定为“cls”, 通过它来传递类的属性和方法(不能传实例对象的属性和方法)

调用:实例对象和类对象都可以调用.

class Foo:

    @classmethod
def class_method(cls):
"""类方法必须有参数cls,这里cls传递的是类名Foo"""
s = cls("普通属性")
print("这里是类方法: ", s) obj = Foo()
obj.class_method() # 输出结果:
# 这里是类方法: <__main__.Foo object at 0x0000016B9B8DAD68>

(3)静态方法

定义:使用装饰器@staticmethod. 参数随意, 没有强制要求必须是“self”或“cls”参数, 但是静态方法的方法体中不能使用类或实例的任何属性和方法.

调用:实例对象和类对象都可以调用.

class Foo:

    @staticmethod
def static_method():
"""静态方法对参数没有固定要求,可以根据实际需要进行设置"""
print("这里是静态方法") obj = Foo()
obj.static_method() # 输出结果:
# 这里是静态方法

3.3 属性(两种形式): 字段的访问形式, 方法的表现形式

class Person:

    """字段的访问形式"""
def __init__(self, name, gender):
self.name = name
self.gender = gender """方法的表现形式"""
@property
def age(self):
"""这里是关于年龄的函数体"""
return 18

举例说明

(1)字段的访问形式

class Person:

    """字段的访问形式"""
def __init__(self, name, gender):
self.name = name
self.gender = gender p = Person("张三", "男")
print(p.name) # 输出结果: 张三
print(p.gender) # 输出结果: 男

字段的访问形式是最常用,最普遍的

(2)方法的表现形式

class Person:

    """方法的表现形式"""
@property
def age(self):
"""这里是关于年龄的函数体"""
return 18 p = Person()
print(p.age) # 输出结果: 18

由于对象的某些属性并不一定是固定不变的, 它可能会随着条件的改变而发生改变, 于是, 我们可以 "用方法来描述我们的属性信息".
需要格外注意的是:

"属性--方法的表现形式"有以下特点:

1. 必须在方法的上方用 @property 来进行声明
2. 该方法有且仅有一个参数 self
3. 该方法必须有返回值

4. 私有成员

私有成员只能在自己的类中访问, 在类的外部无法直接访问.

class Liu_de_hua:    # 创建一个类
nickname = "华仔" # 类变量
gender = "男"
__real_age = 57 # 私有成员 def __init__(self, age, wife=None): # 构造方法
self.age = age # 实例变量
self.wife = wife
self.__wife = "朱丽倩" # 私有成员 def act(self): # 实例方法
print("我会表演") def date(self): # 实例方法
print("我常常和%s约会" % self.__wife) # 在实例方法内部访问私有成员 ldh = Liu_de_hua(48) print(ldh.wife) # 实例对象访问实例变量
ldh.date() # 实例对象访问实例方法
print(ldh.__wife) # 尝试用实例对象访问私有成员 # 执行结果:
# None
# 我常常和朱丽倩约会
# 报错: 'Liu_de_hua' object has no attribute '__wife'

私有成员的特征:

1. 私有成员必须以 双下划线 开头, 如上面代码中的 __real_age 和 __wife .
2. 我们可以在类的内部随意访问私有成员, 但在外部则不行.

三. 面向对象三大特性: 封装, 继承, 多态

关于面向对象更加准确更加规范的语言表述, 大家可以点击这里进行查看

1. 封装: 把内容(属性或方法)封装到一个对象中, 之后调用的时候直接通过对象即可调用它们.

(1)将内容封装到对象中

class Person:
def __init__(self, name, year_of_birth, gender):
self.name = name
self.year_of_birth = year_of_birth
self.gender = gender p1 = Person("刘德华", "", "男")
p2 = Person("王菲", "", "女") # 实例化对象p1, 将 '刘德华', '1961', '男' 分别封装到了对象p1(对象p1等同于self)内的 'name', 'year_of_birth', 'gender' 属性中
# p2也是同样的运行过程

(2)用对象去调用被封装的内容

class Person:

    def __init__(self, name, year_of_birth, gender):
self.name = name
self.year_of_birth = year_of_birth
self.gender = gender p1 = Person("刘德华", "", "男")
p2 = Person("王菲", "", "女") print(p1.name) # 输出结果: 刘德华
print(p2.name) # 输出结果: 王菲

2. 继承: 子类继承父类, 子类可以继承父类中除了私有内容外的其他所有内容. Python支持多继承.

class Foo1:

    __private1 = "我是父类1的私有内容1"
class_variables1 = "我是父类1的类变量1" def instance_method1(self):
print("我是实例方法1, 我在父类1的内部") class Foo2: __private2 = "我是父类2的私有内容2"
class_variables2 = "我是父类2的类变量2" def instance_method2(self):
print("我是实例方法2, 我在父类2的内部") class Bar(Foo1, Foo2): def func(self):
print("我是子类") b = Bar() # 实例化 print(b.class_variables1) # 子类调用类变量1
b.instance_method1()    # 子类调用实例方法1 print(b.class_variables1) # 子类调用类变量2
b.instance_method2()     # 子类调用实例方法2 # 以上执行结果为:
# 我是父类1的类变量1
# 我是实例方法1, 我在父类1的内部
# 我是父类1的类变量1
# 我是实例方法2, 我在父类2的内部

需要注意的是: 子类无法调用父类的私有内容, 例如在上面代码中, 如果用对象b去访问__private1则会报错.

3. 多态: 一个对象有多种形态.

在Python中, 多态无处不在, 因而我们无法用语言去准确描述什么是python中的多态. 或许这既是python的优点也是它的缺点吧.
我们只能用例子来简单说明一下python中的多态, 辅助理解:

class Animal:
def chi(self):
print("吃是动物的本能") class Haski(Animal):
def chi(self):
print("哈士奇逗比作死地吃") class Monkey(Animal):
def chi(self):
print("猴子张牙舞爪地吃") class si_yang_yuan:
def wei_yang(self, animal):
animal.chi() # 把动物全部实例化
dong_wu = Animal()
er_ha = Haski()
hou_zi = Monkey() # 把饲养员实例化
syy = si_yang_yuan() # 饲养员喂动物
syy.wei_yang(dong_wu)
syy.wei_yang(er_ha)
syy.wei_yang(hou_zi) # 执行结果:
# 吃是动物的本能
# 哈士奇逗比作死地吃
# 猴子张牙舞爪地吃

从上面的例子中可以看出:
当子类和父类存在相同的 chi() 方法时, 子类的 chi() 覆盖了父类的 chi(). 当子类调用chi()时, 会首先调用子类自己的 chi() 方法, 如果子类自己没有, 才会去父类中寻找.

参考资料:

1. 《面向对象三大特性介绍》-- heroliy的博客园

2. 《python 实例方法,类方法,静态方法的区别与作用》-- 蔷薇&Nina的博客园

3. 《面向对象 - 属性》-- 原创作者sjmicosoft

4. 《面向对象程序设计概述 牛咏梅》-- 对立·统一 转载

Python 面向对象(上)的更多相关文章

  1. python面向对象(上)

    创建类 Python 类使用 class 关键字来创建.简单的类的声明可以是关键字后紧跟类名: class ClassName(bases): 'class documentation string' ...

  2. Python 面向对象(下)

    本篇博客承接自Python 面向对象(上) 四. 继承,实现,依赖,关联,聚合,组合 Python面向对象--继承,实现,依赖,关联,聚合,组合 五. 特殊成员 Python面向对象--类的特殊成员 ...

  3. python学习笔记六 初识面向对象上(基础篇)

    python面向对象   面向对象编程(Object-Oriented Programming )介绍   对于编程语言的初学者来讲,OOP不是一个很容易理解的编程方式,虽然大家都知道OOP的三大特性 ...

  4. Python开发【第七篇】:面向对象 和 python面向对象(初级篇)(上)

    Python 面向对象(初级篇)   51CTO同步发布地址:http://3060674.blog.51cto.com/3050674/1689163 概述 面向过程:根据业务逻辑从上到下写垒代码 ...

  5. Python面向对象编程(上)

    Python不仅支持面向过程编程,同时也支持面向对象编程.面向工程就是分析解决问题所需的步骤,然后用函数把这些步骤逐一实现,使用的时候再一个个调用函数就可以.面向对象则是把解决的问题按照一定规则划分为 ...

  6. python 面向对象初级篇

    Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...

  7. Python 面向对象 基础

    编程范式概述:面向过程 和 面向对象 以及函数式编程 面向过程:(Procedure Oriented)是一种以事件为中心的编程思想. 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现 ...

  8. python面向对象进阶(八)

    上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  9. python 面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

随机推荐

  1. WinForm DevExpress使用之ChartControl控件绘制图表二——进阶

    1. 多坐标折线图 在这个项目中,我需要做不同采集地方和不同数据类型的数据对比,自然而然就用到了多重坐标轴,多重坐标轴可以是多个X轴,也可以是Y轴,它们的处理方式类似.本文通过项目中的实际例子介绍多重 ...

  2. js文件中使用el表达式问题

    作者:Sang 单独js文件不能用el表达式. 首先,JSP是由服务端执行的,EL表达式自然也由服务端解析执行,因此如果EL所在的脚本在JSP页面内,它是可以获取到值的,这个值在服务器端返回到浏览器端 ...

  3. HDU 6088 - Rikka with Rock-paper-scissors | 2017 Multi-University Training Contest 5

    思路和任意模数FFT模板都来自 这里 看了一晚上那篇<再探快速傅里叶变换>还是懵得不行,可能水平还没到- - 只能先存个模板了,这题单模数NTT跑了5.9s,没敢写三模数NTT,可能姿势太 ...

  4. LDA的参数确定和主题数确定方法

    主题数确定:困惑度计算,画出曲线,选择拐点,避免信息丢失和主题冗余 https://blog.csdn.net/u014449866/article/details/80218054 参数调节: 方法 ...

  5. 1 Java面向对象

    0 工具 在分析面向对象时最好采用UML图进行分析设计 1 Java面向对象的特点 java采用面向对象的方法设计程序主要体现在:对象有属性和方法,事件的发生是对象间的信息交互产生的即程序中的get ...

  6. [Luogu] 选择客栈

    https://www.luogu.org/problemnew/show/P1311 思路就是,从1到n枚举,输入color和price的值,我们需要记录一个距离第二个客栈最近的咖啡厅价钱合理的客栈 ...

  7. redis,memcached,mongodb之间的区别

    Redis Redis的优点: 支持多种数据结构,如 string(字符串). list(双向链表).dict(hash表).set(集合).zset(排序set).hyperloglog(基数估算) ...

  8. OUC_TeamTraining_#1 720

    D - The Mirror of Galadriel Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %l ...

  9. FFmpeg之Linux下编译与调试

    注:下面的一切都是在 root 模式下进行的,可以不再 root 模式下进行 1. 安装linux的基础环境 基础环境就是编译代码的基础库,Ubuntu联网安装软件很简单,一个语句即可搞定,这里列出语 ...

  10. jetbrains 2019 激活 error 1653219 解决办法

    我以前用PyCharm按照http://idea.lanyus.com/上的激活码直接可激活. 后来用到IDEA(最新版)了之后激活报错.错误代码为1653219. 后参考博客 解决办法: 把host ...