目录结构:

contents structure [-]

1.类的基本使用

下面是类使用的一个简单案例,

class person:
"person 类的描述信息"
def __init__(self,name="",age=0):
self.name = name
self.age = age def setName(self,name):
'''设置名称'''
self.name = name def getName(self):
'''获取名称'''
return self.name def setAge(self,age):
self.age = age def getAge(self):
return self.age def __del__(self):
print("person (name:"+self.name+",age:"+str(self.age)+") is deleting") p = person("jame",12);
#Output:jame
print(p.getName())
#效果和下面的调用方式是一样的
#person.getName(p) #Output:12
print(p.getAge())
#效果和下面的调用方式是一样的
#person.getAge(self) #Output: person 类的描述信息
print(p.__doc__) #输出person类的帮助信息
print(help(person)) del p

输出:

jame
12
person (name:jame,age:12) is deleting
person 类的描述信息
Help on class person in module __main__: class person(builtins.object)
| person 类的描述信息
|
| Methods defined here:
|
...

__init__函数是构造函数,在构造对象的时候会自动调用该函数。
__del__函数是析构函数,在使用del删除目标对象时会自动调用该方法。

Python中,类不可以定义多个构造方法,只能定义一个构造方法。所有成员实例函数的第一个参数都必须是self参数(也可以有非self参数的成员函数,下面会讲解)。python会自动创建成员属性,无需提前定义,例如self.name=name。

类属性

类属性的定义无需使用self参数,可以直接定义到类中。类属性可以直接通过类名调用。

class Person:
type = "哺乳类" def __init__(self,name,age):
self.name = name
self.age = age p = Person("luyis",13)
#通过类名调用类属性
print(Person.type)
#通过对象调用类属性
print(p.type)

静态方法

静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互,即在静态方法中,不会涉及到类中的方法和属性的操作。用 @staticmethod 装饰的不带 self 参数的方法,类的静态方法可以没有参数,可以直接使用类名调用。

import time
class TimeTest:
def __init__(self):
pass #静态方法
@staticmethod
def show_time():
print(time.strftime("%H:%M:%S", time.localtime())) TimeTest.show_time()

类方法

类方法是将类本身作为对象进行操作的方法。默认有个 cls 参数,可以被类和对象调用,需要加上 @classmethod 装饰器。

class ClassTest:
num = 0
def __init__(self,num):
ClassTest.num = num #类方法
@classmethod
def showNum(cls):
print(cls.num) c = ClassTest(20)
#通过类直接调用
ClassTest.showNum()
#通过实例对象调用
c.showNum()

私有成员

Python中的私有成员,不能在类外面直接访问。私有成员只需要在成员前面加上两条下划线(__)就表明该成员是私有的了。

class Person:
#__type是私有成员
__type = "哺乳类" def __init__(self,name="",age=0,country="中国"):
#__name,__age是私有成员
self.__name = name
self.__age = age
self.__setcountry(country) def get_name(self):
return self.__name def get_age(self):
return self.__age def set_name(self,name):
self.__name = name def set_age(self,age):
self.__age = age #__setcountry是私有函数
def __setcountry(self,cty):
self.country = cty @classmethod
def get_type(cls):
return cls.__type @classmethod
def set_type(cls,type):
cls.__type = type p = Person("jame",21)
print(p.get_name())
print(p.get_age())
print("--------------------") p.set_name("charlse")
p.set_age(31)
print(p.get_name())
print(p.get_age())
print("-------------------") print(Person.get_type())
print("------------------") Person.set_type("灵长类")
print(Person.get_type())

输出:

jame
21
--------------------
charlse
31
-------------------
哺乳类
------------------
灵长类

定义私有成员的格式:
__xxx:私有成员,只有类对象自己能访问,子类对象不能直接访问到这个成员,

注意:虽然不能在类外直接访问到类的私有成员,但在对象外部可以通过“ 对象名._类名__xxx ”这样的特殊方式来访问类的私有成员。应此,在Python中不存在严格意义上的私有成员。

class Person:
#__type是私有成员
__type = "哺乳类" def __init__(self,name="",age=0):
#__name,__age是私有成员
self.__name = name
self.__age = age p = Person("Emma",32);
#直接访问私有成员的值
print(p._Person__type)
print(p._Person__name)
print(p._Person__age) #直接修改私有成员的值
p._Person__age = 33
p._Person__name = "Angela"
p._Person__type = "灵长类" print("-------------------")
print(p._Person__type)
print(p._Person__name)
print(p._Person__age)

输出:

哺乳类
Emma
32
-------------------
灵长类
Angela
33

2.专有方法

Python除了自定义私有变量和方法外,还可以定义专有方法。专有方法是在特殊情况下或使用特殊语法时由python调用的,而不是像普通方法一样在代码中直接调用。看到形如__XXX__的变量或函数名时就需要注意下,这在python中是有特殊用途的,下面是Python中的部分专用方法:
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__str__: 打印,转换,适合于展示给用户看的
__repr__ : 打印,转换,适合开发者调试
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__div__: 除运算
__mod__: 求余运算
__pow__: 乘方
__doc__: 说明文档信息

上面笔者已经讲解过__init__和__del__函数的使用了,应此笔者不再这里重复缀述了。笔者接下来讲解其它的专有方法的用法:

__str__,__repr__

都是用于将对象转化为字符串的内置方法。
但是 repr() 函数将对象转化为供解释器读取的形式,__str__只是覆盖了__repr__以得到更友好的用户显示。
例如:

>>> y = 'a string'
>>> repr(y)
"'a string'"
>>> str(y)
'a string'

repr函数的返回字符串可以再次传递给eval函数。但是str函数的返回值传递给eval显然是不合适。

>>> y == eval(repr(y))
True
>>> y == eval(str(y))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
a string
^
SyntaxError: unexpected EOF while parsing

repr返回的字符串应该是编译器能够再次解析的,str返回的字符串应该可以是易阅读的

在知道了repr和str的区别后,我们就知道该如何自定义__repr__和__str__函数了。

class person:
def __init__(self,name="",age=0):
self.__name = name
self.__age = age def __str__(self):
return "name:%s,age:%d"%(self.__name,self.__age) def __repr__(self):
return "person(name='%s',age=%d)"%(self.__name,self.__age) p = person("jame",12)
#Output: name:jame,age=12
print(str(p))#same as print(p) #Output: person(name='jame',age=12)
print(repr(p)) p2 = eval(repr(p))
#Output: name:jame,age=12
print(p2)

__setitem__,__getitem__

用于通过下标来设置和获取值,可以直接使用[]符来操作。

class DicDecorate:

    def __init__(self,dic):
self.__dic = dic def __getitem__(self,key):
return self.__dic[key] def __setitem__(self,key,val):
self.__dic[key] = val dicdec = DicDecorate({}) dicdec[0] = "hello"
dicdec[1] = "word" print(dicdec[0])
print(dicdec[1])

__len__():

当调用len函数时会调用该方法。

lass DicDecorate:
def __init__(self,dic):
self.__dic = dic def __len__(self):
return len(self.__dic); dicdec = DicDecorate({})
print(len(dicdec))

__call__()

关于 __call__ 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable。

如果在类中实现了 __call__ 方法,那么实例对象也将成为一个可调用对象。

class Entity:
def __init__(self, x, y):
self.x, self.y = x, y def __call__(self, x, y):
self.x, self.y = x, y def __str__(self):
return "x=%s,y=%s"%(self.x,self.y) e = Entity(2, 3) # 创建实例
if(callable(e)):
e(4, 5) #实例可以象函数那样执行,并传入x y值,修改对象的x y
#Output:x=4,y=5
print(e)

__add__: 加运算 __sub__: 减运算 __mul__: 乘运算 __div__: 除运算 __mod__: 求余运算 __pow__: 幂运算

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)

3. 继承

3.1 单重继承

Python继承的语法格式:

class ClassName1(ClassName2):
statement

其中
ClassName1:派生类
ClassName2:基类

class Shape:
def __init__(self,type,area):
self.type = type
self.area = area
def describe(self):
return "Share type:%s,area=%f"%(self.type,self.area)
class Square(Shape):
def __init__(self,area):
super().__init__("square",area);
square = Square(12.1)
print(square.describe())

和其它编程语言一样,可以重写父类中的方法,可以继承父类中开放的属性和方法(不能继承父类中的私有属性和方法)。

3.2 多重继承

除了单重继承,Python还支持多重继承

class ClassName1(ClassName2,ClassName3,ClassName4...):
statement

Python多重继承中顺序继承是一个非常重要的概念,如果继承的多个父类中有相同的方法名,但在派生类中使用时未指定父类名,则Python解释器将从左至右搜索,即调用先继承的类中的同名方法。

class A:
def test(self):
print("I am in Class A");
class B:
def test(self):
print("I am in Class B"); class C(A,B):
def __call__(self):
#调用A类中的test方法
self.test()
#可以通过类名显示指定调用B类中的test方法
B.test(self) class D(B,A):
def __call__(self):
#调用B类的test方法
self.test()
#通过类名显示指定要调用A类中的test方法
A.test(self) c = C()
c()
print("---------------");
d = D()
d()

输出:

I am in Class A
I am in Class B
-----------------
I am in Class B
I am in Class A

通过上面的结果可以看出,子类在父类中查找方法的顺序是从左到右的。

3.3 砖石继承

砖石继承问题是Python多重继承中的典型问题,下面先通过一张图片看看什么是砖石继承。

通过这张图片看出,D继承了B和C,B和C又派生于A,在调用D类的test()方法时,会再去调用B和C的test()方法,B和C又会去调用A的test()方法,所以A类的test()方法在理论应该会被调用两次,例如:

class A:
def test(self):
print("I am in Class A");
class B(A):
def test(self):
A.test(self);
print("I am in Class B")
class C(A):
def test(self):
A.test(self);
print("I am in Class C"); class D(B,C):
def test(self):
B.test(self)
C.test(self)
print("I am in Class D") d = D()
d.test()

输出:

I am in Class A
I am in Class B
I am in Class A
I am in Class C
I am in Class D

从上面的输出结果可以看出,A类的test()被调用了两次。在有些情况这种逻辑将会造成极大的Bug,比如一笔银行转账记录转了两次。要避免这种情况,可以使用super()方法,当使用super()调用父类的test方法时,会转而去调用下一个重写了该super类的test方法,若没有的话才会去调用父类的test方法。
案例:

class A:
def test(self):
print("I am in Class A")
class B(A):
def test(self):
super().test() #不能替换为A.test(self)
print("I am in Class B")
class C(A):
def test(self):
super().test()
print("I am in Class C") class D(B,C):
def test(self):
super().test() #可以替换为B.test(self)
print("I am in Class D") d = D()
d.test()

输出:

I am in Class A
I am in Class C
I am in Class B
I am in Class D

通过上面的结果我们可以看出,super.test()和父类.test(self)是不一样的,在B类中使用super()调用父类的test()时,会去寻找B实例后的下一个类是否重写A类的test()方法,由于类D继承了类B和类C,所以类C在类B后,而且类C又重写了test()方法,应此会直接调用类C的test()方法。在类C的test()方法中,又使用了super().test()调用父类的test(),所以又会去寻找C实例后的下一个类有重写A类的test方法,因为类D只继承了B和C,并且类C是最后一个,所以C后没有实例直接重写A类的test()方法,因此直接去调用A类的test()方法。最终完整的方法压栈顺序是D->B->C->A。

下面的逻辑和上面案例中使用super()的逻辑是等同的:

class A:
def test(self):
print("I am in Class A")
class B(A):
def test(self):
C.test(self)#调用C
class C(A):
def test(self):
A.test(self)#调用A
class D(B,C):
def test(self):
B.test(self)#调用B

上面的逻辑变成了如图所示:

【Python】解析Python中类的使用的更多相关文章

  1. 从json到python解析python,从bson到monogdb

    1.JSON JSON是JavaScript Object Notation的缩写,中文译为JavaScript对象表示法.用来作为数据交换的文本格式,作用类似于XML,而2001年Douglas C ...

  2. 使用Python解析JSON数据

    使用Python解析百度API返回的JSON格式的数据 # coding:utf-8 # !/usr/bin/env python import matplotlib.pyplot as plt fr ...

  3. 使用Python解析JSON数据的基本方法

    这篇文章主要介绍了使用Python解析JSON数据的基本方法,是Python入门学习中的基础知识,需要的朋友可以参考下:     ----------------------------------- ...

  4. python解析robot framework的output.xml,并生成html

    一.背景 Jenkins自动构建RF脚本,生成的RF特有HTML报告不能正常打开. 需求:用Python解析测试报告的xml数据,放在普通HTML文件中打开 二.output.xml数据 三.用pyh ...

  5. python 解析json loads dumps

    认识 引用模块 重要函数 案例 排序 缩进参数 压缩 参考 认识 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standa ...

  6. Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试

    摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...

  7. python 解析XML python模块xml.dom解析xml实例代码

    分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...

  8. python解析xml模块封装代码

    在python中解析xml文件的模块用法,以及对模块封装的方法.原文转自:http://www.jbxue.com/article/16586.html 有如下的xml文件:<?xml vers ...

  9. python解析xml之lxml

    虽然python解析xml的库很多,但是,由于lxml在底层是用C语言实现的,所以lxml在速度上有明显优势.除了速度上的优势,lxml在使用方面,易用性也非常好.这里将以下面的xml数据为例,介绍l ...

  10. Python解析生成XML-ElementTree VS minidom

    OS:Windows 7 关键字:Python3.4,XML,ElementTree,minidom 本文介绍用Python解析生成以下XML: <Persons> <Person& ...

随机推荐

  1. ML-软间隔(slack)的 SVM

    Why Slack? 为了处理异常值(outlier). 前面推导的svm形式, 是要求严格地全部分对, 基于该情况下, 在margin 的边界线 线上的点, 只能是支持向量. \(min_w \ \ ...

  2. 解锁 redis 锁的正确姿势

    redis 是 php 的好朋友,在 php 写业务过程中,有时候会使用到锁的概念,同时只能有一个人可以操作某个行为.这个时候我们就要用到锁.锁的方式有好几种,php 不能在内存中用锁,不能使用 zo ...

  3. GMT与UTC简介(转)

    GMT与UTC简介 一.简介 许多人都知道两地时间表简称为GMT或UTC,而世界时区表则通称为World Time ,那么GMT与UTC的实质原意又是为何?世界时区又是怎么区分的?面盘上密密麻麻的英文 ...

  4. ARM架构体系

    架构 处理器家族 ARMv1 ARM1 ARMv2 ARM2.ARM3 ARMv3 ARM6, ARM7 ARMv4 StrongARM.ARM7TDMI.ARM9TDMI ARMv5 ARM7EJ. ...

  5. Beta冲刺第4次

    二.Scrum部分 1. 各成员情况 翟仕佶 学号:201731103226 今日进展 今天不再使用Excel绘制燃尽图,改学习使用highcharts绘制 存在问题 对前端不够了解,第一次在这博客园 ...

  6. 性能测试基础---LR运行设置

    ·LR的运行时设置(Runtime settings): ·Run Logic:该选项是用来控制脚本的真正的运行逻辑. ·该选项会把脚本中的函数分别放入三个运行模块中:Init.Run.End ·默认 ...

  7. PAT 甲级 1025.PAT Ranking C++/Java

      Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Z ...

  8. 后台返回的base64的图片格式,前端如何转为普通的图片格式

    在上一篇的博客当中,写了前端如何将普通的图片格式转为base64的图片,今天开发的时候遇到了后台返回的图片格式是base64的,我这边需要把base64的图片格式转为普通的,搜了一下js的方法,感觉很 ...

  9. P1850 换教室[dp+期望]

    流下了不会概率的眼泪,由于不会概率,转移少写了点东西... 这个dp很简单,就是一个普通的线性dp加点期望.(刚开始写这道题时信笔写下) \(dp[0/1][i][j]\)表示到第\(i\)个时间段时 ...

  10. ArcGIS Server 注册托管数据库

    需要已经安装好ArcGIS for Desktop.ArcGIS for Server和ArcSDE,并且已经创建了地理数据库 我试了用管理网站添加,总是不成功,后来用ArcCatalog添加成功.这 ...