文章目录
一、类与对象
面向对象编程
类(class):现实世界中一些事物的封装(如:学生)
类:有属性(如:名字、成绩)
理解【类】最简单的方式:【类】是一个函数包。类中可以放置【函数】和【变量】,然后类中的函数可以很方便的使用类中的变量。
——定义在类里面的函数,就是类的方法
classmethod;
——定义在类里面的变量,就是类的属性
val
类中的属性(变量)也不是不能改变,使用类名.变量名
的格式,可以让我们在类的外面,增加或修改类的属性:
类对象、实例对象
引用:通过引用对类的属性和方法进行操作
实例化:创建一个类的具体实例对象(如:学生张三)
一个简单的例子
# 定义一个学生类
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def introduce(self):
print("Hi, my name is ", self.name)
print("My grade is ", self.grade)
def improve(self, amount):
self.grade = self.grade + amount
Jack = Student("Jack", 86)
Jack.introduce()
Jack.improve(10)
Jack.introduce()
给类方法传参
1)类方法 只使用 类中的属性(内部)
class Class1():
val1 = 100
val2 = 200
@classmethod
def func1(cls):
print(cls.val1)
print(cls.val2)
Class1.func1()
1)@classmethod的中文意思就是“类方法”,@classmethod声明了 func1 是类方法,这样才能允许func1使用类属性中的数据。
2)cls的意思是class的缩写。如果类方法func1想使用类属性(也就是类中的变量),就要写上cls为函数1的第一个参数,也就是把这个类作为参数传给自己,这样就能被允许使用类中的数据。
3)cls.变量。类方法想使用类属性的时候,需要在这些变量名称前加上cls.
- 当类中的函数【不需要】用到类中的变量时,就不要用@classmethod、cls、cls.三处格式,否则终端也会报错。
2)类方法 只使用外部传入的参数(外部)
直接使用即可
只使用了外部的参数,没有使用类属性,所以格式上不需要 @classmethod 和 cls 。
3)类方法 同时使用 类中的属性 和 外部传入的参数(内部 & 外部)
定义类方法的时候,传入多个参数,其中属于类属性的参数,还是要加 cls, 并且前面要加 @classmethod
修改类属性
1)从内部,用类方法去增加/修改
2)从外部,用类.变量 = xx直接增加/修改类属性。
类方法 不但能调用类中的属性,还能调用类中的其他方法
装饰器 decorator
#加上装饰器
def add_candles(add_function):
def insert_candles():
return add_function + "candles"
return insert_candles()
@add_candles #加上装饰器使原来的函数拥有一些附加上去的功能
def make_cake():
return "cake"
print(make_cake())
二、类的实例化
从类
变成实例对象
的过程,就叫做实例化
。
注意:当类需要被实例化后使用时,相应的在方法中调用自身属性的参数,要从 cls 换成 self;并且 不再需要 @classmethod 的声明!
同样是上面的代码,如果是类被实例化了使用:
class Class1():
val1 = 'abc'
def func1(self):
print('类属性的值是:', self.val1)
a = Class1() #实例化
a.func1() #实例化后再使用
b = Class1() #可以实例化多个不同的实例
b.func1() #实例化后再使用
1)当类支持实例化的时候,self是所有类方法位于首位、默认的特殊参数。
(不管该类方法中 是否使用到了类属性,需要实例化的类方法,必须使用 self 参数,作为参数首位 传入,否则会报错)
2)当类支持实例化的时候,就不能再直接使用类方法了
通常来说,我们都是把类实例化后再调用。(哪怕取一个和类名相同的实例名称也可以)
- 当我们完成实例化后,对应于一个实例的属性和方法,叫“实例属性、实例方法”,不再称为“类属性、类方法”
类属性和实例属性
实例直接从类上继承过来的属性和方法,是完全相同的。
不过,我们可以修改类属性,这会导致所有实例属性变化(因为类是模板)
—— 修改实例属性,但这不会影响到其他实例,也不会影响到类。因为每个实例都是独立的个体。
—— 新增也是一样的道理,在类中新增属性会影响到实例,但在实例中新增属性只影响这个实例自己。
—— 当实例自己的属性已经修改过一次后,类的同一个属性 再发生修改,不会反映到该实例上
类方法
和类属性一样,我们可以重写类方法,这会导致所有实例方法自动被重写。
——“重写类方法”分成两个步骤:第一个步骤是在类的外部写一个函数,第二个步骤是把这个新函数的名字赋值给类.原始函数:
—— 我们可以通过重写类方法,让实例方法发生变化,但我们不能重写实例方法,模板给的技能不是说换就能换的。
- 小结(属性和方法):
1、修改类属性和类方法,将会影响所有实例
2、修改某个实例的属性,只会影响这个实例自身
3、不能修改实例的方法
初始化函数
—— 很实用的类方法
—— 初始化函数的意思是,当你【创建一个实例】的时候,这个函数就会被调用。上面的代码在执行实例 = 类()的语句时,就【自动调用】了__init__(self)函数。
—— 初始化函数的写法是固定的格式:中间是“init”,这个单词的中文意思是“初始化”,然后前后都要有【两个下划线】,然后__init__()的括号中,第一个参数一定要写上self,不然会报错。
——同时,这个初始化函数照样可以传递参数
class Class2():
def __init__(self):
print('实例化成功!')
a = Class2()
通过 初始化函数传递参数 例子
(这样生成不同的实例就方便了很多)
class StudentScore():
def __init__(self,name,chinese_score,math_score):
self.name = name
self.chinese_score = chinese_score
self.math_score = math_score
score1 = StudentScore('张三',99,88)
score2 = StudentScore('李四',64,73)
score3 = StudentScore('王五',33,22)
三、继承与多态
两个类, 如果非常相似,通过【继承】可以避免在创建新类时 又要写同样的代码。
类的单继承
—— 子类从
一个父类
继承类方法,我们叫做单继承
—— 在Python里,我们统一把旧的类称为父类,新写的类称为子类。子类可以在父类的基础上改造类方法,所以我们可以说子类继承了父类。
# StudentScore2 比 StudentScore,多了一个 打印总分的方法
class StudentScore2(StudentScore):
def print_score(self):
score = self.chinese_score + self.math_score
print(self.name + '的总分是:' + str(score))
# 创建一个跟父类完全一样的子类
class StudentScore2(StudentScore):
pass
# 父类
class Car:
def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
self.number_of_wheels = number_of_wheels
self.seating_capacity = seating_capacity
self.maximum_velocity = maximum_velocity
# 子类
class ElectricCar(Car):
def __init__(self, number_of_wheels, seating_capacity, maximum_velocity):
Car.__init__(self, number_of_wheels, seating_capacity, maximum_velocity)
# 对象
car = ElectricCar(1, 2, 3)
car.maximum_velocity
'''
3
'''
子类除了可以定制新的类方法,还能直接覆盖父类的方法,只要使用相同的类方法名称就能做到这一点。
—— 我们能在子类中重写覆盖任意父类方法,哪怕是 覆盖初始化函数__init__
类的多重继承
—— 还有一种更复杂的继承情况,叫
多重继承
,就是一个子类从多个父类
中继承类方法。
—— 格式是class 子类(父类1,父类2,……)。
—— 不过,多重继承有利有弊。过度使用继承容易把事情搞复杂(如果不是开发大型项目,不太需要用到太复杂的继承关系)
四、封装
封装 ----> 限制直接访问目标属性和方法的机制, 将抽象性函数接口的实现细节部分包装, 隐藏起来的方法
同时, 防止外界调用端, 去访问对象内部实现细节的手段,这个手段是由编程语言本身提供的
对象所有的内部表征对于外部来说都是隐藏的,只有对象 能直接与内部数据交互 --> 需要理解 公开 public 和 私有 non-public 实例变量和方法
# 公开实例变量
class Person:
def __init__(self, first_name):
self.first_name = first_name
tk = Person('TK')
print(tk.first_name)
'''
TK
'''
# 对象可以管理其变量的值
tk.first_name = 'custom_name'
print(tk.first_name)
'''
custom_name
'''
# 修改对象的变量值,不会对新从父类继承的对象产生影响
tk2 = Person()
print(tk2.first_name)
print(tk.first_name)
'''
TM
custom_name
'''
print(tk.__dict__)
'''
{'first_name': 'custom_name'}
'''
print(Person.__dict__)
'''
{'__module__': '__main__', 'first_name': 'TM', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''
tk.custom_attr = 'apple'
print(tk.__dict__)
'''
{'first_name': 'custom_name', 'custom_attr': 'apple'}
'''
私有变量 —> 我们可以使用功能constructor方法 或者在类的内部声明而定义一个私有实例变量, 语法上 需要在前面加上一个下划线
class Person():
def __init__(self, first_name, email):
self.first_name = first_name
self._email = email
print(Person.__dict__)
'''
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x11de6fe60>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''
tk = Person('TK', 'tk@email.com')
print(tk.__dict__)
'''
{'first_name': 'TK', '_email': 'tk@email.com'}
'''
print(tk._email)
tk._email = 'new_email@email.com'
print(tk._email)
'''
tk@email.com
new_email@email.com
'''
私有变量 —> 我们可以使用功能constructor方法 或者在类的内部声明而定义一个私有实例变量, 语法上 需要在前面加上一个下划线
class Person():
def __init__(self, first_name, email):
self.first_name = first_name
self.__email = email
def get_email(self):
return(self.__email)
def set_email(self, new_email):
self.__email = new_email
print(Person.__dict__)
'''
{'__module__': '__main__', '__init__': <function Person.__init__ at 0x11dedfb00>, 'get_email': <function Person.get_email at 0x11dedf830>, 'set_email': <function Person.set_email at 0x11dedfef0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
'''
tk = Person('TK', 'tk@email.com')
print(tk.__dict__)
# print(tk.__email)
# tk._email = 'new_email@email.com'
# print(tk.__email)
'''
{'first_name': 'TK', '_Person__email': 'tk@email.com'}
'''
print(tk.get_email())
tk.set_email('new_email')
print(tk.get_email())
'''
tk@email.com
new_email
'''