python面向对象编程 -- 基本概念
面向对象的编程简要概括就是将要处理的问题抽象为数据和操作的集合,用类对其进行封装。其中数据和操作都称为类的属性,它们是一般是不变的。
对类进行实例化生成我们所说的对象,对象有自己的属性。对象的属性一般是个性化的,不同的对象可能具有不同的属性。同一个类的所有对象都共享类的属性。
对象属性的查找顺序为:对象自身 --> 类 --> 类的祖先类
在python中一切皆对象。
以下我们讨论python中类相关的概念和语法。
1、类的定义
class ClassName:
<statement-1>
.
.
.
<statement-N>
- 类定义必须使用class关键字
- 类名最好使用大驼峰,如ClassName, 这是一种约定
- 当输入类定义时,一个新的命名空间产生,在类中定义的所有本地变量都放入这个新的命名空间。
- 命名空间中的所有变量都是类的属性。类属性主要分为两类,数据属性(变量)和函数。
- 语句块执行完成后,生成一个类对象绑定到ClassName。ClassName的作用域由它的定义的位置决定。
python中一切皆对象,类也是对象,它是type类的实例。可以用 obj.__class__来查看一个对象是由那个类实例化而来的。
类中可以使用任何合法的语句,不过实际应用中,主要是赋值语句和函数定义。
2、类对象
下面的代码定义了一个 Chinese 类:
class Chinese:
"""A sample example class"""
nationality = 'China' def display(self):
print(self, 'I am Chinese!', sep=', ') for name, value in sorted(Chinese.__dict__.items(), key=lambda x: x[0]):
print(name, '==>', value)
类定义会生成一个新的命名空间,其中包含了所有在类本地定义的变量,也就是类的属性。这些属性可以在类的 __dict__属性中查看,可以将其近似等价于类的命名空间。其中 __name__形式的属性为特殊属性。
print(type(Chinese.__dict__)) # <class 'mappingproxy'>
for name, value in sorted(Chinese.__dict__.items(), key=lambda x: x[0]):
print(name, '==>', value) # __dict__ ==> <attribute '__dict__' of 'Chinese' objects>
# __doc__ ==> A sample example class
# __module__ ==> __main__
# __weakref__ ==> <attribute '__weakref__' of 'Chinese' objects>
# display ==> <function Chinese.display at 0x1020759d8>
# nationality ==> China
- __dict__ 在类定义的时候自动生成。
- __doc__ 类定义的时候自动生成。值为类定义语句块内第一行,类的文档字符串,由三引号引用。如果没有值为None。
- __module__ 类定义所在的模块,自动添加的属性。如果是正在执行的模块,值为 __main__
- __weakref__
- display 和 nationality 用户定义属性
python中属性的引用都是通过obj.name 的形式,name为对象 obj 的属性。类中的所有属性都可以通过obj.name 的形式引用。比如该类的两个用户自定义属性:数据属性 nationality 和 函数 display:
print(Chinese.nationality) # China
print(Chinese.display) # <function Chinese.display at 0x1021759d8>
Chinese.display(1) # 1, I am Chinese!
通过类引用函数并对其进行调用,与普通的函数调用没有差异。不过,在类中定义的函数一般是给实例使用的,不建议直接通过类引用,下面会进一步说明。
3、类实例化
类的实例化使用和函数调用类似的语法。
xm = Chinese()
上面的语句创建了一个新的Chinese类的实例,并将其赋值给 xm 变量。实例有自己的命名空间:
print(xm.__dict__) # {}
可以看到 xm.__dict__ 的返回值是一个空字典,实例 xm没有自己的属性。可以直接通过 xm.name = 'xiaoming' 的形式为实例添加属性。也可以通过 del xm.name 删除该属性:
xm.name = 'xiaoming'
print(xm.__dict__) # {'name': 'xiaoming'}
del xm.name
print(xm.__dict__) # {}
如果类的所有实例都具有某些属性,只是属性的值不同,可以通过定义实例的初始化方法,在方法中为实例添加属性。
3.1 初始化方法
类的实例化过程:
- 实例化出一个对象
- 自动调用特殊方法 __init__对产生的对象初始化。如果类中没有定义会在父类(父类的概念之后说明)中查找该方法。
我们称__init__方法为实例的初始化方法, __init__方法中不要写返回值,默认返回None。
一般在实例初始化方法中会定义实例的个性化属性,这些属性是实例私有的,可以通过实例的__dict__属性查看。实例的属性不会影响类的属性,换句话说类不能引用实例的属性。
下面是对Chinese类的扩展:
class Chinese:
"""A sample example class"""
nationality = 'China' def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender def display(self):
print(self, 'I am Chinese!', sep=', ') xm = Chinese('xiaoming', 18, 'male')
print(xm.__dict__) # {'name': 'xiaoming', 'gender': 'male', 'age': 18}
print(Chinese.__dict__.keys())
# dict_keys(['__weakref__', '__module__', '__dict__', '__init__', 'nationality', 'display', '__doc__'])
self指代引用该方法的实例(具体实现在4.1介绍),实例化操作的参数列表化传递给__init__方法,Chinese('xiaoming', 18, 'male') --> xm.__init__('xiaoming', 18, 'male')
3.2 实例的类
查看对象的类:
- obj.__class__
- type(obj)
print(xm.__class__)
print(type(xm))
# <class '__main__.Chinese'>
# <class '__main__.Chinese'>
判断一个对象是不是某个类的实例:isinstance(obj, ClassName)
print(isinstance(xm, Chinese))
# True
4 实例
实例可以操作两种属性:数据属性和方法
print(xm.name, xm.age, xm.gender, sep=', ') # xiaoming, 18, male
print(xm.nationality, xm.display, sep=', ')
# China, <bound method Chinese.display of <__main__.Chinese object at 0x10217c898>>
有上面的代码可以看到实例不仅可以引用自己的属性,也可以引用类的属性。类属性可以被它的实例共享。
值得注意的是,实例对类的函数的引用。其返回值并不是一个函数对象而是一个"bound method"绑定的方法对象。尝试调用这个对象:
xm.display(1)
# Traceback (most recent call last):
# File "test.py", line 28, in <module>
# xm.display(1)
# TypeError: display() takes 1 positional argument but 2 were given
xm.display() # <__main__.Chinese object at 0x10217c7f0>, I am Chinese!
display函数要求传入一个位置参数,第1行给方法传入一个参数1,调用出错,错误信息告诉我们多传入了一个位置参数。
再次调用,不传参,竟然能够正常调用了!why?函数打印了传入的值,"<__main__.Chinese object at 0x10217c7f0>",表明出入的是一个Chinese对象,在本例中只能是 xm。这是怎么实现的呢?
4.1 实例方法
print(Chinese.display)
print(xm.display)
print(Chinese.display is xm.display) # <function Chinese.display at 0x1021759d8>
# <bound method Chinese.display of <__main__.Chinese object at 0x10217c7f0>>
# False
分别通过类和实例引用display属性,返回的并不是同一个对象:通过类引用返回一个函数对象;通过实例引用返回一个"bound method"绑定的方法对象。
- 方法:属于某个对象的函数。当通过对象(实例)引用一个类的属性,且该属性对应一个函数对象时,函数和实例绑定返回一个方法对象。可以通过方法对象的__self__ 和 __func__ 属性查看对应的实例和方法
method = xm.display
print(method.__self__) # <__main__.Chinese object at 0x10217c7f0>
print(method.__func__) # <function Chinese.display at 0x1021759d8> - 方法对象是可调用的,方法的调用即其对应的类的函数属性的调用,特殊之处在于会将其实例作为第一个参数传给函数,等价形式为:method(*args, **kwargs) ==> method.__func__(method.__self__, **args, **kwargs)。在本例中xm.display() 等价于Chinese.display(xm)。简要概括来说就是,方法对应函数的第一个参数由python自动填充以引用实例对象。
- 在类中定义的函数一般至少有一个位置参数,第一个位置参数一般用'self'标识,指代引用函数的实例。这是一个约定,可以用任意其他合法标识符替代,为了代码的可读性,不建议这么做。
- 类中定义的函数对应到实例即为实例的方法。
很多资料中将类中的定义的函数都称为方法,虽然如此我们要知道未经过任何装饰器装饰的普通函数本质上依然是函数,只有在通过实例引用是才与实例绑定生成方法对象。
以上是相关的基本概念,下一篇讨论类的封装、继承相关的概念。
python面向对象编程 -- 基本概念的更多相关文章
- python面向对象编程学习
python面向对象编程 基本概念理解 面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...
- python 面向对象编程(一)
一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义: class c ...
- python面向对象编程进阶
python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...
- Python面向对象编程——继承与派生
Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...
- 图解python | 面向对象编程
作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/56 本文地址:http://www.showmeai.tech/article-det ...
- python 面向对象编程学习
1. 问题:将所有代码放入一个py文件:无法维护 方案:如果将代码才分放到多个py文件,好处: 1. 同一个名字的变量互相不影响 2.易于维护 3.引用模块: import module 2.包:解决 ...
- Python面向对象编程指南
Python面向对象编程指南(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1SbD4gum4yGcUruH9icTPCQ 提取码:fzk5 复制这段内容后打开百度网 ...
- Python面向对象编程(下)
本文主要通过几个实例介绍Python面向对象编程中的封装.继承.多态三大特性. 封装性 我们还是继续来看下上文中的例子,使用Student类创建一个对象,并修改对象的属性.代码如下: #-*- cod ...
- Python 面向对象编程——访问限制
<无访问限制的对象> 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑.但是,从前面Student类的定义来看(见:Py ...
随机推荐
- Android——MaterialDesign之三NavigationView
NavigationView的使用 这里我们来讲讲在Android5.0之后推出的NavigationView的具体使用方式.和普通的侧拉菜单制作方式一样,首先所有的东西还是都放在一个DrawerLa ...
- Gitlab中README.MD编写格式模板
README.MD文件 格式: 源码: # Hbase组件 ## Maven依赖 ``` <dependency> <groupId>catf</groupId> ...
- 1.ansible基本参数介绍
想使用ansible 先--help学习下基本的options吧小兄弟1: -m 指定模块名称只有一个模块command 可以省略:-M 指出模块路径来加载2: -a 指定模块参数就是模块的内容你知道 ...
- CF343D Water Tree
题目链接 题目翻译(摘自洛谷) 疯狂科学家Mike培养了一颗有根树,由n个节点组成.每个节点是一个要么装满水要么为空的贮水容器. 树的节点用1~n编号,其中根节点为1.对于每个节点的容器,其子节点的容 ...
- git 回退版本
回滚到指定的版本 git reset --hard e377f60e28c8b84158 强制提交 git push -f origin master
- HTML5-canvas-基础篇
<canvas>新元素 <canvas> 元素用于图形的绘制,通过脚本 (通常是JavaScript)来完成. <canvas> 标签只是图形容器,您必须使用脚本来 ...
- IntelliJ cannot log in to GitHub上传github报错解决
重装系统,新装的Intellij IDEA上新建的项目上传github失败,报错: invalid authentication token ... 此处多为本地git用户的用户名/邮箱,与之前设置的 ...
- int,String转换
int -> String 第一种方法:s=i+""; //会产生两个String对象 第二种方法:s=String.valueOf(i); //直接使用String类的静态 ...
- 基本排序算法[python实现]
冒泡排序 原理 冒泡排序(Bubble Sort)是一种简单的排序算法.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换, ...
- Android 右上角菜单栏
1 创建菜单栏 在res下新建menu文件夹,并且创建righttopmenu.xml righttopmenu.xml: <?xml version="1.0" encod ...