Python 面向对象(上)
一. 什么是面向对象?
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() 方法, 如果子类自己没有, 才会去父类中寻找.
参考资料:
2. 《python 实例方法,类方法,静态方法的区别与作用》-- 蔷薇&Nina的博客园
3. 《面向对象 - 属性》-- 原创作者sjmicosoft
4. 《面向对象程序设计概述 牛咏梅》-- 对立·统一 转载
Python 面向对象(上)的更多相关文章
- python面向对象(上)
创建类 Python 类使用 class 关键字来创建.简单的类的声明可以是关键字后紧跟类名: class ClassName(bases): 'class documentation string' ...
- Python 面向对象(下)
本篇博客承接自Python 面向对象(上) 四. 继承,实现,依赖,关联,聚合,组合 Python面向对象--继承,实现,依赖,关联,聚合,组合 五. 特殊成员 Python面向对象--类的特殊成员 ...
- python学习笔记六 初识面向对象上(基础篇)
python面向对象 面向对象编程(Object-Oriented Programming )介绍 对于编程语言的初学者来讲,OOP不是一个很容易理解的编程方式,虽然大家都知道OOP的三大特性 ...
- Python开发【第七篇】:面向对象 和 python面向对象(初级篇)(上)
Python 面向对象(初级篇) 51CTO同步发布地址:http://3060674.blog.51cto.com/3050674/1689163 概述 面向过程:根据业务逻辑从上到下写垒代码 ...
- Python面向对象编程(上)
Python不仅支持面向过程编程,同时也支持面向对象编程.面向工程就是分析解决问题所需的步骤,然后用函数把这些步骤逐一实现,使用的时候再一个个调用函数就可以.面向对象则是把解决的问题按照一定规则划分为 ...
- python 面向对象初级篇
Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...
- Python 面向对象 基础
编程范式概述:面向过程 和 面向对象 以及函数式编程 面向过程:(Procedure Oriented)是一种以事件为中心的编程思想. 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现 ...
- python面向对象进阶(八)
上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- python 面向对象(进阶篇)
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
随机推荐
- 【Java基础 项目实例 -- Bank项目2】Account 和 customer 对象
总结: customer.setAccount(account); //引用,日后的account 和 customer.getAccount()的结果始终一致 实验目的 扩展银行项目,添加一个 Cu ...
- shell脚本中case /*的作用
如下语句 case $0 in /*) ;; *) ;; /*在这里的作用就是绝对路径的意思
- config.json读取和存储
json格式的配置文件的读取和存储 public class ConfigHelper { public static T GetConfig<T>(string path) { if ( ...
- 关于github报错 ssh: connect to host github.com port 22: Connection timed out fatal: Could not read from remote repository.
今天上午写demo的时候,突然pull不下代码了,报了一下这样情况的错误: 看了一下代码,怀疑是网路错误,因为在这以前一切都正常的,然后将代码复制搜索了一番,解决办法有很多什么配置config啦,gi ...
- 干物妹小埋 (离散化 + 线段树 + DP)
链接:https://ac.nowcoder.com/acm/contest/992/B来源:牛客网 题目描述 在之前很火的一个动漫<干物妹小埋>中,大家对小埋打游戏喝可乐的印象十分的深刻 ...
- 11 canvas 画布 - 基础
一.概述 canvas它和其它的HTML5标签的使用基本一致,但是它相当于在浏览器中建立一个画布,可以再这个画布上画图.创建动画甚至是3D游戏.由于canvas要适配不同终端的分辨率,所以尽可能的在标 ...
- Series和Dataframe分组时使用groupby函数的区别
1. Dataframe分组用groupby("列名")或者groupby(["列名1","列名2"]) import pandas as ...
- Qt 模型/视图结构
MVC是一种与用户界面相关的设计模式.通过使用此模型,可以有效地分离数据和用户界面.MVC设计模式包含三要素:表示数据的模型(Model).表示用户界面的视图(View)和定义了用户在界面上的操作控制 ...
- 1、docker简介:课程定位、是什么、能干什么、下载
1.前提知识和定位 2.是什么 1.为什么会有docker出现 环境配置如此麻烦,换一台机器,就要重来一次,费力费时.很多人想到,能不能从根本上解决问题,软件可以带环境安装? 也就是说,安装的时候,把 ...
- linux 下python进程查看及关闭
查看进程 ps -ef |grep python 关闭进程 kill -9 26879 其中26879为进程号. linux下后台执行某个python脚本 nohup python -u xxx.py ...