【Python】解析Python中类的使用
目录结构:
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中类的使用的更多相关文章
- 从json到python解析python,从bson到monogdb
1.JSON JSON是JavaScript Object Notation的缩写,中文译为JavaScript对象表示法.用来作为数据交换的文本格式,作用类似于XML,而2001年Douglas C ...
- 使用Python解析JSON数据
使用Python解析百度API返回的JSON格式的数据 # coding:utf-8 # !/usr/bin/env python import matplotlib.pyplot as plt fr ...
- 使用Python解析JSON数据的基本方法
这篇文章主要介绍了使用Python解析JSON数据的基本方法,是Python入门学习中的基础知识,需要的朋友可以参考下: ----------------------------------- ...
- python解析robot framework的output.xml,并生成html
一.背景 Jenkins自动构建RF脚本,生成的RF特有HTML报告不能正常打开. 需求:用Python解析测试报告的xml数据,放在普通HTML文件中打开 二.output.xml数据 三.用pyh ...
- python 解析json loads dumps
认识 引用模块 重要函数 案例 排序 缩进参数 压缩 参考 认识 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standa ...
- Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试
摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...
- python 解析XML python模块xml.dom解析xml实例代码
分享下python中使用模块xml.dom解析xml文件的实例代码,学习下python解析xml文件的方法. 原文转自:http://www.jbxue.com/article/16587.html ...
- python解析xml模块封装代码
在python中解析xml文件的模块用法,以及对模块封装的方法.原文转自:http://www.jbxue.com/article/16586.html 有如下的xml文件:<?xml vers ...
- python解析xml之lxml
虽然python解析xml的库很多,但是,由于lxml在底层是用C语言实现的,所以lxml在速度上有明显优势.除了速度上的优势,lxml在使用方面,易用性也非常好.这里将以下面的xml数据为例,介绍l ...
- Python解析生成XML-ElementTree VS minidom
OS:Windows 7 关键字:Python3.4,XML,ElementTree,minidom 本文介绍用Python解析生成以下XML: <Persons> <Person& ...
随机推荐
- 学习Spring5源码时所遇到的坑
学习Spring5源码时所遇到的坑 0)本人下载的源码版本是 spring-framework-5.0.2.RELEASE 配置好gradle环境变量之后,cmd进入到spring项目,执行gradl ...
- [SourceInsight].source insight 使用技巧
转自:https://www.veryarm.com/140428.html 1 开胃菜-初级应用 1.1 选择美丽的界面享受工作 虽然不能以貌取人,但似乎从来没有人责备以貌取软件的.SI的华丽界 ...
- Linux操作系统之用户权限,重定向,文件管理
文件的权限 ls -al ----->隐藏文件会以 .号开头 ls -ld :显示目录自身属性 ls -i 显示文件的索引号----每个文件都有一个对应的号码 ls -r 逆序显示 dr-xr ...
- zabbix--CPU监控并告警
zabbix监控CPU超值则报警 由于默认没有 cpu 的使用率监控,需要添加一个监控项,通过 system.cpu.util[,,] 来进行配置 添加监控项 添加图形 添加触发器 展示图
- jenkins与gitlab集成,分支提交代码后自动构建任务(六)
一.在gitlab中创建token 复制token,此token只显示一次:6SB8y4jt31NnYG5-nWoi 二.在gitlab上为项目创建trunk分支 三.在jenkins中配置gitla ...
- c语言实现基本的数据结构(四) 循环队列
#include <stdio.h> #include <tchar.h> #include <stdlib.h> #define MaxQueueSize 100 ...
- 去除WordPress分类描述P标签
我们知道栏目页调用栏目描述直接用<?php echo category_description(); ?>就ok了,但是使用上面的代码调用Wordpress分类描述,会自动出现P标签,如& ...
- js地理定位对象 navigator.geolocation
浏览器信息的存储对象(navigator): 在新的API标准中,可以通过navigator.geolocation来获取设备的当前位置,返回一个位置对象,用户可以从这个对象中得到一些经纬度的相关信息 ...
- 关于ArrayList
List概述 List是一个列表结构抽象定义,有序的,可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素.包括函数的有:添加元素,删除元素,判断是否包含元素等等重要函数. ...
- Object archiving
https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Arch ...