1. Python类的定义
类: 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。在Python中用关键字class来定义类,语法如下:
class <类名称>:
"文件字符串" # 可以省略
<语句> # 用来定义类的属性和方法
简单的定义类的例子
- a = 123 是这个类的属性
- f(x) 则是 这个类的方法
class MyClass:
"这是一个定义类的例子"
a = 123
def f(x):
return x
除了上述简单类型外,类还可以继承别的类,其语法为:
class 类名称(类名称1,类名称2):
"文件字符串"
<语句>
2. 类的构造方法和内置属性
构造方法就是创建对象时,对象本身所运行的函数
- def __init__(self)语句定义MyClass的构造方法,self是必要的参数且为第一个参数,这里的self可以替换为其它名称,但是通常默认用self
- 我们在 __init__()构造方法中可以添加参数,在创建类时同时设置类的属性值
class MyClass:
def __init__(self):
print(self)
MyClass
__main__.MyClass
定义一个car类,其中基本属性为name和car,定义私有属性为__prince,接着定义构造方法def __init__(self,n,b,p),主要作用是对基本属性以及私有属性进行复制操作,def explain(self)则是用于输出结果
# 定义类
class car:
# 定义基本属性
name = ''
brand = ''
# 定义私有属性,私有属性在类外部无法直接进行访问
__price = 0
# 定义构造方法
def __init__(self,n,b,p):
self.name = n
self.brand = b
self.__price = p
def explain(self):
print("%s属于%s系列的轿车,价格为%s元。"%(self.name,self.brand,self.__price))
# 实例化类
c = car('BWM','X7','570000')
c.explain()
BWM属于X7系列的轿车,价格为570000元。
所有Pyhton类都有下列内置属性:
class MyClass:
"这是一个定义类的例子"
a = 123
- classname. __dict__(类内的属性是以字典对象的方式存储,__dict__属性为此字典对象的值
print(MyClass.__dict__)
{'__module__': '__main__', '__doc__': '这是一个定义类的例子', 'a': 123, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>}
# '__module__': '__main__'模块与所对应的的函数
# '__doc__': '这是一个定义类的例子'类的说明文档
# 'a': 123 类的属性
- classname.__doc__:.__doc__属性返回此类的文件字符串
MyClass.__doc__
'这是一个定义类的例子'
- classname.__name__:.__name__属性返回此类的名称
MyClass.__name__
'MyClass'
- classname._module_:.__module__属性返回此类的模块名称
MyClass.__module__
'__main__'
- classname.__bases__:.__bases__属性是一个元组对象,返回此类的基类名称
MyClass.__bases__
(object,)
class NewClass(MyClass):
"这是一个派生类"
b = 100
NewClass.__bases__
(__main__.MyClass,)
3. Python类实例
类实例是一个Python对象,是使用类创建的对象,Python中每一个对象都有识别码、对象类型、属性、方法以及值。
3.1 创建类实例
# 定义类
class MyClass:
"这是一个类实例"
a = 123
# 实例化类 即指定变量给类名即可
x = MyClass()
# 定义类
class MyClassNew:
"这是一个类实例"
def __init__(self,x): # 构造函数时有一个参数
self.x = x
# 实例化类 即指定变量给类名即可,
# 主义构造函数有一个参数,因此实例化也需要传递一个参数给类
x = MyClassNew(2)
# 不指定参数则实例化类将报错
y = MyClassNew()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-119-3cf3f4acd46c> in <module>()
1 # 不指定参数则实例化类将报错
----> 2 y = MyClassNew()
TypeError: __init__() missing 1 required positional argument: 'x'
- id(),返回类的识别码
# 定义类
class MyClassNew:
"这是一个类实例"
def __init__(self,x): # 构造函数时有一个参数
self.x = x
# 实例化类 即指定变量给类名即可,
# 主义构造函数有一个参数,因此实例化也需要传递一个参数给类
x = MyClassNew(2)
id(x)
2851014515232
- type(),返回类的对象类型
type(x)
__main__.MyClassNew
对象的属性,也称为数据成员
# 定义类
class test():
def __init__(self,name=None,sex=None,age=None):
self.name = name
self.sex = sex
self.age = age
# 实例化类
x = test('小明','男',18)
print(x.name,x.sex,x.age) # 类实例的成员变量
小明 男 18
3.2 类实例的内置属性
Python的类实例都有下列属性:
扫描二维码关注公众号,回复: 11184786 查看本文章
- obj.__dict__:类实例内额属性以字典对象存储
# 定义类
class test():
def __init__(self,name=None,sex=None,age=None):
self.name = name
self.sex = sex
self.age = age
# 实例化类
x = test('小明','男',18)
x.__dict__
{'age': 18, 'name': '小明', 'sex': '男'}
- obj.__dict__:返回类名称
x.__class__
__main__.test
4. Python类的内置方法
Python类中有许多的内置方法,这些内置方法的开头与结尾都是双下划线字符
- __init__():这是类的构造方法,当创建一个类的实例时,就会调用此方法。
class MyClass:
def __init__(self):
print(self)
x = MyClass()
# <__main__.MyClass(类名称) object at 0x00000297CDABC438(内存地址)>
<__main__.MyClass object at 0x00000297CDB51B38>
- __str__():此方法被str()内置函数与print函数调用,返回值为一个字符串对象。
class MyClass:
def __init__(self,name):
self.name = name
def __str__(self):
return self.name
x = MyClass('小明')
print(x)
小明
- __del__():此方法用于删除类对象
class MyClass:
def __init__(self,name):
self.name = name
def __del__(self):
print('不能删除此对象')
x = MyClass('小明')
del x
不能删除此对象
5. 类重载运算符
用来替换运算符的功能,类的专有方法有:
- __init__: 构造函数,在生成对象时调用
- __del__ : 析构函数,释放对象时使用
- __repr__ : 打印,转换
- __setitem__ : 按照索引赋值
- __getitem__: 按照索引获取值
- __len__: 获得长度
- __cmp__: 比较运算
- __call__: 函数调用
- __add__: 加运算
- __sub__: 减运算
- __mul__: 乘运算
- __truediv__: 除运算
- __mod__: 求余运算
- __pow__: 乘方
- __neg__(a):取反
- __abs__(a):取绝对值
# 加运算
import operator
operator.add(1,2)
3
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)
v3 = Vector(5,3)
print (v1 + v2 + v3)
Vector (12, 11)
6. Python类的继承
类的继承指的是新类继承旧类的属性与方法,这种行为成为派生子类。继承的新类被称为派生类,被继承的则被称之为基类。我们创建派生类后就可以在派生类内新增或者改写基类的任何方法。一个派生类可以同时继承多个基类,基类之间用’,'隔开
- 派生类的语法为:
class 类名称(基类1,基类2):
"文件字符串"
语句
6.1 派生类的构造方法
这个基类Student有三个成员变量name、sex和phone,同时定义了两个函数。
- __init__()函数是Student类的构造方法
- prinfo()函数是用来输出成员信息
# 定义基类
class Student:
def __init__(self,name,sex,phone):
self.name = name
self.sex = sex
self.phone = phone
def prinfo(self):
print("姓名:%s,性别:%s,联系电话:%s"%(self.name,self.sex,self.phone))
# 定义派生类
class Per(Student):
def __init__(self,name,sex,phone): # 派生类的构造方法
Student.__init__(self,name,sex,phone) # 调用基类的构造方法
# 实例化派生类
s = Per("小明","男","12345678")
s.prinfo()
姓名:小明,性别:男,联系电话:12345678
6.2 命名空间的搜索顺序
搜索顺序:类的实例、类、基类
class A:
def __init__(self,name):
self.name = name
def printName(self):
print("这是A类的printName函数,Name = %s"%self.name)
class B(A):
def __init__(self,name):
A.__init__(self,name) # 直接调用类A的构造方法
def printName(self):
print("这是B类的printName函数,Name = %s"%self.name)
class C(B):
def __init__(self,name):
B.__init__(self,name) # 直接调用类B的构造方法
def printName(self):
print("这是C类的printName函数,Name = %s"%self.name)
A("张三").printName()
B("李四").printName()
C("王麻子").printName()
这是A类的printName函数,Name = 张三
这是B类的printName函数,Name = 李四
这是C类的printName函数,Name = 王麻子
class A:
def __init__(self,name):
self.name = name
def printName(self):
print("这是A类的printName函数,Name = %s"%self.name)
class B(A):
def __init__(self,name):
A.__init__(self,name) # 直接调用类A的构造方法
def printName(self):
print("这是B类的printName函数,Name = %s"%self.name)
class C(B):
def __init__(self,name):
B.__init__(self,name) # 直接调用类B的构造方法
# def printName(self):
# print("这是C类的printName函数,Name = %s"%self.name)
C("王麻子").printName()
这是B类的printName函数,Name = 王麻子
class A:
def __init__(self,name):
self.name = name
def printName(self):
print("这是A类的printName函数,Name = %s"%self.name)
class B(A):
def __init__(self,name):
A.__init__(self,name) # 直接调用类A的构造方法
# def printName(self):
# print("这是B类的printName函数,Name = %s"%self.name)
class C(B):
def __init__(self,name):
B.__init__(self,name) # 直接调用类B的构造方法
# def printName(self):
# print("这是C类的printName函数,Name = %s"%self.name)
C("王麻子").printName()
这是A类的printName函数,Name = 王麻子
6.3 类的多继承(有限个)
# 定义基类
class Star:
# 定义基本属性
name = ''
age = ''
# 定义私有属性
__weight = ''
# 定义构造方法
def __init__(self,name,sex,weight):
self.name = name
self.sex = sex
self.__weight = weight
def prinfo(self):
print("%s是一个%s明星,体重%skg"%(self.name,self.sex,self.__weight))
# 单继承实例
class Info(Star):
# 添加一个成员属性
age = ''
def __init__(self,name,sex,age,weight):
# 调用父类的构造方法
Star.__init__(self,name,sex,weight)
self.age = age
# 重写父类的方法
def prinfo(self):
print("%s是一个%s明星,年龄是%s岁"%(self.name,self.sex,self.age))
# 实例化单继承
s = Info('张三','男','50','60')
s.prinfo()
张三是一个男明星,年龄是50岁
# 定义基类1
class Star:
# 定义基本属性
name = ''
age = ''
# 定义私有属性
__weight = ''
# 定义构造方法
def __init__(self,name,sex,weight):
self.name = name
self.sex = sex
self.__weight = weight
def prinfo(self):
print("%s是一个%s明星,体重%skg"%(self.name,self.sex,self.__weight))
# 定义基类2
class Sing():
song = ''
name = ''
def __init__(self,name,song):
self.name = name
self.song = song
def prinfo(self):
print("%s唱了《%s》这一首歌"%(self.name,self.song))
# 多重继承
class test(Sing,Star):
a = ''
def __init__(self,name,a,sex,weight,song):
Star.__init__(self,name,sex,weight)
Speak.__init__(self,name,song)
self.a = a
cc = test('张三','男','12','60','愿你')
cc.prinfo() # 调用方法同名时调用的是多重继承的第一个,这里则调用的是Sing这个类
张三唱了《愿你》这一首歌
7. Python类的多态
类的多态就是类中可以由许多个相同名称参数类型不同的函数。Python中没有明显的多态特性,因为Python函数的参数不必声明数据类型,但是结合动态数据类型,Python还是可以实现处理对象的多态。如果不利用动态数据类型在Python的类内声明多个相同的名称,却有不同参数的函数,Python则会使用类内最后一个声明的函数。
- 没有使用动态数据类型的情况
# 定义类
class MyClass:
"未使用动态数据类型"
a = 2 # 类的属性
def __init__(self): # 类的方法
pass
def handle(self): # 类的方法
return '0个参数'
def handle(self,x): # 类的方法
return '1个参数'
def handle(self,x,y): # 类的方法
return '2个参数'
def handle(self,x,y,z): # 类的方法
return '3个参数'
# 实例化类
x = MyClass()
# 访问类的属性
print("MyClass类的属性为:",x.a)
# 访问类的方法这里只有最后一个才是正确的,调用其他的方法都会报错
print("MyClass类的方法为:",x.handle(1,2,3))
MyClass类的属性为: 2
MyClass类的方法为: 3个参数
# 如果不用3个参数则会报错,访问第一个handle
x.handle()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-138-e30d1d33b00a> in <module>()
1 # 如果不用3个参数则会报错,访问第一个handle
----> 2 x.handle()
TypeError: handle() missing 3 required positional arguments: 'x', 'y', and 'z'
# 如果不用3个参数则会报错,访问第二个handle
x.handle(2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-139-ca20048039c6> in <module>()
1 # 如果不用3个参数则会报错,访问第二个handle
----> 2 x.handle(2)
TypeError: handle() missing 2 required positional arguments: 'y' and 'z'
# 如果不用3个参数则会报错,访问第三个handle
x.handle(2,2)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-140-a481426cba84> in <module>()
1 # 如果不用3个参数则会报错,访问第三个handle
----> 2 x.handle(2,2)
TypeError: handle() missing 1 required positional argument: 'z'
- 使用动态数据类型,根据handle()函数中的参数数目,来决定调用类中的哪一个函数,实质上就是在类中多了一个根据参数的数量选择调用哪一个方法而已。
# 定义类
class MyClass:
"未使用动态数据类型"
a = 2 # 类的属性
def __init__(self): # 类的方法
pass
# * 在定义函数表示可以使用多个参数,详见Python函数学习笔记
def handle(self,*arg):
if len(arg) == 0:
self.handle0(*arg)
elif len(arg) == 1:
self.handle1(*arg)
elif len(arg) == 2:
self.handle2(*arg)
elif len(arg) == 3:
self.handle3(*arg)
else:
print('输入参数过多,请重新输入')
def handle0(self): # 类的方法
print('输入0个参数')
def handle1(self,x): # 类的方法
print('输入1个参数')
def handle2(self,x,y): # 类的方法
print('输入2个参数')
def handle3(self,x,y,z): # 类的方法
print('输入3个参数')
# 实例化类
x = MyClass()
# 访问类的属性
print("MyClass类的属性为:",x.a)
# 访问类的方法
x.handle()
x.handle(1)
x.handle(1,2)
x.handle(1,2,3)
x.handle(1,2,3,4)
MyClass类的属性为: 2
输入0个参数
输入1个参数
输入2个参数
输入3个参数
输入参数过多,请重新输入
8. Python类的封装
类的封装就是类将其属性(变量与方法)封装在该类中,只有该类中的成员,才可以使用该类中的其它成员,这种封装变量和方法称为私有变量和私有方法。
8.1 类封装原则
- 属性名称的第一个字符如果是单底线’_’,则此属性视为内部变量,外部的变量不可以引用此属性
- 属性名称的前两个字符如果是单底线,则当编译时属性名称则会发生改变为【单底线+类名+双底线的变量名】
class MyClass:
def __init__(self,value):
self._n = value # 第一个字符为单底线的变量_n
self.__n = value # 前两个字符为单底线的变量__n
def __func(self): # # 前两个字符为单底线的函数__func()
print(self._n + 1)
x = MyClass(100)
print(x._n) # 第一个字符为单底线的变量_n,可以任意提取
print(x._MyClass__n)# MyClass中__n 变为了 _MyClass__n
x._MyClass__func()
100
100
101
# 报错
x.__n
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-143-8bd431554bb4> in <module>()
1 # 报错
----> 2 x.__n
AttributeError: 'MyClass' object has no attribute '__n'
# 报错
x.__func()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-144-45a13f6f92c7> in <module>()
1 # 报错
----> 2 x.__func()
AttributeError: 'MyClass' object has no attribute '__func'
8.2 类的命名空间
类中的所有属性,都存储与该类的命名空间内,因此如果在类中存储了一个全局变量的值,此值则会放置在类的命名空间中,如果之后这个全局变量的值发生了变化,类中的该值依然保持不变。
class MyClass:
w = 10
def storeVar(self,n=w):
return n
x = MyClass()
x.storeVar()
10
w = 20
x.storeVar() # 可以看到外部的值并未是类中的值发生变化
10