第十四天python3 面向对象
1、面向对象
是对现实世界中的事物进行抽象的方式;
一切皆对象;
对象是数据和操作的封装;
对象之间相互独立,但也可以相互作用;
三要素:
封装:
数据与方法的集合;
提供一个或者多个接口来访问;隐藏数据,使用者不需要知道具体是怎么运作的;
继承:多继承,少修改,继承来的就不用自己写了;
多态:动态绑定;
2、类
类是一系列事物的统称,同类事物必定具有相同的特征;对应到类中是变量和方法;
定义类的语法格式: class Cat: pass
3、对象
对象是类的具体表现形式;是实际存在的个体;
#定义类 class Cat: print("Hello Word") #创建对象,也叫实例化对象 cat1=Cat()
4、成员变量
用于描述对象的固有状态或属性
class 类名: def __init__(self): self.变量名1 = 值1 self.变量名2 = 值2
5、成员方法
用于描述对象的固有行为;
class 类名: def __init__(self): self.变量名1 = "值1" self.变量名2 = "值2" def 方法名1(self): 方法体 def 方法名2(self): 方法体 调用方法格式: 对象名.方法名()
#######################################
class MyClass: """A example class""" x = 'abc' def foo(self): return 'My Class' #MyClass这个类调用共有属性 print(MyClass.x) abc #返回内存中函数对象的地址 print(MyClass.foo) <function MyClass.foo at 0x0000020F73459F70> #没有被实例化而调用foo方法,提示foo()需要一个参数 print(MyClass.foo()) Traceback (most recent call last): File "d:/Doc/test.py", line 7, in <module> print(MyClass.foo()) TypeError: foo() missing 1 required positional argument: 'self' #MyClass实例化后调用foo()方法;self指代当前实例本身,在这个示例中self表示的就是MyClass(); #可以这理解,当MyClass()实例调用foo()方法的时候,self=MyClass(),也就是foo(MyClass()) print(MyClass().foo()) My Class #__doc__也是类的属性 print(MyClass.__doc__) A example class #每实例化出一个对象,都可以和方法做绑定,也就是说多个对象可以绑定一个方法;他们在内存中的地址是不一样的; a = MyClass() print(MyClass().foo) print(a.foo) print(hex(id(a.foo))) <bound method MyClass.foo of <__main__.MyClass object at 0x000001C3E93A5C40>> <bound method MyClass.foo of <__main__.MyClass object at 0x000001C3E9376B50>> 0x1c3e8ed3100 #一个是通过实例访问,一个是通过类访问; print(a.foo) #MyClass类对象的内存地址 print(MyClass.foo) #函数对象的内存地址 <bound method MyClass.foo of <__main__.MyClass object at 0x00000246CBD86B50>> <function MyClass.foo at 0x00000246CBDC9F70>
#前后都有下划线的方法称为魔术方法,init可以理解为初始化方法,当构建一个实例的时候都会去执行这个方法 class Persion: def __init__(self,name): print(name) p = Persion() print(p) TypeError: __init__() missing 1 required positional argument: 'name' p1 = Persion('tom') print(p1) tom <__main__.Persion object at 0x000002152D9E5C40>
#############################
面向对象代码执行过程:
class Horse: nose="鼻子" eye="眼睛" def __init__(self,name,age): self.name = name self.age = age def showname(self): print('{} is {} 有 {} 有 {}'.format(self.name,self.age,self.nose,self.eye)) whitehorse = Horse('whitehorse',18) darkhorse = Horse('darkhorse',19) whitehorse.showname() darkhorse.showname() print(darkhorse.age) darkhorse.age += 1 print(darkhorse.age) ''' 执行结果: whitehorse is 18 有 鼻子 有 眼睛 darkhorse is 19 有 鼻子 有 眼睛 19 20 '''
1、首先在内存中定义一个Horse的类对象,在这个类对象中捆绑一个__init__的属性,生成一个归类对象Horse管理的函数;
2、对Horse这个类做实例化操作,创建两个实例,whitehorse和darkhorse;执行__init__函数,与创建的实例建立关系;
3、whitehorse/darkhorse再去调用showname方法,showname方法再调用实例变量和类变量打印结果;
实例化
baima = Horse('baima','18')
heima = Horse('heima','19')
实例化就是真正创建一个该类的对象,baima和heima就是Horse类的实例;每次实例化后获得的实例,都是不同的实例,即使使用同样的参数实例化,得到的也是不一样的对象;python类实例化后,会自动调用__init__方法;这个方法的第一个参数必须留给self,其他参数随意;
__init__方法
ClassName实际上调用的是__init__(self)方法,可以不定义,如果没有定义会在实例化后隐式调用;
作用:对实例进行初始化;
class ClassName:
def __init__(self):
print('init')
print(ClassName) #未调用__init__
print(ClassName()) #临时创建一个对象,调用__init__
a = ClassName() #创建一个对象,并赋值给a,调用__init__;
初始化函数可以有多个参数,但是第一个位置必须留给self,self指代当前实例本身;
init方法被调用的时候,实例就已经存在了;self.name=表示给实例添加了个属性(因为self是一个实例,所以.name是实例的属性;)
注意:__init__方法不能有返回值,只能是None;其实隐式的在init下面有个return None;
class ClassName: def __init__(self): print('1','init') return None #init方法不能有返回值,只能是None,隐式的在init方法内有一个return None,正常是可以不写的; print('2',ClassName) #只返回了一个类,并没有产生实例,所以不调用init; print('3',ClassName()) #实例化了一个类,所以调用了init,返回了结果; a = ClassName() #同样的道理,实例化了一个类,调用了init,返回了结果 ''' 执行结果: 2 <class '__main__.ClassName'> 1 init 3 <__main__.ClassName object at 0x0000020C4A8B6B50> 1 init '''
class ClassName: def __init__(self): return 1 print(ClassName()) ''' 执行结果: Traceback (most recent call last): File "d:/Doc/test.py", line 13, in <module> print(ClassName()) TypeError: __init__() should return None, not 'int' 进一步证明了在init方法中不能有返回值; '''
self
class MyClass: def __init__(self): print('self in init = {}'.format(id(self))) c = MyClass() #会调用__init__ print("c = {}".format(id(c))) ''' 打印结果: self in init = 1653473318728 c = 1653473318728 在真正调用init的时候,其实实例就已经存在了,所以id(self)能取到值;所以前后两个的id值是一样的;进一步说明了self指代的是实例本身; '''
实例对象instance
类实例化后一定会获得一个对象,就是实例对象;
Horse是定义一个类,Horse()创建一个实例,并实例化,baima=Horse()将实例化的值赋给白马,baima就是Horse类的实例对象;
__init__方法的第一个参数self就是指代某一个实例,这个self就是上述例子中的baima,python会把方法的调用者作为第一参数self的实参传入;
类实例化后,得到一个实例对象,实例对象会绑定方法,调用方法时采用baima.showname()的方式;
self.name就是baima对象的name,name是保存在了baima对象上,而不是Horse类上,所以称为实例变量;
实例变量和类变量
实例变量是每一个实例自己的变量,是自己独有的;类变量是类的变量,是类的所有实例共享的属性和方法;
特殊属性 含义
__name__ 对象名
__class__ 对象的类型
__dict__ 对象的属性的字典
__qualname__ 类的限定名
注意:python中每一种对象都拥有不同的属性;函数、类都是对象,类的实例也是对象;
class Person: age = 5 def __init__(self,name): self.name = name #self.age = age def showage(self): print('{} is {}'.format(self.name,self.age)) t = Person('tom') t.showage() #age属于类变量,当实例没有age属性的时候就问类去要; print(Person.age) ##age属于类变量 Person.age = 30 #为类变量重新赋值 print(t.age) #原则是一样的,当实例没有的时候问类要; t.showage() ''' 执行结果: tom is 5 5 30 tom is 30 '''
class Person: """hello""" age = 5 def __init__(self,name:str): #init方法一旦被调用,则实例已经存在了; self.name = name #给实例添加属性,因为目前self代表的是一个实例;则这是实例的属性;而不是类的属性; self.age = 18 def showage(self): pass print(1,sorted(Person.__dict__.items())) tom = Person('tom') print(2,tom.__class__) print(3,sorted(tom.__dict__.items())) print(3.1,tom.__dict__) print(4,sorted(tom.__class__.__dict__.items())) print(5,Person('jerry').__dict__) print(6,tom.age) print(7,tom.__class__.age) print(8,type(tom).age) print(9,Person.age)
######
print(Person.__class__) #类类型的对象
print(Person.__class__.__name__) #类类型的名称
print(Person('jerry').__class__) #问这个实例的类是谁
print(Person('jerry').__class__.__name__) #这个实例的类的名字是什么
# 执行结果 PS D:\Doc> & D:/Python/Python38/python.exe d:/Doc/test.py 1 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', 'hello'), ('__init__', <function Person.__init__ at 0x00000243FDE79F70>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 5), ('showage', <function Person.showage at 0x00000243FDE8A040>)] 2 <class '__main__.Person'> 3 [('age', 18), ('name', 'tom')] 3.1 {'name': 'tom', 'age': 18} 4 [('__dict__', <attribute '__dict__' of 'Person' objects>), ('__doc__', 'hello'), ('__init__', <function Person.__init__ at 0x00000243FDE79F70>), ('__module__', '__main__'), ('__weakref__', <attribute '__weakref__' of 'Person' objects>), ('age', 5), ('showage', <function Person.showage at 0x00000243FDE8A040>)] 5 {'name': 'jerry', 'age': 18} 6 18 7 5 8 5 9 5
上例中,可以看到类属性保存在类的__dict__中,实例属性保存在实例的__dict__中,如果从实例访问类的属性,就需要借助__class__找到所属的类;
实例属性的查找顺序
指的是实例使用"."来访问属性,会先找自己的__dict__,如果没有,然后通过属性__class__找到自己的类,再去类的__dict__中找;
注意,如果实例使用__dict__[变量名]访问变量,将不会按照上面的查找顺序找变量了,这是指明使用字典的key查找,不是属性查找;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!