类与对象
一、什么是类、对象
1. 什么是对象:对象(实例),万物皆对象,对象是具有属性和行为的。
举例:桌子,椅子,你,你同桌,小猫,小狗。。
属性:桌子:颜色、四个腿、有没有桌洞。。。名词
行为:猫:叫,吃饭,睡觉,打豆豆 动词
2. 什么是类
一个类别,按照某种需求划分的类别。
具有相同的属性和行为的对象,构成一个整体----类
分类规则:按照需求,不是所有的分类都是一个样子
举例:学生管理系统,学生,老师
公交卡系统,学生和老师?是一个分类 人和公交车,票,站台
3. 类和对象之间的关系
类是对象的抽象,对象是类的具体实现。
类:看成是模板,蓝图,设计图纸
对象:看成设计出来实际的实例
举例,生产汽车,Car 类(属性:颜色、牌子、尺寸、座椅)
(行为:运动档。。。)
奥迪--Car(颜色=黑色,牌子=奥迪,尺寸=2米,座椅=真皮)
(行为:运动档,自动)
总结:一个对象至少有类的属性和行为,才能称为是这个类的对象。
学生管理系统:定义一个python讲师,Student产生对象?Teacher产生对象?
二、 类的定义和初始化
1. 类的定义
格式:class 类名
'注释':不是必须的,开发好习惯
类体
类名:习惯是首字母大写
"""
# 定义一个人的类
# class Person:
# '这是一个人的类'
# pass
# 可以使用类产生(创建)对象
# 语法 对象名=类名()--------本质上就是在调用类里面的创建对象的函数
# p1=Person()
# print(p1)
# print(p1.__doc__)
2. 定义属性和方法
# 属性:以变量赋值的方式存在
# 行为:以方法(函数)的形式存在
(1). 动态的属性和方法(都是给对象的)
# 属性:动态属性,就是简单的变量赋值,如果当前的对象已经有这个属性了,
# 那么会覆盖(其实只是变量绑定修改了,不是真正删除了),如果没有,则会新建
# 对象名.属性名
# p1.name="张三"
# print(p1.name)
# p1.name="张三丰"
# print(p1.name)
# 动态定义属性,缺点:只对于某一个对象有作用,对于其他对象是不起作用的
# p2=Person()
# print(p2.name)
# 行为:在类的外面定义函数
def run(self):
print("我在跑步")
# self 代表 参数代表当前对象自己,run方法属于哪一个对象,self就是那个对象
# 给某一个类定义行为的时候,必须要self方法,
# 在类的外面调用的时候,必须传入self
# 在类的里面调用,则不用传入
# 把行为给一个对象:对象名.行为名=函数名
# p1.run=run
# 调用,对象.行为(对象)
# p1.run(p1)
# p2=Person()
# p2.run=run
# p2.run(p2)
# 动态的属性和方法的局限:每一个对象都有单独被赋予属性和方法才可以使用
(2) 在类中定义属性和方法(必须掌握)
# 方法:是定义在类里面
# 给类定义行为(函数),必须有self这个参数。
# class Person:
# def run(self):
# print("我在跑步")
# # 希望调用类下面的实例方法(行为),必须先有对象
# p1=Person()
# p1.run() # 在类下面定义行为的时候,调用时,不需要显式的传入self参数
#
# p2=Person()
# p2.run()
# 定义属性
# 类里面,对象的初始化方法 __init__:在创建对象时,自动调用的方法
# init 方法每创建一次,都会执行一次
# class Person:
# def run(self):
# print("我在跑步")
# def __init__(self):
# self.name="张三"
# self.age=20
# print("在执行__init__方法")
# p1=Person()
# print(p1.name)
# print(p1.age)
#
# p2=Person()
# print(p2.name)
# print(p2.age)
# 解决不是所有的对象的name都一样的问题
class Person:
# 在自定义的方法中也可以获得对象的属性
def run(self,place):
print("我{}{}在{}跑步".format(self.name,self.age,place))
def __init__(self,name,age):
self.name=name
self.age=age
print("在执行__init__方法")
p1=Person("张三",20)
print(p1.name)
print(p1.age)
p1.run("操场")
p2=Person("李四",40)
print(p2.name)
print(p2.age)
p2.run("公园")
"""
1.创建一个"狗"的类
2.定义对象的共有属性 name age type(类型)
3.定义对象的共有行为:
叫,可以获得狗的名字
吃饭,可以传入狗粮的牌子
睡觉
4.定义对象的特殊属性(不是所有对象共有),对产生的某一个对象定义出生地
"""
class Dog:
'这是一个狗狗的分类'
def __init__(self,name,age,type):
self.name=name
self.age=age
self.type=type
print('{} {}岁 品种:{}'.format(self.name,self.age,self.type))
def rowl(self):
print("{}在叫".format(self.name))
def eat(self,brand):
print("{}在吃{}牌子的狗粮".format(self.name,brand))
def sleep(self):
print("{}在睡觉".format(self.name))
d1=Dog("大黄",3,"狼狗")
d1.rowl()
d1.eat("单身")
d1.sleep()
d1.place="火星"
print("{}出生在{}".format(d1.name,d1.place))
print("
-------------------
")
d2=Dog("sanmo",2,"阿拉斯加")
d2.rowl()
d2.eat("NexGard")
d2.sleep()
d2.place="阿拉斯加"
print("{}出生在{}".format(d2.name,d2.place))
三、类的成员
"""
类属性,类方法
实例属性,实例方法
静态方法
"""
1. 类属性和 实例属性
# 实例属性:跟对象相关,对象属性
# 类属性:跟类关联,不属于任何一个对象、类属性直接定义在类体(变量赋值的形式)
"""
分析类属性和实例属性的不同
(1) 属性的绑定不同
类属性:绑定跟当前的类相关,产生的任何一个对象都跟类属性没有任何关系
所有的对象都可以访问这个属性,公用的,共享
实例属性:跟每一个对象都有关系的属性
每一个对象独有,不共享
(2) 访问方式不同
类属性:访问方式有两种,一种是可以通过类名访问:类名.类属性(可读可写)
另外一种,可以对象.类属性访问(只能访问,不能修改)
实例属性:对象(实例).属性,会通过实例访问。不能通过类去访问
"""
class Person:
# 类属性
desc="人的描述"
def __init__(self,name):
# 实例(对象)属性
self.name=name
# 访问实例属性
# p1=Person("张三")
# print(p1.name)
# p2=Person("李四")
# 访问类属性
# 第一种方式,通过类访问,可以访问和修改
# print(Person.desc)
# Person.desc="=人的描述_new"
# print(Person.desc)
# 第二种方式,通过对象访问,不能修改
# print(p1.desc)
# print(p2.desc)
# p2.desc="人的描述_new_new"
# print(p2.desc) # 使用对象.类属性的形式修改类属性,其实不是修改,而是新建了一个属性
# print(Person.desc)
# 类属性的应用:定义所有对象共有的属性
# 建议访问类属性,只使用【类.类属性】
# 练习:注意实例属性属于每一个对象。跟类没关系
# p3=Person("王五")
# p4=Person("赵六")
# p3.name="王五五"
# print(p3.name)
# print(p4.name)
2. 类方法和实例方法
# (1) 实例方法:跟具体的每一个对象关联的方法。
# 类方法:跟类相关联的方法,跟每一个对象没有关系
# (2) 类方法的定义:在类里面写方法,加标记(装饰器)@classmethod修饰
# (3) 访问方式
# 类方法:两种形式
# 类名.类方法(建议方式)
# 对象.类方法
# 实例方法:
# 对象.实例方法
# 类.实例方法
class Person:
desc="人的描述"
def __init__(self,name):
self.name=name
def run(self):
print("跑步")
@classmethod
def cm(cls):
# cls指当前类
print("类方法")
print(cls is Person) # 证明是不是当前类
@classmethod
def copy(cls,p):
return cls(p.name)
# 应编码
# return Person("张三")
# Person.cm()
# p1=Person("张三")
# p1.cm()
# p2=Person.copy(p1)
# print("p2的name",p2.name)
# Person.run(p1) # 通过类也能访问到实例方法,但是不建议
# 类方法的应用:复制对象,通过一个已有对象,返回跟当前对象一样的一个新对象
3. 类方法和实例方法中对实例属性和类属性进行访问
# (1) 实例方法调用实例属性
class Person:
def __init__(self,name):
self.name=name
def walk(self):
print(self.name+"正在走路")
p1=Person("张三")
p1.walk()
p2=Person("李四")
p2.walk()
# (2) 类方法调用类属性
class Person:
desc="人的描述"
@classmethod
def cm(cls):
cls.desc="人的描述_new"
print(Person.desc)
Person.cm()
print(Person.desc)
# (3) 实例方法调用类属性
class Person:
desc="人的描述"
def walk(self):
# 使用self对象,只能对类属性进行访问,不能修改
print(self.desc)
# __class__ 获得当前对象所属的类,可以通过他访问属性,修改类属性
print(self.__class__.desc)
self.__class__.desc="人的描述_new"
print(self.__class__.desc)
print(self.desc)
print("正在走路")
p=Person()
p.walk()
# (4) 类方法调用实例属性
# 一般来说不这么用
class Person:
def __init__(self,name):
self.name=name
@classmethod
def cm(cls,p):
print(p.name)
p=Person("张三")
Person.cm(p)
4. 静态方法
# 在类中定义的方法:静态方法跟类没关系,跟实例更没关系,一般用来给类服务。
# 调用的时候,使用类调用
# 用法
"""
@staticmethod
def 静态方法的名字:
方法体
"""
class Person():
def __init__(self,name):
self.name=name
@staticmethod
def s_m():
print("这是静态方法")
@staticmethod
def makeFriend(p1,p2):
print("{}和{}交朋友".format(p1.name,p2.name))
# 访问:建议使用【类.静态方法】
Person.s_m()
p=Person()
p.s_m()
# 静态方法的应用:实现两个对象之间的关系。
p1=Person("张三")
p2=Person("李四")
Person.makeFriend(p1,p2)
"""
类和实例的选择
类属性、类方法、静态方法
实例属性、实例方法
【类属性、实例属性的选择】
属性是所有对象共享的,还是单对象独享,如果是共享,就应该定义成类属性,如果是独享的,就应该定义成实例属性
【实例方法、类方法、静态方法的选择】
方法的目的:为了对类中属性进行操作
当定义的方法是对实例或者实例的属性进行操作的,那么应该定义成实例方法
如果定义的方法操作的是类属性,应该定义成类方法
如果定义的方法跟对象没多大关系,跟类也没多大关系,完全可以拿到类的外面,只是为了类服务的,定义成静态方法
"""
四、魔法方法
# 在python中定义的特殊的方法,格式__xx__ 命名规则
# 魔法方法不需要主动调用,也不需要显示的调用,当符合一定条件的时候,自动调用
1. __new__(cls):
# 类方法,在创建对象的时候,自动执行,是真正的创建对象的方法
# new是类方法,但是定义的时候不需要使用classmethod修饰
class Person():
def __new__(cls):
print("new 方法")
# 在创建的 任何一个类里面,已经继承了object类
return super().__new__()
# def __init__(self):
# print("init 方法")
# p=Person("aa",20)
# print(p)
2. __init__(self),在new方法后面,对创建的对象进行初始化
# 对对象的属性进行初始化
# 在new方法中如果有return才会执行init,如果没有return则不会执行init
3. __del__(self),当对象销毁的时候,会自动调用的方法
class Person:
def __new__(cls):
print("new 方法")
# 在创建的 任何一个类里面,已经继承了object类
return super().__new__()
def __init__(self):
print("init 方法")
def __del__(self):
print("执行del方法")
p=Person()
# # 如果在删除对象之前,给对象赋予新的变量,del不能删除当前对象
# p2=p
# print("删除p之前")
# del p
# print("删除p之后")
4. __str__(self):实例方法 相当于调用内建函数中的str 或者format,print时候,会自动把对象转换成字符串
class Person:
def __new__(cls):
print("new 方法")
return super().__new__()
def __init__(self,name,age):
self.name=name
self.age=age
print("init 方法")
def __del__(self):
print("执行del方法")
def __str__(self):
s="属性:name={};age={}".format(self.name,self.age)
return s
def __repr__(self):
return "<Person class>"
def __bytes__(self):
return b"byte person class"
p=Person("张三",20)
print(p)
print(str(p))
print(repr(p))
5.__repr__(self):实例方法,返回str类型的对象,repr是对解释器友好,str是对人友好
# 当程序中 没有定义str方法,却调用了str方法,python会去找repr
6. __bytes__(self):相当于调用bytes方法,返回字节类型,以字节类型描述对象
print(bytes(p))
7. __call__(self):可以把对象当成函数一样调用
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
print("init 方法")
def __call__(self):
print("call 方法")
p=Person("张三",20)
p()
五、 动态属性的操作
1. hasattr(obj,name):判断obj对象中是否存在name属性,返回True,False
class Person:
pass
p=Person()
p.name="张三"
print(hasattr(p,"name"))
print(hasattr(p,"age"))
2.setattr(obj,name,value)设置属性的值
setattr(p,"age",20)
print(p.age)
3.getattr(obj,name,default)返回属性的值
print(getattr(p,"age"))
print(getattr(p,"age1",5))
# 删除
delattr(p,"age")
# 动态设置属性的操作是3个内置方法,主要用来动态的给对象进行赋值
p.gender="男"
print(p.gender)
# 通过键盘输入,设置属性名和属性值
aname=input("输入属性名")
avalue=input("输入属性值")
setattr(p,aname,avalue)
print(getattr(p,aname))