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 ...
随机推荐
- 小程序获取当前页面URL
var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length-1] //获取当前页面的对象 var url ...
- ssh 登陆服务器原理
这里分两种情况,这两种情况都涉及到公钥加密的概念. 由于公钥加密概念作为基础就不在本文进行讨论了. 使用ssh对远程服务器进行密码登录发生了什么: 客户端通过ssh连接服务器 1. 首先服务器把自己的 ...
- 解决spring多线程不共享事务的问题
在一个事务中使用多线程操作数据库时,若同时存在对数据库的读写操作,可能出现数据读取的不准确,因为多线程将不会共享同一个事务(也就是说子线程和主线程的事务不一样),为了解决这个问题,可以使用spring ...
- JQuery跳出each循环的方法(包含数组遍历)
0. 前言 也许我们通过 jquery 的循环方法进行数组遍历,但是当不符合条件时,怎么跳出当前循环?(即用each方法内,当不满足条件时想break跳出循环体,想continue继续执行下一个循环遍 ...
- opencv imdecode和imencode用法
主要是对内存数据自动编解码 string fname = "D:/image.jpg"; //! 以二进制流方式读取图片到内存 FILE* pFile = fopen(fname. ...
- 思路:当一个表嵌套另一个表时候 只需在dao中引入该mapper即可 进行正常的数据插入 查询 修改等
- Spring 使用介绍(四)—— SpEL
一.SpEL介绍 Spring表达式语言全称为“Spring Expression Language”,缩写为“SpEL”,可在运行时构建复杂表达式 使用步骤: 1)创建解析器:ExpressionP ...
- kubernetes 编排详解 挂载
##kube挂载本地磁盘apiVersion: v1 kind: Pod metadata: name: redis spec: containers: - name: redis image: re ...
- BZOJ3224普通平衡树——旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- Educational Codeforces Round 60 Div. 2
F:考虑对于每个字母对求出删掉哪些字符集会造成字符串不合法,只要考虑相邻出现的该字母对即可,显然这可以在O(np2)(或小常数O(np3))内求出.然后再对每个字符集判断是否能通过一步删除转移而来即可 ...