Day 14
一、认识类和对象
1.什么是类,什么是对象
- 类就是拥有相同功能和相同属性的对象的集合。 - 抽象的概念
- 对象就是类的实例(类具体的表现)
人是类,具体的一个人就是它的对象,比如:小明、小刚
电脑是类,我的桌上这台电脑,同桌桌子上的电脑
杯子是类,我桌上这三个杯子都是它的对象
list是类,[10, 20]是列表的对象 - 类就是类型、类别
2. 定义类(创建类) - 用代码描述清楚这个类是拥有哪些相同功能和哪些相同属性的对象的集合
- 功能 - 函数
- 属性 - 保存数据的变量
语法:
class 类名:
类的说明文档
类的内容
说明:
1)class - 关键字;固定写法
2)类名 .
程序员自己命名
用驼峰式命名并且首字母大写。(类名大写开头;驼峰式 - 从第二个单词开始单词首字母大写)
3): - 固定写法
4)类的说明文档 - 多行注释
5)类的内容 :
相同功能和相同属性。
由方法(对象方法、类方法、静态方法)和属性(对象属性、类属性)组成
方法 - 定义在类中的函数
性 - 定义在类中的变量
class Person:
"""人类"""
num = 61 # num是属性
def eat(self): # eat是方法
print('吃饭')
def sleep(self):
print('睡')
3.创建对象
- 语法: 类名() - 创建指定类对应的一个对象,并且将对象返回
class Person:
"""人类"""
p1 = Person()
p2 = Person()
print(p1)
print(p2)
# <__main__.Person object at 0x000002735A4C6AC0>
# <__main__.Person object at 0x000002735A0A26D0>
二、类中的方法
1.方法 - 定义在类中的函数,用来描述具备的功能
- 类中的方法有三种:对象方法、类方法、静态方法
1)对象方法
a.怎么定义:将函数直接定义在类中
b.怎么调用:通过对象来调用 - 对象.xxx()
c.特点:自带参数self,通过对象调用对象方法的是参数self不需要传参,系统自动将当前对象传给self(self,谁调用就指向谁)
d.什么时候用:如果实现函数的功能需要用到对象属性就使用对象方法
2)类方法
a.怎么定义:定义函数前加装饰器’@classmethod’
b.怎么调用:通过类来调用 - 类名.xxx()
c.特点:自带参数cls,调用的时候不需要传参,系统自动将当前类传给cls
d.什么时候用:如果实现函数的功能不需要对象属性需要类就是用类方法
3)静态方法
a.怎么定义:定义函数前加装饰器’@staticmethod’
b.怎么调用:通过类来调用 - 类名.xxx()
c.特点:没有特点
d.什么时候用: 实现函数功能既不需要对象属性也不需要类
class A:
def func1(self):
print(f'self:{self}')
print('对象方法')
def func11(self, x, y):
print('对象方法2')
@classmethod
def func2(cls):
print('类方法')
@staticmethod
def func3():
print('静态方法')
a = A()
b = A()
print(f'a:{a}')
# 通过对象调用对象方法
a.func1() # 对象方法
b.func11(200, 200) # 对象方法2
a.func11(x=100, y=200) # 对象方法2
# 通过类调用类方法
A.func2() # 类方法
# 通过类调用静态方法
A.func3() # 静态方法
三、初始化方法
1.魔法方法
- 方法名以’–‘开头并且以’–结尾的自带的方法,就是魔法。
- 所有的魔法方法都会特定的情况下被自动调用。
2.–repr–
- 打印对象的时候会自动调用对象对应的类中的__repr__方法,来定制打印规则(函数的返回值是什么,对象打印结果就是什么)
- 返回值必须是字符串!
class A:
def __repr__(self):
return 'abc'
pass
a1 = A()
print(f'a1:{a1}')
a2 = A()
print(f'a2:{a2}')
3…–init-- - 每次创建类的对象的时候会自动调用类中的–init–方法
class B:
# def __new__(cls, *args, **kwargs):
# pass
def __init__(self):
print('init方法')
b1 = B()
b2 = B()
class C:
# 在类中添加__init__方法的时候,除了方法名和方法类型不能动,可以随意添加参数和随意添加函数体
def __init__(self, x, y):
print('C的init方法', x, y)
# 创建类的对象的时候需不需要参数,需要几个参数,由类中__init__方法决定
c1 = C(10, 20)
c2 = C(100, 200)
c3 = C(x=1, y=2)
四、属性
1.属性: 分为对象属性和类属性两种
-
- 类属性
a. 怎么创建: 在类中直接定义一个变量,这个变量就是类属性
b. 怎么使用: 通过类来使用 - 类.xxx
c. 什么时候用: 当属性值不会因为对象不同而不一样的时候就使用类属性
- 类属性
-
2.对象属性
a. 怎么创建: 以’self.属性名=值’的形式定义在类的__init__方法
b. 怎么使用: 通过对象来使用 - 对象.属性名
c. 什么时候用: 当属性值会因为对象不同而不一样的时候就使用类属性
class A:
# x是类属性
x = 100
# name和num是对象属性
def __init__(self):
self.name = '小明'
self.num = 10
# 使用类属性
print(A.x) # 100
# 修改类属性的值
A.x = 200
print(A.x) # 200
a = A()
# 使用对象属性
print(a.name, a.num) # '小明' 10
# 修改对象属性的值
a.name = '小花'
a.num = 11
print(a.name, a.num) # '小花' 11
- 练习:定义一个圆的类,拥有属性:半径和圆周率,拥有的方法:求周长和求面积
-
class Circle:
pi = 3.1415926
def __init__(self):
self.r = 1
# 类中实现函数功能的时候如果需要的数据是属性,不需要提供额外的参数
def get_area(self):
# self = c1; self = c2
# 如果需要类属性直接用类来提供
# 如果需要对象属性用self来提供
return Circle.pi * self.r ** 2
def get_perimeter(self):
return 2 * Circle.pi * self.r
c1 = Circle()
c2 = Circle()
c2.r = 3
print(c1.get_area(), c2.get_area())
3.14 28.27
### 2.对象属性赋初始值的方式
```python
class Person:
def __init__(self, name, gender='男'):
self.name = name # 使用没有默认值的参数来赋值
self.age = 1 # 赋固定值
self.gender = gender # 使用有默认值的参数来赋值
def __repr__(self):
# return f'name:{self.name}, age:{self.age}, gender:{self.gender}'
return str(self.__dict__)
p1 = Person('小明')
print(p1.name, p1.age, p1.gender) # 小明 1 男
p2 = Person('小花', '女')
print(p2.name, p2.age, p2.gender) # 小花 1 女
- 练习2:创建一个矩形类(根据生活扩展类的内容)
class Rect:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return (self.length + self.width) * 2
def __repr__(self):
# 调用对象对应的类中的__repr__方法,来定制打印规则
return f'长度:{self.length}, 宽度:{self.width}, 面积:{self.area()}, 周长:{self.perimeter()}'
# return f'<{str(self.__dict__)[1:-1]}>'
r1 = Rect(5, 4)
r2 = Rect(10, 7)
print(r1) # 长度:5, 宽度:4, 面积:20, 周长:18
print(r2) # 长度:10, 宽度:7, 面积:70, 周长:34
五、属性的增删改查
1. 在面向对象编程的时候,可以直接使用对象来代替字典
# stu1 = {'name': '小明', 'age': 12, 'score': 67}
# stu2 = {'name': '小花', 'age': 19, 'score': 100}
class Student:
def __init__(self, name, age=18, score=0):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return str(self.__dict__)
stu1 = Student('小明', 12, 67)
stu2 = Student('小花', 19, 100)
print(stu1, stu2)
# 除去创建类比较繁琐,后续所有操作均比字典效率高一点...
2.对象的对象属性支持增删改查
-
- 查 - 获取属性值
a. 对象.属性 - 获取指定属性的值,属性不存在报错
b. getattr(对象,属性名) - 获取指定属性的值,属性不存在报错
c. getattr(对象,属性名, 默认值) - 获取指定属性的值,属性不存在直接返回默认值
- 查 - 获取属性值
print(stu1.name) # 小明
print(getattr(stu1, 'name')) # 小明
# print(stu1.gender) # 报错!
# print(getattr(stu1, 'gender')) # 报错!
print(getattr(stu1, 'gender', '男')) # 男
2.增、改
- a. 对象.属性 = 值 - 当属性存在的时候修改指定属性对应的值;当属性不存在的是给对象添加属性
- b. setattr(对象, 属性名, 值) - 当属性存在的时候修改指定属性对应的值;当属性不存在的是给对象添加属性
print(stu1) # {'name': '小明', 'age': 12, 'score': 67}
stu1.age = 22
print(stu1) # {'name': '小明', 'age': 22, 'score': 67}
stu1.gender = '男'
print(stu1) # {'name': '小明', 'age': 22, 'score': 67, 'gender': '男'}
setattr(stu1, 'study_id', '001')
print(stu1) # {'name': '小明', 'age': 22, 'score': 67, 'gender': '男', 'study_id': '001'}
setattr(stu1, 'score', '76')
print(stu1) # {'name': '小明', 'age': 22, 'score': '76', 'gender': '男', 'study_id': '001'}
3.删除
- del 对象.属性
- delattr(对象, 属性名)
print(stu1) # {'name': '小明', 'age': 22, 'score': '76', 'gender': '男', 'study_id': '001'}
del stu1.age
print(stu1) # {'name': '小明', 'score': '76', 'gender': '男', 'study_id': '001'}
delattr(stu1, 'name')
print(stu1) # {'score': '76', 'gender': '男', 'study_id': '001'}
4.判断属性是否存在
- hasattr(对象, 属性名)
print(hasattr(stu1, 'name')) # False
print(hasattr(stu1, 'score')) # True
六、继承
1. 继承 - 让子类直接用拥有父类的属性和方法
- 父类就是一个大的类,子类是这个大的类下面的一个小的分类
2. 继承的语法
class 类名(父类):
类的说明文档
类的内容
- 注意:定义类的时候如果没有写父类,这个类默认继承object(基类)
- class Person: == class Person(object):
class A:
a = 100
def __init__(self):
self.b = 10
self.c = 20
def func1(self):
print('对象方法')
@classmethod
def func2(cls):
print('类方法')
@staticmethod
def func3():
print('静态方法')
class B(A):
pass
print(B.a) # 100
x = B()
print(x.b, x.c) # 10 ,20
x.func1() # 对象方法
B.func2() # 类方法
B.func3() # 静态方法
3.子类添加内容
- 子类在拥有父类的属性和方法的同时,往往需要由属于自己特有的一些属性和方法
a. 添加类属性和方法
直接在子类中定义新的类属性和新的方法
b. 添加对象属性
需要在子类的__init__方法中通过super()去调用父类的__init__方法来继承父类的对象属性
class C(A):
m = 11
def __init__(self):
super().__init__() # 调用当前类的父类的__init__()
self.name = '小明'
def func11(self):
print('C的对象方法')
@classmethod
def func22(cls):
print('C的类方法')
@staticmethod
def func33():
print('C的静态方法')
def func1(self):
print('C的对象方法2')
print(C.a, C.m) # 100 11
x = C()
print(x.name) # 小明
print(x.b, x.c) # 10 20
课后习题
-
定义一个狗类和一个人类:
狗拥有属性:姓名、性别和品种 拥有方法:叫唤
人类拥有属性:姓名、年龄、狗 拥有方法:遛狗
class Person:
def __init__(self, name, age, dog):
self.name = name
self.age = age
self.dog = dog
def skill(self):
return '遛狗'
people = Person('小明', 18, '拉布拉多')
print(people.name, people.age, people.dog, people.skill())
# 狗拥有属性:姓名、性别和品种
# 拥有方法:叫唤
class Dog:
def __init__(self, name, gender='公', variety='中华田园犬'):
self.name = name
self.gender = gender
self.variety = variety
def skill(self):
return '汪汪'
dog = Dog('二狗')
print(dog.name, dog.gender, dog.variety, dog.skill())
- 定义一个矩形类,拥有属性:长、宽 拥有方法:求周长、求面积
class Rect:
def __init__(self, length=0, width=0):
self.length = length
self.width = width
def area(self):
return (self.length + self.width) * 2
def perimeter(self):
return (self.length + self.width) * 2
def __repr__(self):
return f'长度:{self.length}, 宽度:{self.width}, 面积:{self.area()}, 周长:{self.perimeter()}'
rc = Rect(5, 5)
print(rc)
- 定义一个二维点类,拥有属性:x坐标、y坐标 拥有方法:求当前点到另外一个点的距离
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def distance(self, x2, y2):
return ((self.x - x2) ** 2 + (self.y - y2) ** 2) ** 0.5
x = Point(2, 4)
print(x.distance(7, 4))
- 定义一个圆类,拥有属性:半径、圆心 拥有方法:求圆的周长和面积、判断当前圆和另一个圆是否外切
class Circle():
pi = 3.14
def __init__(self, r, center: tuple, r1, center1: tuple):
self.r = r
self.center = center
self.r1 = r1
self.center1 = center1
def c(self):
return f'当前圆的周长为:{Circle.pi * self.r * 2}'
def area(self):
return f'当前圆的面积为:{self.r ** 2 * Circle.pi}'
def contact(self):
return ((self.center1[0] - self.center[0]) ** 2 + (
self.center1[-1] - self.center[-1]) ** 2) ** 0.5 == self.r1 + self.r
a = Circle(2, (1, 0), 1, (3, 0))
print(a.c(), a.area(), a.contact())
- 定义一个线段类,拥有属性:起点和终点, 拥有方法:获取线段的长度
class Segment:
def __init__(self, origin=0, termins=0):
self.origin = origin
self.termins = termins
def length(self):
return abs(self.termins - self.origin)
line1 = Segment(-7, -8)
print(line1.length())
- 写一个斗地主游戏类(根据生活经验添加类的内容)