说明:面向对象语言中的类中都只有两种成员
1.成员变量,就是我们常说的整型,浮点型,字符串型等数据
2.成员函数,就是类中的函数也叫方法
最不要脸的地方来了:很多语言为了显示与众不同,老是给他的类中的成员取不同的名字,显示自己的独创性,显得语言的独一无二,显得自己的语言最牛逼(其实底层都是相互抄袭)结果弄得学习的人一塌糊涂.
- 成员变量:叫法有静态成员,字段,静态字段,属性
- 成员函数:叫法有动态成员,方法,动态属性 造这么多名词干啥?弄得我们学的乱成一锅粥,
python中的叫法: - 成员变量–>属性
- 成员函数–>方法(或者动态属性)
- python中的叫"函数"东西不属于类中的成员
1.类
1.定义类的格式:
class 类名:
方法列表
2.定义方法的格式:
def 方法名(self, 形参2, 形参3, …):
方法体
3.创建对象的格式:
变量名 = 类名()
说明 python中第一个参数不写self的方法称之为函数,方法是类中的动态属性。self相当于java语言和c++中类中的方法中的this关键字,只不过在Java和c++中方法中的第一个this参数编译器编译时默认给我们加上不需要手动加上(Java语言中多态实现分析的关键)
class Student:
# 吃饭
def eat(self, food):
print(f"吃{food}")
# 睡觉
def sleep(self, where):
print(f"睡在{where}")
# 学习
def study(self, course):
print(f"学习{course}")
方法中的self表示 正在调用方法的对象,哪个对象正在调用方法,self就表示哪个对象既self中存储调用当前方法的对象的引用(也就是对象的地址).
python解释器能够根据self的值确定是哪个对象正在调用方法(类中的属性在对象中,而方法不再对象中内存分析).
class Student:
def study(self, course):
print(f"学习{course}")
s1 = Student()
s1.study("python")
s2 = Student()
s2.study("python")
表皮分析:
内存分析(缺1)
2**__ init() __方法**:又叫魔法方法(扯淡),用来做变量初始化 或 赋值 操作,在类实例化对象的时候,会被自动调用。("“python牛逼python世界第一一个小脚本语言有啥可吹的–致龟叔吧”"其实功能与别的面向对象语言中的构造函数(又叫构造器)的功能一模一样,在这里加几条下划线变个名字后非要叫什么鬼的魔法方法,)
作用:1.实例化对象 2.初始化成员变量
python与其他语言不同的是类的属性要写在__ init() __方法中
1.创建对象时(实例化一个对象时)python解释器干三件事
- 1.在堆区开辟一块空间
- 2.在堆中实例化对象
- 3.调用构造函数初始化类的属性(成员变量)
class Student:
def __init__(self):
print("只要创建对象,不用你们手动调用我,编译器会自动调用我这个亲生的魔法方法(构造函数).....")
#创建对象
stu = Student()
运行结果:
2.1.python的属性要写在__init__(self):方法中(既构造函数中)这与其他面向对象语言不通(Java,c++的成员变量都是写在类中,仅仅在构造函数中初始化)
class Student:
def __init__(self):
self.name = "欧阳铁娃"
self.age = 18
self.sex = "男"
stu = Student()
#通过对象名访问类的属性(非私有)
print(stu.name)
#通过对象名更改类的属性
stu.name = "诸葛狗剩"
print(stu.name)
运行结果:
2.2.通过__init__(self)方法初始化类属性
class Student:
"""
在__init__方法中添加了几个形参,用来接收 创建对象时 传递过来的属性值的
可以在 形参的值 赋值给 属性.
"""
def __init__(self, name, age, gender):
# 添加姓名
self.name = name
# 添加年龄
self.age = age
# 添加性别
self.gender = gender
def study(self, course):
print(f"{self.name}学习{course}")
stu1 = Student("司马狗剩", 20, "男")
# 访问属性:对象名.属性名
print(stu1.name)
print(stu1.age)
print(stu1.gender)
stu1.study("python")
print("============华丽的分割线===============")
stu2 = Student("欧阳铁娃", 22, "女")
# 访问属性:对象名.属性名
print(stu2.name)
print(stu2.age)
print(stu2.gender)
stu2.study("python")
运行结果:
2.3给对象添加属性
- 通过__init__添加
- 在类中的其他方法通过self添加(不用)
- 通过对象添加(不用)
在其他方法中通过self添加属性(不常用)
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def study(self, course):
self.weight = 100
print(f"司马狗剩学习:{course}")
stu = Student("司马狗剩",18, "男")
stu.study("python")
print(f"我是通过study方法添加的属性:{stu.weight}")
运行结果:
用对象给特定对象添加属性
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def study(self):
print(f"我是通过对象添加的属性:{self.num}")
stu = Student("司马狗剩",18, "男")
stu.num = 1008611#给特定对象添加属性
stu.study()
运行结果:
2.4__str__(self)方法:又一个魔法方法:
- 1.这个方法必须返回一个字符串
- 2.当我们没有在类中写这个方法时,python解释器会给我们默认加上,且python解释器会在打印对象时,自动调用这个方法,得到一个返回值然后打印返回值,这个返回值默认为对象的地址.(既打印对象时实际就是打印这个方法的返回值)
- 3.把对象转换成字符串类型的数据时,自动调用这个方法,得到一个返回值,然后把返回值当成结果打印出来
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
stu = Student("诸葛憨憨", 18)
print(stu)#<__main__.Student object at 0x000002A643233280>默认打印对象的地址
运行结果:
通常我们重写它让它打印打印类的属性
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"姓名;{self.name}, 年龄:{self.age}"
stu = Student("诸葛憨憨", 18)
print(stu)
当我们把对象转换成字符串是也会调用这个魔法方法
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"姓名;{self.name}, 年龄:{self.age}"
stu = Student("诸葛憨憨", 18)
print(stu)
result = type(stu)#单步调试可以看到
print(result)#类也是一中数据类型<class '__main__.Student'>
print(str(stu))
运行结果:
属性值可以是对象:
"""
发动机:
品牌
型号
点火
汽车;
品牌
型号
开
"""
class FDJ:
def __init__(self,brand, module):
self.brand = brand
self.module = module
def fire(self):
print("发动机点火.........")
class Car:
def __init__(self,c_brand, c_module, c_fdj):
self.c_brand = c_brand
self.c_module = c_module
#发动机属性
self.c_fdj = c_fdj
def run(self):
# 调用发动点火
# c_fdj是发动机的一个对象
self.c_fdj.fire()
print("汽车可以开了")
fdj = FDJ("红旗", "Mode")
car = Car("路虎","揽胜",fdj)
car.run()
结果:
表皮分析:
3.封装
3.1.私有属性
- 私有属性: 这样的属性只能在类的里面访问,不能在类的外面的访问.
- 定义私有属性的格式:
self.__属性名 = 属性值 - 在类内访问私有属性的格式:
self.私有属性
class Student:
def __init__(self, name, age, gender):
self.name = name#非私有属性
self.__age = age #私有属性
self.__gender = gender # 私有属性
def info(self):
print(f"姓名:{self.name}, 年龄:{self.__age}, 性别:{self.__gender}")
print("------原来的信息------")
stu = Student("欧阳狗蛋", 18, "男")
stu.info()
print("-------类外更改非私有属性---------")
stu.name = "上官狗剩" # 通过对象更改私有属性
stu.info()
print("-------类外更改私有属性没有改回来--------")
stu.__gender = "女"
stu.info()
print(stu.__age) # 'Student' object has no attribute '__age'没有全限访问私有的
运行结果
修改私有属性的正确方法
class Student:
def __init__(self, name, age, gender):
self.__name = name
self.__age = age
self.__gender = gender
def set_age(self, age):
if 0 < age <= 90:
self.__age = age
else:
print("输入的名字粗合法")
def get_age(self)
return self.__age
def info(self):
print(f"姓名;{self.__name}, 年龄:{self.__age},性别:{self.__gender}")
stu= Student("诸葛憨憨",20,"男")
stu.info()
stu.set_age(30)
stu.info()
运行结果:
3.2为什么把方法定义成私有的?
-
在定义方法时,都已经想好了,这个方法不允许在类的外面被调用.
-
如何定义私有方法?
跟之前定义方法一样,只是在方法名前加两个下划线:__ -
私有方法的特点:
只能在类的里面访问,不能在类的外面访问.
class Student:
def __init__(self, name, age, gender):
self.__name = name
# 定义私有属性 __age
self.__age = age
self.__gender = gender
def set_age(self, age):
"""
修改私有属性的值
:param age: 传递过来的年龄,把它赋值给私有属性
"""
if 0 <= age < 150:
self.__age = age
else:
print("年龄应该在0-150之间,请重新赋值!!!")
def get_age(self):
# 返回私有属性值的
return self.__age
def study(self, course):
print(f"学习{course}")
self.__game("王者荣耀")
def __game(self, game_name):
print(f"同时玩{game_name}!!!")
s1 = Student("铁娃", 18, "男")
# 不能在类的外面访问 私有方法.
# s1.__game("王者荣耀")
s1.study("玩游戏")
运行结果:
- 封装的总结
概念:
把不需要对外暴露的代码隐藏起来.
封装的几种形式:
1.函数:使用函数包裹一个代码块
2.类:使用类 包裹 数据和行为
3.方法:包裹一个代码块
4.定义私有属性
5.定义私有方法
好处:
1.避免代码重复,提高代码重复使用率;
2.实现功能的设计 与 调用 进行分离;
3.提高开发效率;**