在了解什么是Python类之前,先来了解一下什么是面向对象编程:
1、面向对象编程(oop)是一种程序设计思想。oop把对象作为程序的基本单元,一个对象包含数据和操作数据的函数
2、在python中,所有数据类型都被视为对象,也可以自定义对象。自定义对象数据类型就是面向对象中类的概念
术语 | 意义 |
---|---|
类(class) | 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例 |
方法 | 类中定义的函数 |
类变量(属性) | 类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体(方法)之外。类变量通常不作为实例变量使用,类变量也称作属性 |
数据成员 | 类变量或者实例变量用于处理类及其实例对象的相关的数据 |
方法重写 | 如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写 |
实例变量 | 定义在__init__方法中的变量,只作用于当前实例的类 |
继承 | 即一个派生类(derived class)继承基类(base class)的字段和方法 |
实例化 | 创建一个类的实例,类的具体对象。一个类可以实例化出无数个对象 |
对象 | 通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法 |
多态 | 对不同的类使用不同的工作 |
封装 | 对外部世界隐藏对象的工作细节 |
Python的类提供了面向对象编程的所有标准特性:
⑴类继承机制允许多个基类,派生类可以覆盖它基类的任何方法,一个方法可以调用基类中相同名称的的方法
⑵对象可以包含任意数量和类型的数据
⑶和模块一样,类也拥有Python天然的动态特性:它们在运行时创建,可以在创建后修改
类的定义
class MyStudent: # 定义一个类
def __init__(self,name,age,sex): #类的构造函数,用于初始化类的内部状态,为类的属性设置默认值
self.name = name # 定义类的属性
self.age = age # 定义类的属性
self.sex = sex # 定义类的属性
self.__secret = 0 #私有变量
def studentName(self,name):
print(f'student name is{self.name}')
t = MyStudent('小王',11,0) # 实例化一个对象t
t.studentName('小李') #对象调用studentName方法
1.一般使用 class 语句来创建一个新类,class之后为类的名称(通常首字母大写)并以冒号结尾;
2.类中可以定义所使用的方法,类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self;
3.创建类时,可以定义一个特定的方法,名为__init__(),只要创建这个类的一个实例就会运行这个方法。类似于C++中的构造方法,可以通过__init__()方法传递参数。
4.self 代表类的实例,self 在定义类的方法时是必须有的,用来实例化类定义的函数和变量;
5.__private_attrs 两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。
classmethod类方法
类方法(装饰器),第一个参数是cls,代表这个类(注意不是类实例),常用来调用类级方法(如系统方法跟静态方法,类方法等)来进行预处理,然后返回预处理后的类。效果就像另一个构造函数一样(实际上并不是)
class info(object):
@classmethod
def sayclassmethod(cls):
print 'say %s' % cls
def saymethod(self):
print 'say %s' % self
test = info()
test.saymethod()##实例调用方法
test.sayclassmethod()##实例调用类方法
info.saymethod(test)##类调用实例方法
info.sayclassmethod()##类调用类方法
使用@classmethod是为了处理一些__init__处理不了的赋值问题(一般是参数不对应),可以当成有第二、第三个__init__方法,或者是C++中的构造函数,要通过类名才能显示调用。
staticmethod静态方法
使用@staticmethod目的之一是为了增加可读性,不需要参数self的方法都可以加上@staticmethod增加可读性,因为,这个方法是类级别的,在调用时要使用类名。
继承类定义
1.单继承
class <类名>(父类名)
<语句>
class A:
#不管是本类还是子类 只要实例化 就会调用(前提是 没有被子类的__init__覆盖)
def __init__(self,n,a,s):
self.name = n
self.age = a
self.sex = s
def speak(self):
print("我现在{}岁了 我叫{} 我的性别是{}".format(self.age,self.name,self.sex))
# a = A('张三',18,'男')
# print(a.name)
# a.speak()
class B(A):
grade = ''
def __init__(self,name,age,sex,grade):
print('我是子类的__init__')
self.grade = grade
A.__init__(self,name,age,sex)
def speak(self):
A.speak(self)
print("我今年{} 我叫{} 我的成绩是{}".format(self.age,self.name,self.grade))
b = B('张三',18,'男',60)
# print(b.name)
# print(b.__dict__)
b.speak()
2.类的多重继承
class 类名(父类1,父类2,…,父类n)
<语句1>
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法
class A:
def speak(self):
print('我是A类的speak方法')
def a(self):
print('a')
class B:
def speak(self):
print('我是B类的speak方法')
def b(self):
print('b')
class C(A,B):
def speak(self):
super().speak() #还是从左往右找..
#super(C,self).speak()
# super(A,self).speak()
# super(B,self).speak()
首先需要理解的是,两个下划线开头的函数是声明该属性为私有,不能在类的外部被使用或访问
1__init__()
类似于构造函数,可以通过__init__()方法传递参数,但是一个参数必须为self,后续参数为自己定义。
#!/usr/local/bin/python
class Study:
def __init__(self,name=None):
self.name = name
def say(self):
print self.name
study = Study("Badboy")
study.say()
2__del__()
类似于析构函数,析构函数往往是用来是否内存,哪怕不写也会默认调用。
#!/usr/local/bin/python
class Study:
def __init__(self,name=None):
self.name = name
def __del__(self):
print "Iamaway,baby!"
def say(self):
print self.name
study = Study("zhuzhengjun")
study.say()
在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self(可以自定义)。其作用相当于C++中的this指针,表示当前类的对象,可以调用当前类中的属性和方法。
简单的说self就是把 class中定义的变量和函数变成实例变量和实例函数,它和this一样作用域是在类内部,只能在成员函数中使用,使得成员间能互相调用,而不需要从外部调用 数据(即变量)和方法(即函数),以实现数据的封装。
如果不使用self把类中定义的变量和函数实例化,那么在类的成员函数中调用未被实例化的变量或函数便会报错。
self代表类的实例,而非类;self 就是 对象/实例 属性集合
class Box():
def __init__(self, boxname, size, color):
self.boxname = boxname
self.size = size
self.color = color # self就是用于存储对象属性的集合,就算没有属性self也是必备的
def open(self, myself):
print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
print('-->用类自己的self,打开那个%s,%s的%s' % (self.color, self.size, self.boxname))
def close(self):
print('-->关闭%s,谢谢' % self.boxname)
b = Box('魔盒', '14m', '红色')
b.close()
b.open(b) # 本来就会自动传一个self,现在传入b,就会让open多得到一个实例对象本身,print看看是什么。
print(b.__dict__) # 这里返回的就是self本身,self存储属性,没有动作。
在 class 类的函数中,为什么 self是必要的,因为 self 是对象的载体,可以理解成一个字典,看下面代码:
class Box():
def myInit(mySelf, boxname, size, color):
print(mySelf.__dict__)#显示为{}空字典
mySelf.boxname = boxname
mySelf.__dict__['aa'] = 'w'#甚至可以像字典一样操作
mySelf.size = size
mySelf.color = color # 自己写一个初始化函数,一样奏效,甚至不用self命名。其它函数当中用标准self
return mySelf # 返回给实例化过程一个对象!神奇!并且含有对象属性/字典
# def __init__(self, boxname, size, color):
# self.boxname = boxname
# self.size = size
# self.color = color #注释掉原来标准的初始化
def open(self, myself):
print(self)
print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
print('-->用类自己的self,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
def close(self):
print('-->关闭%s,谢谢' % self.boxname)
# 经过改造,运行结果和标准初始化没区别
b = Box().myInit('魔盒', '14m', '红色')
# b = Box('魔盒', '14m', '红色')#注释掉原来标准的初始化方法
b.close()
b.open(b) # 本来就会自动传一个self,现在传入b,就会让open多得到一个实例对象本身,print看看是什么。
print(b.__dict__) # 这里返回的就是self本身,self存储属性,没有动作。
故可以把 self 理解成存储实例化对象属性的字典(dict), self 存储属性,而没有动作执行.
类的注释规范
class SampleClass(object):
"""Summary of class here.
Longer class information....
Longer class information....
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def __init__(self, likes_spam=False):
"""Inits SampleClass with blah."""
self.likes_spam = likes_spam
self.eggs = 0
def public_method(self):
"""Performs operation blah."""
函数的注释规范
def func(path, field_storage, temporary):
'''基本描述
详细描述
Args:
path (str): The path of the file to wrap
field_storage (FileStorage): The :class:`FileStorage` instance to wrap
temporary (bool): Whether or not to delete the file when the File instance is destructed
Returns:
BufferedFileStorage: A buffered writable file descriptor
'''
pass
Python风格规范
实现名为 Human 的Class,
需要有以下三个方法 ,1、getHeight 返回身高 ,2、getName 返回姓名 3、setName 修改姓名
需要有以下三个属性,1、身高 2、姓名 3、年龄
class Human: # 定义一个类
def __init__(self,height,name,age):#类的构造函数,用于初始化类的内部状态,为类的属性设置默认值
self.height = height # 定义类的属性
self.name = name # 定义类的属性
self.age = age # 定义类的属性
def getHeight(self): # 定义一个类的函数,称为方法,至少含有一个self
height = self.getHeight
return height
def getName(self): # 定义一个类的函数,称为方法,至少含有一个self
name = self.name
return name
def setName(self,sName): # 定义一个类的函数,称为方法,至少含有一个self
self.name = sName # 修改一个实例变量
t = Human(167,'小王',20)
personName = t.getName()
print(f"名字是:{personName}")
personHeight = t.getHeight()
print(f'身高是:{personHeight}')
t.setName('小李')
personName=t.getName()
print(f"名字是:{personName}")
1.如果直接返回一个实例变量,是无法打印对应值的,需要定义一个局部变量来作为返回值使用。
2.实例化类的时候不带括号本质上是给类对象起了一个别名,类似C语言中的typedef关键字,而并不会创建一个实例。
3.调用类方法的时候不加括号,调用的是函数(这个对象),不用等函数执行结束;