面向对象的编程简要概括就是将要处理的问题抽象为数据和操作的集合,用类对其进行封装。其中数据和操作都称为类的属性,它们是一般是不变的。

对类进行实例化生成我们所说的对象,对象有自己的属性。对象的属性一般是个性化的,不同的对象可能具有不同的属性。同一个类的所有对象都共享类的属性。

对象属性的查找顺序为:对象自身 --> 类 --> 类的祖先类

在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 初始化方法

类的实例化过程:

  1. 实例化出一个对象
  2. 自动调用特殊方法 __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面向对象编程 -- 基本概念的更多相关文章

  1. python面向对象编程学习

    python面向对象编程 基本概念理解 面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...

  2. python 面向对象编程(一)

    一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法. 类是对现实世界中一些事物的封装,定义一个类可以采用下面的方式来定义: class c ...

  3. python面向对象编程进阶

    python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...

  4. Python面向对象编程——继承与派生

    Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...

  5. 图解python | 面向对象编程

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/56 本文地址:http://www.showmeai.tech/article-det ...

  6. python 面向对象编程学习

    1. 问题:将所有代码放入一个py文件:无法维护 方案:如果将代码才分放到多个py文件,好处: 1. 同一个名字的变量互相不影响 2.易于维护 3.引用模块: import module 2.包:解决 ...

  7. Python面向对象编程指南

    Python面向对象编程指南(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1SbD4gum4yGcUruH9icTPCQ 提取码:fzk5 复制这段内容后打开百度网 ...

  8. Python面向对象编程(下)

    本文主要通过几个实例介绍Python面向对象编程中的封装.继承.多态三大特性. 封装性 我们还是继续来看下上文中的例子,使用Student类创建一个对象,并修改对象的属性.代码如下: #-*- cod ...

  9. Python 面向对象编程——访问限制

    <无访问限制的对象> 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑.但是,从前面Student类的定义来看(见:Py ...

随机推荐

  1. oninput和onchange的区别

    菜鸟教程: oninput事件:HTML5标准事件 当用户向<input>中尝试输入时执行JavaScript: <input type="text" oninp ...

  2. mongodb的安装方法

    下载安装 mongodb官网下载地址:https://www.mongodb.org/downloads#produc...直接下载.msi文件并安装到指定目录即可.我的安装路径是D:\mongodb ...

  3. vscode git设置远程仓库码云

    https://www.cnblogs.com/klsw/p/9080041.html

  4. Redis 禁用FLUSHALL FLUSHDB KEYS 命令

      (error) ERR unknown command 'keys'问题解决(error) ERR unknown command 'FLUSHDB' 问题解决 背景 FLUSHALL FLUSH ...

  5. tensorflow点滴笔记

    1.模型保存 模型保存需要使用函数 tf.train.Saver(), a)创建saver时,可以指定需要存储的tensor,如果没有指定,则全部保存. b) 创建saver时,可以指定保存的模型个数 ...

  6. U68464 滑稽树上滑稽果(guo)

    U68464 滑稽树上滑稽果(guo) 题目描述 小小迪有 n 个约会对象,每个对象有一个约会时长 p[i],小小迪 想尽可能多的去完成他的约会(假设小小迪可以瞬移),每个对象还有 一个忍耐时间 q[ ...

  7. HTML5获取地理位置信息

    <!DOCTYPE html> <html> <head> <title>Location</title> <meta charset ...

  8. oracle复习(一)

    一.系统操作cmd->sqlplus / as sysdba; //以管理员身份登录数据库alter user system account unlock; //解锁用户systemalter ...

  9. 微服务配合docker使用

    1.docker 安装 rabbitmq 启动脚本: docker run -d --name rabbitmq --publish : \ --publish : --publish : --pub ...

  10. nginx-添加禁止访问规则

    location ~* /application/(admin|index)/static/.*$ { allow all; } location ~* /(applicaion|addos|coe| ...