1、手机是对象还是类?
2、苹果手机,是对象还是类?
3、iPhonex 手机是对象还是类?
4、我手里的苹果手机,是对象还是类?
# 定义一个类:
'''
格式:
# 经典类
class 类名:
# 新式类
class 类名(父类名):
'''
# 经典类
# 不由任何类派生,或者说不继承任何类
class student:
pass # 为了保证代码结构完整,在类下边必须书写表达式,如果没有使用pass占位
# 新式类
# 括号内就是我们的父类,也就是存在一定的继承关系
# 有些地方称其为object的派生类
class teacher(object):
# pass
... # 为了保障代码结构完整,也可以使用...来进行占位
# 类的实例化又称为创建对象
# 定义一个类
class Student(object):
# 定义方法.定义方式和函数定义类似
def study(self):
print('我在听直播课,贼有意思,就是学习非常不努力我也能听懂')
def eat(self):
print('我在吃脑白金,补补脑子继续学习')
# 类的实例化(创建对象)
# 格式: 类名()
s1 = Student()
# 我们可以直接打印对象,得到的是其所对应的类和所在的内存地址
print(s1) # <__main__.Student object at 0x7f9be20848e0>
# 也可以打印对象的类型,其实就是我们创建对象所使用的类
print(type(s1)) # <class '__main__.Student'>
# 实例可以调用实例方法
s1.study()
s1.eat()
# 理论上类可以创建无数个实例对象
s2 = Student()
print(s2)
# 类名的定义要使用大驼峰命名法
# 类名严格区分大小写,类名遵循标识符的命名规则
# class ChineseStudent():
# pass
#
# s3 = Student()
# s4 = student()
# s3.eat()
# s4.eat()
# 在类的内部定义方法的时候,自动传入一个self
# 在调用实例方法时,不需要对self 进行传值
# self到底是什么?有什么用?
class Student(object):
def study(self):
# 由于s1和self指向同一块内存空间,所以其必为同一个对象
# 也就是说在对象调用方法时会将对象本身传入方法内部进行使用
print(self) # <__main__.Student object at 0x7fa2654848e0>
print('我要学习了,谁也不要打扰我,我知道你们为了超过我不择手段,但是没有用')
def eat(self):
# self 有什么作用呢?
# 可以在方法内部调用实例所拥有的属性或者方法
print('我要吃饭了吃完就学习')
self.study()
# 实例化对象
s1 = Student()
print(s1) # <__main__.Student object at 0x7fa2654848e0>
s1.study()
s1.eat()
# 我们为什么要讲对象传入进去呢?
# 方法时定义在类的内部的,所有的对象共有一个类,所以我们再调用方法的时候,需要传入我们调用方法所使用的类
# s2 调用study方法时所指向的空间和s1无关所以两个对象指向不同的内存空间,修改一个,另一个不发生变化
s2 = Student()
s2.study()
super().方法名()
类名.方法名(self)
spuer(要从哪一个类的上一级类开始查找, self).方法名()
子类调用父类方法时,一般都是想对父类方法进行扩展
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def driver(self):
print('开车太好玩了 ,10迈,太快了')
class Father(Person):
# 如果我们现在想在原有父类方法基础上扩展,例如我们现在需要重写一个init方法
# 可以接收 name, age ,gender三个属性
def __init__(self, name, age, gender):
# 在父类方法中已经添加了name,和age我们可不可以直接使用呢???
super().__init__(name, age)
# 在父类方法的基础上我们在添加一个子类方法独有的功能
self.gender = gender
def driver(self):
print('我要去天安门完,开挖掘机不让我进')
def __str__(self):
return f'我的姓名是{self.name},我的年龄是{self.age},我的性别是{self.gender}'
class Son(Father):
def driver(self):
# 调用Person中的dirver
# TypeError: driver() missing 1 required positional argument: 'self'
# Person.driver()
Person.driver(self)
# 从Father类的上一级类开始查找方法,并进行调用
super(Father,self).driver()
# 调用Father中的dirver
super().driver()
# 格式:super(从哪个类的上一级开始查找,self).方法名()
# 如果类名是当前类,可以省略括号内的内容
super(Son, self).driver()
# 书写特有功能
# 所有的参数都传递到了Father类中,并且添加为当前对象的属性
print(Father('Jack', 28, '男'))
s1 =Son('xiaoming', 12, '男')
s1.driver()
# 子类中调用父类方法的三种方式:
# super().方法名() # 只能调用当前类的上一级类中的方法或函数
# 类名.方法名(self) # 所使用的类名,必须在当前类的继承关系中 这种方法可以调用不在类中的类方法,但是不能使用self作为对象出现
# super(要从哪一个类的上级类开始查询,self).方法名() # 类名必须在继承关系内,如果类名是当前所在的类,则可以将括号内内容省略,就是第一中方式
class Person(object):
def driver(self):
print('开车太好玩了 ,10迈,太快了')
class Father(Person):
def driver(self):
print('我要去天安门完,开挖掘机不让我进')
class Mother(Person):
def driver(self):
print('我会开小汽车,嘟嘟嘟')
class Son(Father):
def driver(self):
print('我会骑自行车,真好玩')
def go_shopping(Driver):
Driver.driver()
print('很快就到超市了,真好呀')
class Monkey(object):
def driver(self):
print('我在骑自行车')
# 在我调用go_shopping时,可以将什么对象传进来???
p1 = Person()
f1 = Father()
s1 = Son()
m1 = Mother()
# 多态: 在继承链条中,无论是多级继承还是多继承,不同的类同种方法会进行重写,重写后在函数或者方法中传入不同的子类创建的对象,调用相同方法所展示的效果完全不同
go_shopping(p1)
go_shopping(f1)
go_shopping(s1)
go_shopping(m1)
# 如果创建一个Monkey对象,能否传入go_shopping并正确执行???
# 如果一个没有继承关系的类,也存在指定方法,也可以进行对象的传递,并在方法或函数内部使用,但是逻辑会有偏差,这种语法没有问题,但是逻辑上有严重偏差的方式叫做"鸭子类型"(扩展,不要求掌握)
# monkey1 = Monkey()
# go_shopping(monkey1)
# 类属性 ,有些地方也叫类变量 就是在类中创建的属于所有对象的属性
class Chinese(object):
# 类属性是所有对象所共有的
color = 'yellow'
def __init__(self, name):
self.name = name
c1 = Chinese('xiaohong')
c2 = Chinese('xiaohuang')
c3 = Chinese('xiaolv')
# 上述三个对象拥有的实例属性是什么??? name
# 他们每个人的实例属性相同么???之间有联系么??? 不相同,每个对象间的实例属性互不相关
# 但是三个对象的类属性是完全相同的
print(c1.color)
print(c2.color)
print(c3.color)
# 类属性的获取方式
# 格式1:对象名.类属性名 在实例属性中,不能有与类属性同名的属性,否则类属性不能通过这种方式提取
# 格式2:类名.类属性名 (推荐)
# 修改类属性
# 格式:类名.类属性名 = 值
Chinese.color = 'orange'
# 注意:修改类属性不能使用 对象名.属性名 = 值 这种方式会添加一个实例属性
print(c1.color)
print(c2.color)
print(c3.color)
# 类属性使用场景:
# 可以进行计数
# 可以控制或者包含多个对象
class Apple(object):
apple_list = []
def __init__(self):
Apple.apple_list.append(self)
count = 10
def eat(self):
Apple.count -= 1
a1 = Apple()
a2 = Apple()
a3 = Apple()
a4 = Apple()
a1.eat()
a2.eat()
a3.eat()
a4.eat()
print(Apple.count)
print(Apple.apple_list)
class Apple(object):
num = 10
def __init__(self):
self.eat_num = 0
def eat(self):
# 每次吃苹果,当前的食用数量加1
self.eat_num += 1
# 每次吃苹果,让苹果总数 -1
Apple.num -= 1
# 当方法中不适用实例属性和实例方法,只会使用到类属性和类方法的时候我们就选择类方法
# 因为类方法,不需要创建实例去进行调用,可以直接使用类名调用
@classmethod
def eat_apple_num(cls):
# 在类方法中传入的cls即为当前类的类名
print(f'一共被吃了{10-cls.num}个,还剩{cls.num}个')
# 类方法的调用
# 格式: 类名.类方法名
Apple.eat_apple_num()
# 创建对象
a1 = Apple()
a2 = Apple()
a3 = Apple()
a4 = Apple()
# 吃苹果
a1.eat()
a2.eat()
a3.eat()
a4.eat()
a4.eat()
# 调用类方法
Apple.eat_apple_num()
# 查看每人吃了几个苹果
print(a1.eat_num)
print(a2.eat_num)
print(a3.eat_num)
print(a4.eat_num)
# 类方法可以使用对象调用么?
# a1.eat_apple_num() 不推荐这样使用
class Person(object):
# 在静态方法中,不会传入self, 也不会传入cls 所以在我们使用静态方法时,最好再静态方法中不要使用类或对象的属性或者方法
# @classmethod 类方法修饰
@staticmethod
def func():
print('我是一个静态方法')
# def func():
# print('我是一个静态方法')
# 一般能够定义为函数的内容,都可以改写为静态方法,理论静态方法不依赖与类和对象,但是为了更好的封装,我们会将其写到类中
Person.func()
# 静态方法就是一个普通函数,放到类内部就是为了封装,方便我们去继承和导入模块
# 需求: 进行游戏
# 1/显示游戏信息
# 2/展示历史最高分
# 3/开始游戏
class Game(object):
top_score = 100
def __init__(self, name):
self.name = name
# 定义一个静态方法,与类和实例都没有关系
@staticmethod
def print_game_info():
print('游戏信息展示')
# 定义类方法,内部可以调用类属性和类方法,依赖于类
@classmethod
def show_top_score(cls):
print(f'历史最高分数为{cls.top_score}')
# 定义了一个实例方法,内部可以调用实例属性和实例方法,依赖于实例
def start_game(self):
print(f'{self.name}开始游戏')
Game.print_game_info()
Game.show_top_score()
# 实例方法必须使用实例进行调用
g1 = Game('xiaoming')
g1.start_game()