python面向对象——类
from:http://www.runoob.com/python3/python3-class.html
Python3 面向对象
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。
如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。
接下来我们先来简单的了解下面向对象的一些基本特征。
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。
类定义
语法格式如下:
class ClassName:
<statement-1>
.
.
.
<statement-N>
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
类对象
类对象支持两种操作:属性引用和实例化。
属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。
类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:
实例(Python 3.0+)
#!/usr/bin/python3 class MyClass:
"""一个简单的类实例"""
i = 12345
def f(self):
return 'hello world' # 实例化类
x = MyClass() # 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())
以上创建了一个新的类实例并将该对象赋给局部变量 x,x 为空的对象。
执行以上程序输出结果为:
MyClass 类的属性 i 为: 12345
MyClass 类的方法 f 输出为: hello world
很多类都倾向于将对象创建为有初始状态的。因此类可能会定义一个名为 __init__() 的特殊方法(构造方法),像下面这样:
def __init__(self):
self.data = []
类定义了 __init__() 方法的话,类的实例化操作会自动调用 __init__() 方法。所以在下例中,可以这样创建一个新的实例:
x = MyClass()
当然, __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上。例如:
实例(Python 3.0+)
#!/usr/bin/python3 class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i) # 输出结果:3.0 -4.5
self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
class Test:
def prt(self):
print(self)
print(self.__class__) t = Test()
t.prt()
以上实例执行结果为:
<__main__.Test object at 0x7f5606b6b1d0>
<class '__main__.Test'>
从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:
class Test:
def prt(runoob):
print(runoob)
print(runoob.__class__) t = Test()
t.prt()
以上实例执行结果为:
<__main__.Test object at 0x7fb55ab742e8>
<class '__main__.Test'>
类的方法
在类地内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
实例(Python 3.0+)
#!/usr/bin/python3 #类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age)) # 实例化类
p = people('runoob',10,30)
p.speak()
执行以上程序输出结果为:
runoob 说: 我 10 岁。
继承
Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义。派生类的定义如下所示:
class DerivedClassName(BaseClassName1):
<statement-1>
.
.
.
<statement-N>
需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找基类中是否包含方法。
BaseClassName(示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
实例(Python 3.0+)
#!/usr/bin/python3 #类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age)) #单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade)) s = student('ken',10,60,3)
s.speak()
执行以上程序输出结果为:
ken 说: 我 10 岁了,我在读 3 年级
多继承
Python同样有限的支持多继承形式。多继承的类定义形如下例:
class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
实例(Python 3.0+)
#!/usr/bin/python3 #类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self,n,a,w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print("%s 说: 我 %d 岁。" %(self.name,self.age)) #单继承示例
class student(people):
grade = ''
def __init__(self,n,a,w,g):
#调用父类的构函
people.__init__(self,n,a,w)
self.grade = g
#覆写父类的方法
def speak(self):
print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade)) #另一个类,多重继承之前的准备
class speaker():
topic = ''
name = ''
def __init__(self,n,t):
self.name = n
self.topic = t
def speak(self):
print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic)) #多重继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t) test = sample("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中排前地父类的方法
执行以上程序输出结果为:
我叫 Tim,我是一个演说家,我演讲的主题是 Python
方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:
#!/usr/bin/python3 class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法') class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法') c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
执行以上程序输出结果为:
调用子类方法
类属性与方法
类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类的方法
在类地内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。
self 的名字并不是规定死的,也可以使用 this,但是最好还是按照约定是用 self。
类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类地外部调用。self.__private_methods。
实例
类的私有属性实例如下:
实例(Python 3.0+)
#!/usr/bin/python3 class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量 def count(self):
self.__secretCount += 1
self.publicCount += 1
print (self.__secretCount) counter = JustCounter()
counter.count()
counter.count()
print (counter.publicCount)
print (counter.__secretCount) # 报错,实例不能访问私有变量
执行以上程序输出结果为:
1
2
2
Traceback (most recent call last):
File "test.py", line 16, in <module>
print (counter.__secretCount) # 报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute '__secretCount'
类的私有方法实例如下:
实例(Python 3.0+)
#!/usr/bin/python3 class Site:
def __init__(self, name, url):
self.name = name # public
self.__url = url # private def who(self):
print('name : ', self.name)
print('url : ', self.__url) def __foo(self): # 私有方法
print('这是私有方法') def foo(self): # 公共方法
print('这是公共方法')
self.__foo() x = Site('菜鸟教程', 'www.runoob.com')
x.who() # 正常输出
x.foo() # 正常输出
x.__foo() # 报错
以上实例执行结果:
name : 菜鸟教程
url : www.runoob.com
这是公共方法
这是私有方法
Traceback (most recent call last):
File "/home/lai/workspace/sru/2.py", line 81, in <module>
x.__foo() # 报错
AttributeError: 'Site' object has no attribute '__foo'
类的专有方法:
- __init__ : 构造函数,在生成对象时调用
- __del__ : 析构函数,释放对象时使用
- __repr__ : 打印,转换
- __setitem__ : 按照索引赋值
- __getitem__: 按照索引获取值
- __len__: 获得长度
- __cmp__: 比较运算
- __call__: 函数调用
- __add__: 加运算
- __sub__: 减运算
- __mul__: 乘运算
- __div__: 除运算
- __mod__: 求余运算
- __pow__: 乘方
运算符重载
Python同样支持运算符重载,我们可以对类的专有方法进行重载,实例如下
实例(Python 3.0+)
#!/usr/bin/python3 class Vector:
def __init__(self, a, b):
self.a = a
self.b = b def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
以上代码执行结果如下所示:
Vector(7,8)
关于上面的实例做了一些尝试来理解
1、去掉方法__str__中的return
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b def __str__(self):
'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other):
return Vector(self.a, self.b + other.b)#self和other都代表Vector的实例,且是任意的z v1 = Vector(2,10)
v2 = Vector(5,-2)
print(v1)
print(v2)
print (v1 + v2)
上面程序输出的结果
Traceback (most recent call last):
File "/home/lai/workspace/sru/2.py", line 14, in <module>
print(v1)
TypeError: __str__ returned non-string (type NoneType)
无法访问到类方法__str__,因为是类的私有方法,但是加上return后,有了返回值就可以有输出。
再来看看方法__add__
改变__add__方法return后面的参数结果会有改变
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other):
return Vector(self.a, self.b + other.b) v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
结果:
Vector (2, 8)
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other):
return Vector(other.a, self.b + other.b) v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
结果:
Vector (5, 8)
若将other改成others
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other):
return Vector(self.a + others.a, self.b + other.b) v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + others.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)
python面向对象——类的更多相关文章
- python面向对象(类和对象及三大特性)
类和对象是什么 创建类 新式类 和 经典类 面向对象三大特性 继承 封装 多态 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- python 面向对象(类的特殊成员)
python 面向对象: (思维导图 ↑↑↑↑) 类的特殊成员 python的类成员存在着一些具有特殊含义的成员 1.__init__: 类名() 自动执行 __init__ class Foo(ob ...
- python面向对象(类的成员及类方法)
类的普通成员 字段 方法 属性 类的高级成员 静态字段 静态方法 属性方法 类方法 类成员修饰符 类的成员 类的成员可以分为三大类:字段.方法和属性 注:所有成员中,只有普通字段的内容保存对象中, ...
- python 面向对象(类)
面向对象,即是将具备某种共性的事物抽象成一个类(模板),然后再根据类来创建实例对象进行具体的使用. 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写, ...
- Python面向对象 --- 类的设计和常见的内置方法
面向对象:一种基于面向过程的新的编程思想.也就是说面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节:这种思想是将数据作为第一位,而方法或者说是算法作为其次,这是对数据一种 ...
- python 面向对象类与类之间的关系
主要内容: 1. 依赖关系 2. 关联关系, 组合关系, 聚合关系 3. 继承关系 4. 类中的特殊成员 引子 大千世界, 万物之间皆有规则和规律,我们的类和对象是对大千世界中的所有事物进行归类. 那 ...
- Python——面向对象(类)的基础疑难点
相信用Python写def函数大家都信手拈来了,但Python作为面向对象的编程语言,怎么能浪费呢? 那问题来了.什么是类呢?什么是实例?什么是对象?方法是什么??属性又是什么???继承?封装?多态? ...
- python面向对象--类
1.类的概念:简单来说就是一组符合逻辑的参数或者是函数,一个种类.一个模型. 一个类中可以包含任意参数,并且可以定义任意个方法,但类并不是随意的将多个参数或者方法包含在class下,而是创建一个在事物 ...
- python: 面向对象:类和对象调用类中的变量和方法
一. 面向对象初识 我们在生活中做事都是面向过程的,前面实现一些基本逻辑功能代码也是用面向过程的语句实现的,后来学了函数,把这些功能又装到了函数里.但用面向过程的方法去写程序,只能实现一个功能,我们要 ...
随机推荐
- Huge Mods UVA - 10692(指数循环节)
题意: 输入正整数a1,a2,a3..an和模m,求a1^a2^...^an mod m 解析: #include <iostream> #include <cstdio> # ...
- 51nod 1589 移数博弈 | 基数排序(ノಠ益ಠ)ノ彡┻━┻
51nod 1589 移数博弈 题面 给出一个序列a,长度 n <= 10^7, a[i] <= 10^7 求每个长度 >= 2 的区间的最大值*次大值 之和. 题解 主要思路是求每 ...
- 【Cf #502 F】The Neutral Zone
本题把$log$化简之后求得就是每个质数$f$前的系数,求系数并不难,难点在于求出所有的质数. 由于空间限制相当苛刻,$3e8$的$bitset$的内存超限,我们考虑所有的除了$2$和$3$以外的质数 ...
- 【poj2406】 Power Strings
http://poj.org/problem?id=2406 (题目链接) 题意 给定一个字符串 L,已知这个字符串是由某个字符串 S 重复 R 次而得到的, 求 R 的最大值. Solution 后 ...
- 20135239 益西拉姆 linux内核分析 读书笔记之第四章
chapter 4 进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统可以划分为两类: - 非抢占式多任务: - 进程会一直执行直到自己主动停止运行(这一 ...
- spark 调优——基础篇
开发调优 调优概述 Spark性能优化的第一步,就是要在开发Spark作业的过程中注意和应用一些性能优化的基本原则.开发调优,就是要让大家了解以下一些Spark基本开发原则,包括:RDD lineag ...
- 解题:BJOI 2006 狼抓兔子
题面 可以看出来是最小割,然后你就去求最大流了 这么大的范围就是让你用网络流卡的?咋想的啊=.=??? 建议还是老老实实用 平面图最小割等于其对偶图最短路 这个东西来做吧,虽然这个东西跑的也挺慢的,最 ...
- ASP.NET MVC开发,编辑页面和添加页面基本相同,我们控制器 Add Edit是共用同一个View吗?
http://q.cnblogs.com/q/51693/ 这种的话,一般公用就好了.,如下的写法: [HttpGet] public ActionResult UserManage(int user ...
- Rstdio快捷键总结
Rstdio常用快捷键总结 在R语言里面输入了一个不完整的指令以后 左下方的console pane一直有加号+,不管输入什么都是加号,只用推出重新打开Rstudio才行,后来google了下,按左上 ...
- addEventListener() 事件监听
addEventListener() 用于向指定元素添加事件. 可以向一个元素添加多次事件或者多次不同事件,后面的事件是不会覆盖前面的. 语法: element.addEventListener(ev ...