简单说下两种思维方式:
【面向过程】就好比自己按照炒菜的步骤亲手制作一道西红柿炒鸡蛋,看中的是解决问题的过程。编程中主要用到的是“函数”知识,将每个过程步骤打包成函数,再依次调用。
【面向对象】是你做个机器人,告诉机器人该怎么做,而面对的这个对象就是机器人。面向对象主要用到的是“类和对象”知识,也是本章的主题。
构造方法
class Dog: # 一般类的命名开头要大写,和变量命名是小写作区分
def __init__(self, name, age, sex='雌性'): # 第一个参数必须是self
self.name = name # 创建和初始化实例变量name
self.age = age
self.sex = sex
d1 = Dog('毛球', 2) # 省略了默认值
d2 = Dog('哈皮', 1, '雄性') # 位置参数赋值
d3 = Dog(name='小米', sex='雄性', age=5) # 关键字参数赋值
print(f"{d1.name}:{d1.age}岁{d1.sex}")
print(f"{d2.name}:{d2.age}岁{d2.sex}")
print(f"{d3.name}:{d3.age}岁{d3.sex}")
实例方法
class Dog:
# todo 构造方法
def __init__(self, name, age, sex='雌性'): # 第一个参数必须是self
self.name = name # 创建和初始化实例变量name
self.age = age
self.sex = sex
# todo 实例方法
def run(self): # 只有一个参数
print(f"{self.name}在跑...")
def speak(self, sound): # 增加一个参数sound
print(f"{self.name}在叫,{sound}!")
dog = Dog('毛球', 2) # 调用构造方法进行传参,省略了默认值
dog.run() # 调用实例方法,使用 对象.实例方法 的形式,不需要传递参数
dog.speak('汪汪汪') # 调用实例方法,使用 对象.实例方法 的形式,传递一个参数sound
类属性:变量
class Account:
rate = 0.38 # 类变量利率rate
def __init__(self, owner, amount):
self.owner = owner # 创建并初始化实例变量账户名
self.amount = amount # 创建并初始化实例变量账户金额
account = Account('Kellen', 800)
print(f"账户名:{account.owner}") # 对实例变量通过 “对象.实例变量” 访问
print(f"账户金额:{account.amount}")
print(f"利率:{Account.rate}") # 对类变量通过 “类名.类变量” 方法
类方法其实也是函数,用法也和函数类似,为什么要单独出一个类呢?两者最大的区别就是:“类”中的函数可以利用“类”中的变量(也就是类方法可以调用类属性),在下面的 @classmethod 中我们会提到。
类方法:函数
类里面除了多个函数,还可以是多个变量。在类中被定义的函数被称为类的【属性】,调用的方式也是一样的 类名.变量名 。
class 类A():
变量1 = 100
变量2 = 200
def 函数1(): # 【不需要】使用类中的变量时,则不需要声明,否则会报错
print('我不需要使用类属性')
@classmethod
def 函数2(cls): # 【需要】使用类属性
print(cls.变量1)
print(cls.变量2)
类A.函数1()
类A.函数2()
第5行新出现的@classmethod是声明了下面的函数1是类方法,这样才允许函数1使用类中的数据。
第6行的cls是class的缩写,如果类方法函数1想用类属性(也就是类中的变量),就要把cls作为函数1的第一个参数,把类传给自己。
第7,8行,使用 cls.变量名 调用。类方法想使用类属性的时候,需要在这些变量名称前加上cls
最后我们使用【方法】类A,函数() 来调用这个类方法。
以上是使用类方法的三个要点,任何一个格式错误就无法使用。
class Account:
rate = 0.38 # 类变量利率
def __init__(self, owner, amount):
self.owner = owner # 创建并初始化实例变量账户名
self.amount = amount # 创建并初始化实例变量账户金额
# 类方法
@classmethod # 类方法需要装饰器,装饰器是以@开头,修饰函数、方法和类,用来约束它们
def interest_by(cls, amt): # cls代表类自身,即Account类
return cls.rate * amt # cls也可以替换为 Account
interest = Account.interest_by(600.00) # 对类方法可以通过 “类名.类方法” 访问
print(f"计算利息:{interest}") # 对实例变量通过 “对象.实例变量” 访问
print(f"计算利息:{interest:.2f}") # 保留2位小数
给类方法传参
参数可以是外部的,也可以是外部的,使用调用的方式不同。
# 类方法外部传递参数(没有变量) ----------------------------
# 因为只用了外部参数,没有用类属性(也就是变量),所以没有加 @classmethod 和 cls
一首诗 = ['《卜算子》','我住长江头,','君住长江尾。','日日思君不见君,','共饮长江水。']
class 念诗类():
def 念诗函数(参数):
for i in 参数:
print(i)
念诗类.念诗函数(一首诗)
# 类方法内部传递参数 ----------------------------
class 念诗类():
一首诗 = ['《卜算子》','我住长江头,','君住长江尾。','日日思君不见君,','共饮长江水。']
@classmethod # 声明
def 念诗函数(cls): # 赋值
for i in cls.一首诗: # 内部调用
print(i) #打印
念诗类.念诗函数() #调用
# 类方法同时使用类属性和外部参数 -----------------------
class 念诗类():
一首诗 = ['《卜算子》','我住长江头,','君住长江尾。','日日思君不见君,','共饮长江水。']
@classmethod # 声明
def 念诗函数(cls,参数): # 增加一个参数值
print('念给'+参数+'的诗:') # 调用参数值
for i in cls.一首诗: # 调用
print(i) # 打印
念诗类.念诗函数('张三') #调用并把‘张三’赋值给参数
如果我们放到内部,还想调用的话,就要用到我们之前的 @classmethod 三步法:声明、赋值和调用。
外部、内部和两种合并最好放在一起看。最好可以默写出来他们,这样才能理解他们的不同,会默写只是基本,还要理清他们的跳转逻辑,举一反三。
增加/修改类属性(变量)
有两种方式:在外部,用 类.变量 = xx 直接增加/修改类属性;在内部,用 类方法 去增加/修改。
从外部增加/修改属性
变量1 = 15
#这是类外部的变量1
变量2 = 'abc'
class 类A():
变量1 = 100
#这是类属性变量1
变量1 = 类A.变量1 #修改:类属性下面的变量1重新赋值给外部变量1
类A.变量2 = 变量2 #新增:类属性下添加变量2,并且等于外部变量2的值
print(类A.变量1)
print(类A.变量2)
# 除了重新赋值,我们还可以通过input()函数来增加/修改变量:
class 类():
@classmethod
def 打印类属性(cls):
print(cls.变量)
类.变量 = input('请输入字符串:') # 新增类属性(从外部接收一个变量)
类.打印类属性() # 使用类方法打印出来
我们要区分两个变量,虽然名字相同,但是类外部的【变量1】和类属性【变量1】是两个不同的变量。变量1 = 类A.变量1 是把类属性 100 重新赋值给了类外部的变量1(原来是15),类属性变量1的值没有改变,还是100。
而 类A.变量2 = 变量2,是为类A增加了一个类属性变量2(原来类属性下面只有一个变量1),它的值等于外部的变量2也就是abc。
从内部增加/修改属性
因为用到了内部变量,所以就需要 @classmethod
class 念诗类():
一首诗 = ['《卜算子》','我住长江头,','君住长江尾。','日日思君不见君,','共饮长江水。']
@classmethod
def 念诗函数(cls):
cls.接收人 = input('请输入你想给谁念诗:')
print('念给'+ cls.接收人 +'的诗:')
for i in cls.一首诗:
print(i)
念诗类.念诗函数()
我们来对比下他们的区别:
#【从外部增加/修改属性】
class 类A():
pass
类A.变量1 = 100 # 新增一个变量1,也可以使用input()从外部输入
print(类A.变量1) # 打印出来
#【从内部增加/修改属性】
class 类():
@classmethod # 声明类方法
def 增加类属性(cls): # 把cls赋值给方法(增加类属性)
cls.变量 = input('请随意输入字符串:') # 使用input()函数从外部调取变量
类.增加类属性() # 重新返回变量值给【增加类变量】
print('打印新增的类属性:')
print(类.变量) # 因为有上一步给变量赋了一个值,这一步打印出来。
封装性
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性。
私有变量
# 封装-私有变量
class Account:
__rate = 0.38 # 私有类变量利率
def __init__(self, owner, amount):
self.owner = owner # 创建并初始化 实例变量账户
self.__amount = amount # 创建并初始化 私有实例变量余额
def desc(self): # 在类的内部可以访问私有变量
print(f"{self.owner}.金额{self.__amount} 利率{Account.__rate}")
account = Account('Dan', 10000)
account.desc()
print(f'账户名:{account.owner}')
print(f'账户金额:{account.__amount}') # 报错!在类的外部不可以访问私有变量
print(f'利率:{Account.__rate}') # 报错!在类的外部不可以访问私有变量
私有方法
# 封装-私有方法
class Account:
__rate = 0.38 # 私有类变量利率
def __init__(self, owner, amount):
self.owner = owner # 创建并初始化 实例变量账户
self.__amount = amount # 创建并初始化 私有实例变量余额
def __get_info(self): # 定义私有方法
print(f"{self.owner}.金额{self.__amount} 利率{Account.__rate}")
def desc(self): # 在类的内部可以调用私有方法
print(self.__get_info())
account = Account('Tanner', 10000)
account.desc()
account.__get_info() # 报错!在类的外部调用私有方法则会报错
继承性
class Animal: # 定义父类(用于共有的属性)
def __init__(self, name):
self.name = name # 实例变量name
def show_info(self):
return "动物的名字:{0}".format(self.name)
def move(self):
print("动一动...")
class Cat(Animal): # 定义子类并继承父类
def __init__(self, name, age):
super().__init__(name) # 调用父类构造方法,初始化父类成员变量name
self.age = age # 实例化变量age
cat = Cat('Tom', 2)
cat.move()
print(cat.show_info())
多继承
多个父类,调用的子类相同用第一个,只认第一个父类的孩子
# 继承-多继承(多个父类,调用的子类相同用第一个,只认第一个父类的孩子)
class 马: # 定义父类
def __init__(self, name):
self.name = name # 实例变量name
def show_info(self):
return "马的名字:{0}".format(self.name) # 有参数用return
def run(self):
print("马跑...") # 没有参数用print
class 驴: # 定义父类
def __init__(self, name):
self.name = name # 实例变量name
def show_info(self):
return "驴的名字:{0}".format(self.name)
def roll(self):
print("驴打滚...")
class 骡子(马, 驴): # 继承两个父类,从左到右重要性使用
def __init__(self, name, age):
super().__init__(name) # 调用父类构造方法,初始化父类成员变量name
self.age = age # 实例化变量age
m = 骡子('Jaydon', 1)
m.run() # 继承父类马的方法
m.roll() # 继承父类驴的方法
print(m.show_info()) # 两个都有show_info()用第一个马的
方法重写
子类和父类类名相同,用子类
class 马: # 定义父类
def __init__(self, name):
self.name = name # 实例变量name
def show_info(self):
return "马的名字:{0}".format(self.name)
class 骡子(马): # 继承父类马
def __init__(self, name, age):
super().__init__(name)
self.age = age
def show_info(self): # 重写父类方法shwo_info()
return f"骡子{self.name},{self.age}岁"
m = 骡子('Jaydon', 1)
print(m.show_info()) # 子类和父类类名相同,则用子类的