类(class)和对象(object,也被称为实例,instance),可以把类理解成某种概念,对象是一个具体存在的实体
class 类名:
执行语句...
类变量...
方法...
Python语法要求:类名只要是一个合法的标识符
从可读性看,Python的类名必须是由一个或多个有意义的单词连缀而成,每个单词首字母大写,其他字母全部小写,单词与单词间不使用分隔符
类的定义由类头(class关键字和类名)和统一缩进的类体构成
在类体中最主要的是类变量和方法
不为类定义任何类变量和方法,那么这个类就相当于一个空类
如果空类不需要其他可执行语句,可使用pass语句作为占位符
class YOU:
pass #空类没有太大的实际意义
类变量和方法的定义顺序没有任何影响,之间可以相互调用
类变量属于类本身,用于定义该类本身所包含的状态数据;实例变量属于该类的对象,用于定义对象所包含的状态数据
方法用于定义该类的对象的行为或功能实现
类所包含的类变量可以动态增加或删除,实例变量也可以动态增加或删除(del 语句)
方法的定义默认是实例方法,定义实例方法与定义函数基本相同
实例方法的第一个参数会被绑定到方法的调用者(该类的实例),实例方法至少应该定义一个参数,该参数通常被命名为self
实例方法中的__init__被称为构造方法
用于构造该类的对象,通过调用构造方法返回该类的对象(无须使用__new__)
如果没有为该类定义任何构造方法,那么会自动为该类定义一个只包含一个 self 参数的默认的构造方法
class test :
'这是类定义的说明文档' #为类定义说明文档
name = 'you' # 定义了一个类变量
def __init__(self, Name = 'chanwill', age=20): #使用构造方法
self.Name = Name # 为test对象增加的实例变量
self.age = age
T = test()
print(T.Name)
chanwill
Python类的作用:定义变量,创建对象,派生子类
类定义说明文档,放在类声明之后、类体之前
创建类对象的过程,称为类的实例化
已定义好的类的类名(参数)
如果没有手动添加 __init__()构造方法,或者添加的 __init__() 中仅有一个 self 参数,则创建类对象时的参数可以省略不写
class test :
name = "you" #定义类变量
age = "20"
def __init__(self,name,age):
self.name = name #定义实例变量
self.age = age
print(name,"年纪为:",age)
def say(self, content): #定义实例方法
print(content)
TEST = test("chanwill","21") #将test对象赋给TEST变量
chanwill 年纪为: 21
在上面的程序中,除self参数外,还包含2个参数且没有设置默认参数,因此在实例化类对象时,需要传入相应的值(self参数不需要手动传值)
在各个类方法之外(包含在类中)的变量为类变量(或者类属性),定义在类方法中的变量为实例变量(或者实例属性)
类对象访问变量或方法
类对象名.变量名
对象名.方法名(参数)
对象名和变量名以及方法名之间用点 "." 连接
class test :
name = "you" #定义类变量
age = "20"
def __init__(self,name,age):
self.name = name #定义实例变量
self.age = age
print(name,"年纪为:",age)
def say(self, content): #定义实例方法
print(content)
test.say("调用test的say()方法")
print(test.name,test.age)
test.name = 'youchanwill' #修改实例变量的值
test.age = '20'
print(test.name,test.age)
you 20
youchanwill 20
给类对象动态添加/删除变量
test.money= 1016
print(test.money)
通过直接增加一个新的实例变量并为其赋值,成功地为对象添加了新的变量
del test.money
print(test.money)
AttributeError: money
使用 del 语句实现动态删除
给类对象动态添加方法
类对象动态添加方法,不会将调用者自动绑定到第一个参数(第一个参数命名为 self也没用)
def info(self): # 定义函数
print("---info函数---", self)
test.foo = info # 使用info对test的foo方法赋值
test.foo(test) # 不会自动将调用者绑定到第一个参数,需要手动调用
test.bar = lambda self: print('--lambda表达式--', self)# 使用lambda表达式为对象的方法赋值
test.bar(test)
借助 types 模块下的 MethodType 可以实现不用手动给 self 传值
from types import MethodType
test.info = MethodType(info, test)
在定义类的过程中,无论是创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数
类可以有很多类对象,都有相同的类变量和类方法,通过self参数,使每个类对象只能调用自己的类变量和类方法
同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法
Python会自动绑定类方法的第一个参数指向调用该方法的对象
class Person:
def __init__(self):
print("正在执行构造方法")
def study(self): # 定义一个study()实例方法
print(self,"Python")
a = Person()
a.study()
b = Person()
b.study()
正在执行构造方法
<__main__.Person object at 0x02A3CE70> Python
正在执行构造方法
<__main__.Person object at 0x02A0A6F0> Python
study()中的self代表该方法的调用者,谁调用该方法,self就代表谁
class Person:
name = "you"
def __init__(self,name):
self.name=name
a = Person("youchanwill")
print(a.name)
b = Person("b")
print(b.name)
youchanwill
b
对于构造函数中的self参数,其代表的是当前正在初始化的类对象
a在进行初始化时,调用的构造函数中 self 代表的是youchanwill;而b在进行初始化时,调用的构造函数中self代表的是b
class Person:
def who(self):
print(self)
you = Person()
you.who() #第一种方式
who = you.who #第二种方式
who() #通过 who 变量调用you对象中的 who() 方法
<__main__.Person object at 0x0257A670>
<__main__.Person object at 0x0257A670>
无论采用哪种方法,self 所表示的都是实际调用该方法的对象
无论是类中的构造函数还是普通的类方法,谁实际调用它们,则第一个参数 self就代表谁
类方法具体可分为类方法、实例方法和静态方法
用 @classmethod 修饰的方法为类方法;用 @staticmethod 修饰的方法为静态方法;不用任何修改的方法为实例方法
class test:
def __init__(self): #类构造方法,属于实例方法
self.name = "you"
self.age = "20"
def say(self): #定义一个say实例方法
print("正在调用 say() 实例方法")
实例方法最大的特点是最少也要包含一个self参数,用于绑定调用此方法的实例对象
a = test()
a.say()
实例方法通常用类对象直接调用
a = test()
test.say(a)
用类名调用实例方法,需要手动给self参数传值
类方法和实例方法相似,最少也要包含一个参数,类方法中通常将其命名为cls,在调用类方法时,无需显式为 cls 参数传参
class test:
def __init__(self): #类构造方法,属于实例方法
self.name = "you"
self.age = "20"
@classmethod
def info(cls):
print("正在调用类方法",cls)
类方法需要使用@classmethod修饰,如果没有 @classmethod,解释器会认定为实例方法,而不是类方法
类方法推荐使用类名直接调用,也可以使用实例对象来调用
静态方法就是函数,和函数唯一的区别是静态方法定义在类命名空间,函数定义在全局命名空间
静态方法没有类似self、cls这样的特殊参数,解释器不会对它包含的参数做任何类或对象的绑定,类的静态方法中无法调用任何类属性和类方法
class test:
@staticmethod
def info(name,age):
print(name,age)
静态方法需要使用@staticmethod修饰
test.info("you","20")#使用类名直接调用静态方法
a = test() #使用类对象调用静态方法
a.info("you","20")
静态方法的调用,既可以使用类名,也可以使用类对象
在实际编程中,几乎不会用到类方法和静态方法,可以使用函数代替它们的功能
类方法的第一个参数(cls)会自动绑定到类本身;静态方法则不会自动绑定
使用@classmethod 修饰的方法就是类方法;使用@staticmethod 修饰的方法就是静态方法
Python 中,编写的整个程序默认处于全局命名空间内,类体处于类命名空间内
class item:
print('正在定义item类') #在类空间中放置执行性质代码
for i in range(5):
if i % 2 == 0 :
print('偶数:', i)
else:
print('奇数:', i)
正在定义item类
偶数: 0
奇数: 1
偶数: 2
奇数: 3
偶数: 4
在类体中放置普通的输出语句、循环语句、分支语句都是合法的
程序并没有定义变量或函数,可执行代码放在类命名空间与全局空间并无太大的区别
global_lambda = lambda p: print('执行lambda表达式', p)
class Category:
cate_lambda = lambda p: print('执行lambda表达式 ', p)
global_lambda('you') #调用全局范围内的global_lambda,为参数p传入值
c = Category() # 调用类命名空间内的cate_lambda,自动绑定第一个参数
c.cate_lambda()
执行lambda表达式 you
执行lambda表达式 <__main__.Category object at 0x029F4F90>
全局空间定义的lambda表达式相当于普通函数,用调用函数的方式来调用该 lambda表达式,为第一个参数绑定参数值
类命名空间定义的lambda表达式相当于在类命名空间中定义了一个函数,这个函数就变成了实例方法
程序必须用调用方法的方式来调用该lambda表达式,为第一个参数(self 参数)绑定参数值