Python 语言在设计之初,就定位为一门面向对象的编程语言,“Python 中一切皆对象”就是对 Python 这门编程语言的完美诠释。
一、类和对象
1、类的定义
Python 类是由类头(class 类名)和类体(统一缩进的变量和函数)构成。
使用 class 关键字定义一个类,基本语法格式如下:
class 类名:
n个类属性...
n个类方法...
注意:
- 类名本质上就是一个标识符,推荐见名知意,驼峰命名。
- 类名后要紧跟冒号(:),表示告诉 Python 解释器,下面要开始设计类的内部功能了,也就是编写类属性和类方法。
- 类定义说明文档和函数类似,需要要放到类头之后,类体之前的位置。
示例代码如下:
class MyClass:
"""一个简单的类实例"""
name = "赵云"
def m1(self):
return 'hello class'
2、类构造方法
Python 类有一个名为
__init__() 的方法
,该方法是一个特殊的类实例方法,称为构造方法(或构造函数)。
构造方法的作用是每当创建一个类的实例对象时,Python 解释器都会自动调用它。即该方法在类实例化时会自动调用。
手动添加构造方法的语法格式如下:
def __init__(self,...):
代码块
注意:
- 方法名开头和结尾各有 2 个下划线,且中间不能有空格。
__init__() 方法
可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。- 即便不手动为类添加任何构造方法,Python 也会自动为类添加一个仅包含 self 参数的默认构造方法。
示例代码如下:
class MyClass:
"""一个简单的类实例"""
name = "赵云"
# 构造方法
def __init__(self):
print("调用构造方法")
def m1(self):
return 'hello class'
# 实例化类
clazz = MyClass()
# 访问类的属性和方法
print("属性 i 为:", clazz.name)
print("调用 m1方法,输出为:", clazz.m1())
2.1 self 参数
Python 只是规定,无论是构造方法还是实例方法,最少要包含一个参数,并没有规定该参数的具体名称。之所以将其命名为 self(self 不是 python 关键字),只是程序员之间约定俗成的一种习惯,遵守这个约定。
self 参数的具体作用:
- self 代表的是类的实例,代表当前对象的地址。而 self.class 则指向类。
- self 所表示的都是实际调用该方法的对象(即谁调用该方法,那么 self 就代表谁)。
总之,无论是类中的构造函数还是普通的类方法,实际调用它们的谁,则第一个参数 self 就代表谁。
self 参数是特殊参数,无需我们手动传递它,Python 会自动传递。
3、类的实例化
创建类对象的过程,称为类的实例化。
对已定义好的类进行实例化,其语法格式如下:
类名(参数)
- 定义类时,如果没有手动添加
__init__() 构造方法
,又或者添加的__init__()
中仅有一个 self 参数,则创建类对象时的参数可以省略不写。
3.1 类对象访问变量或方法
访问类中实例变量的语法格式如下:
类对象名.变量名
调用类中方法的语法格式如下:
类对象名.方法名(参数)
示例代码如下:
class MyClass:
"""一个简单的类实例"""
name = "赵云"
# 构造方法
def __init__(self):
print("调用构造方法")
def __init__(self, name):
self.name = name
print("self = ", self)
print("self.__class__", self.__class__)
def m1(self):
return 'hello class'
# 实例化类
clazz = MyClass("赵子龙")
# 访问类的属性和方法
print("属性 i 为:", clazz.name)
print("调用 m1方法,输出为:", clazz.m1())
3.2 给类对象动态添加/删除变量
Python 支持为已创建好的对象动态增加/删除实例变量。
- 动态增加:通过直接增加一个新的实例变量并为其赋值即可。
- 动态删除:使用 del 语句即可实现
示例代码如下:
obj = MyClass("赵子龙")
# 动态增加实例变量
obj.age = 18
print("动态增加变量:age = ", obj.age)
# 动态删除实例变量
del obj.age
# 访问不存在的变量,此时会报错
print(obj.age)
3.3 给类对象动态添加方法
Python 也允许为对象动态增加方法。
注意:
为类对象动态增加的方法时,Python 不会自动将调用者自动绑定到第一个参数(即使将第一个参数命名为 self 也没用),因此程序必须手动为第一个参数传入参数值。
示例代码如下:
obj = MyClass("赵子龙")
# 先定义一个函数
def fun1(self, desc):
print("---fun1函数--- self = ", self)
print("---fun1函数--- desc = ", desc)
# 动态绑定方法
obj.m2 = fun1
# 手动将调用者绑定为第一个参数
obj.m2(obj, "动态绑定方法 fun1")
如果不想手动给 动态增加方法 进行 self 传值时,通过借助 types 模块下的 MethodType 可以实现。
示例代码如下:
obj = MyClass("赵子龙")
# 先定义一个函数
def fun1(self, desc):
print("---fun1函数--- self = ", self)
print("---fun1函数--- desc = ", desc)
# 导入MethodType
from types import MethodType
obj.m2 = MethodType(fun1, obj)
# 调用方法,第一个参数不用传
obj.m2("动态绑定方法 fun1")
三、类属性
1、类变量
在类体中,所有函数之外定义的变量,称为类属性或类变量
其特点是,所有类的实例化对象都同时共享类变量,也就是说,类变量在所有实例化对象中是作为公用资源存在的。
类方法的调用方式有 2 种:
- 可以使用类名直接调用,
- 也可以使用类的实例化对象调用。
示例代码如下:
class MyClass:
name = "赵云" # 类变量
# 构造方法
def __init__(self):
print("调用构造方法")
def m1(self):
self.sex = "猛男" # 实例变量
return 'hello class'
# 实例化类
obj = MyClass()
print("实例访问:name = ", obj.name)
print("类名访问:name = ", MyClass.name)
print("-------------")
#修改类变量的值
MyClass.name = "name修改啦"
print("实例访问:name = ", obj.name)
print("类名访问:name = ", MyClass.name)
注意:
- 因为类变量为所有实例化对象共有,通过类名修改类变量的值,会影响所有的实例化对象。
- 通过类对象是无法修改类变量的。通过类对象对类变量赋值,其本质将不再是修改类变量的值,而是在给该对象定义新的实例变量。
2、实例变量
在类体中,所有函数内部,以“self.变量名”的方式定义的变量,称为实例属性或实例变量。
其特点是,只作用于调用方法的对象。另外,实例变量只能通过对象名访问,无法通过类名访问。
示例代码如下:
# 实例化类
obj = MyClass()
print("调用 m1方法,输出为:", obj.m1())
print("类对象访问实例变量:sex = ", obj.sex)
print("类名访问实例变量:sex = ", MyClass.sex) # AttributeError: type object 'MyClass' has no attribute 'sex'
3、局部变量
在类体中,所有函数内部里面以“变量名=变量值”的方式定义的变量,称为局部变量。
class MyClass:
def m1(self):
self.sex = "猛男" # 实例变量
say = self.sex * 3 # 局部变量
desc = "简介" # 局部变量
print("打印:desc={}, say={}".format(desc, say))
return 'hello class'
# 实例化类
obj = MyClass()
print("调用 m1方法,输出为:", obj.m1())
4、私有属性
__private_attrs
:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs
。
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、类实例方法
不用任何修改的方法为实例方法。
实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。
- 使用类对象直接调用实例方法,无需手动给 self 参数传值(推荐使用)。
- 使用类名调用实例方法,需要手动给 self 参数传值。
用类的实例对象访问类成员的方式称为绑定方法,而用类名调用类成员的方式称为非绑定方法。
示例代码如下:
class MyClass:
def m1(self):
return 'hello class'
# 实例化类
obj = MyClass()
print("类对象调用实例方法,输出为:", obj.m1())
print("类名调用实例方法,输出为:", MyClass.m1(obj))
2、类方法
采用 @classmethod 修饰的方法为类方法。
类方法,它最少也要包含一个参数,只不过类方法中通常将其命名为 cls(cls 参数的命名也不是 Python规定的,只是程序员约定俗称的习惯),Python 会自动将类本身绑定给 cls 参数(注意,绑定的不是类对象)。我们在调用类方法时,无需显式为 cls 参数传参。
类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。
示例代码如下:
class MyClass:
@classmethod
def mm2(cls):
return 'this is 类方法'
# 使用类名直接调用
print(MyClass.mm2())
#使用类对象调用
obj = MyClass()
print(obj.mm2())
3、类静态方法
采用 @staticmethod 修饰的方法为静态方法。
静态方法和函数唯一的区别是,静态方法定义在类这个空间(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中。
静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法。
示例代码如下:
class MyClass:
@staticmethod
def sum(x, y):
return x + y
# 使用类名直接调用
print(MyClass.sum(2,3))
# 使用类对象调用
obj = MyClass()
print(obj.sum(5,4))
4、私有方法
__private_method
:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods
。
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.baidu.com')
x.who() # 正常输出
x.foo() # 正常输出
x.__foo() # 报错
Python中有关 描述符和 property()函数可以自行了解一下,都是一种对类中属性的访问方式。
– 求知若饥,虚心若愚。