面向对象编程
面向对象编程 OOP(object oriented programming)
面向对象编程
面向过程(按照指定函数进行调用)
面向对象包括:类和对象
类:类是比函数更高级的一种代码组织形式,类是一个抽象的概念,是虚拟化出来的概念。
什么是类:
具有相同或相似性质的对象的抽象就是类。 类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。 类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。
对象:属性 + 方法
属性:属性是方法的信息,比如:颜色,形态,品牌等
方法:方法是对象能做的活动,比如会行走,会唱歌等。
一个对象就是一个独立空间
初始化和实例化
实例化:创建类的实例对象的过程 初始化:创建对象过程中完成属性赋值操作
实例对象.变量
搜索顺序:先在实例对象空间搜索,找不到再去创建类中找。
类
类 class:默认主类需要加上object 对象:
类的命名规则
1.驼峰式命名法,大驼峰 小驼峰
定义类的三个名词
类名 属性:常用变量来定义 方法:常用函数来定义 self:代表调用者本身,
类
1.类的成员 2.类的成员-变量 3.类的成员-方法 4.类的成员-属性 5.私有
类的成员
首先 什么是类的成员,你能在类中写什么?写的内容就是成员。
class 类名: #属性 def __init__(self,参数1,参数2...) #属性变量 self.属性1 = 参数1 self.属性2 = 参数2 ... #方法 def method(self): pass
#在__init__和method都是属于类的成员方法,又称为实例方法,总之这样的东西需要用对象来访问,而上方的
self.属性1 = 参数1 这个代码的含义是给对象设置属性信息,含义是这个对象的XXX属性是xxx这个东西又被称之为成员变量或者实例变量,再或者被称之为字段,都是一个意思。
也就是说在类中,是存在这实例变量和实例方法的
//self 代表调用者本身 带self的方法叫实例方法
__init__ 初始化方法
__init__ 初始化方法,做属性初始化
实例对象调用实例方法:解释器将实例对象作为第一个实参传入给实例方法。
类的成员-变量
在类中变量分为两大类:
1.实例变量(字段)
2.类变量(静态变量)
实例变量:每个实例都应该拥有的变量,比如,人的名字,人的爱好,都是属于实例变量。
类变量:就是这一类事物统一拥有的变量。
class Person: #类变量,表示所有的该类对象都共享这个变量。 country = "中国" def __init__(self,name,num,birthday): #实例变量(字段),表示创建的每一个人都有着三个变量 self.name = name self.num = num self.birthday = birthday p1 = Person("li",18,"2020-10-24") print(p1.name) #li print(p1.num ) #18 print(p1.birthday) #2020-10-24 print(p1.country) #中国 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.num ) #22 print(p2.birthday) #2020-10-24 print(p2.country) #中国
发现对象p1和p2的name都是对象自己的,但是country是类的,大家公用同一个变量,
验证
Person.country = "唐朝" #这这里 把中国换为了唐朝 p1 = Person("li",18,"2020-10-24") print(p1.name) #li print(p1.num ) #18 print(p1.birthday) #2020-10-24 print(p1.country) #唐朝 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.num ) #22 print(p2.birthday) #2020-10-24 print(p2.country) #唐朝
把类中的值修改了,输出的内容也就跟着修改了。
通过图发现,实例变量中都隐含着一个创建这个对象的类,通过这个类就能找到我们类中定义的全部内容,包括方法和属性信息等等。
一个坑
p1 = Person("li",18,"2020-10-24") p1.country = "大清" print(p1.name) #li print(p1.country) #大清 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.country) #中国
//上面是大清,下面是中国,在执行p1.country = “大清”的时候,其实并没有去改变类中的country,而是给对象添加了一个实例变量,并且这个实例变量,只有当前的p1是存在的,在p2是不存在的
p1只是添加了一个实例变量,并没有修改类的变量,通过这里,我们应该能发现,类变量,最好是用类名来访问,当然,我们通过对象名也可以访问,但只能看,不能修改它,想要修改它,需要用类名来修改它。
案例。通过程序来记录当前类被创建了多少个对象
class Foo: count = 0 def __init__(self): Foo.count += 1 print(Foo.count) #0 Foo() Foo() Foo() print(Foo.count) #3
总结
实例变量是给对象用的。
类变量,多个对象共享,最好是用类名来访问,这样更规范
类的成员-方法
类对象,类属性
飞机实例化的程序 面向对象编程
#类名 class MaKe_Plane(object): #属性 color = "red" wheerNum = 3 #方法 def move(self): print("起飞了") #创建对象 myplane = MaKe_Plane() #输出方法 myplane.move() #输出属性 print(myplane.color)
//增加变量调用 #类名 class MaKe_Plane(object): #属性 color = "red" wheerNum = 3 #方法 def move(self): print("起飞了") def getplaneInfo(self): print("轮胎数%d,染色%s" %(myplane.wheerNum,myplane.color)) #创建对象 myplane = MaKe_Plane() #输出方法 #myplane.move() myplane.getplaneInfo()
//在对象中修改属性 #类名 class MaKe_Plane(object): #属性 color = "red" wheerNum = 3 #方法 def move(self): print("起飞了") def getplaneInfo(self): print("轮胎数%d,染色%s" %(myplane.wheerNum,myplane.color)) #创建对象 myplane = MaKe_Plane() #输出方法 myplane.color = "blue" myplane.getplaneInfo()
//两个实例,并修改属性 #类名 class MaKe_Plane(object): #属性 color = "red" wheerNum = 3 #方法 def move(self): print("起飞了") def getplaneInfo(self): print("轮胎数%d,染色%s" %(self.wheerNum,self.color)) #创建对象 myplane = MaKe_Plane() #输出方法 myplane.color = "blue" myplane.getplaneInfo() #输出属性 #print(myplane.color) #实例化对象 yourplane = MaKe_Plane() yourplane.color = "green" yourplane.getplaneInfo()
//通过变量传递属性 __init__() #类名 class MaKe_Plane(object): #方法(通过变量方式创建属性) def __init__ (self,COLOR,WHEERNUM): self.color = COLOR self.wheerNum = WHEERNUM def move(self): print("起飞了") def getplaneInfo(self): print("轮胎数%d,染色%s" %(self.wheerNum,self.color)) #创建对象 myplane = MaKe_Plane("red",4) myplane.getplaneInfo() yourplane = MaKe_Plane("blue",10) yourplane.getplaneInfo()
面向对象是什么?
面向对象编程是在面向过程编程的基础上发展来的,它比面向过程编程具有更强的灵活性和扩展性。面向对象编程是程序员发展的分水岭,很多初学者会因无法理解面向对象而放弃学习编程。
面向对象编程(Object-oriented Programming,简称 OOP),是一种封装代码的方法。其实,在前面章节的学习中,我们已经接触了封装,比如说,将数据放进列表和字典中中,这就是一种简单的封装,是数据层面的封装;把常用的代码块打包成一个函数,这也是一种封装,是语句层面的封装。
代码封装,其实就是隐藏实现功能的具体代码,仅留给用户使用的接口,就好像使用计算机,用户只需要使用键盘、鼠标就可以实现一些功能,而根本不需要知道其内部是如何工作的。
本节所讲的面向对象编程,也是一种封装的思想,不过显然比以上两种封装更先进,它可以更好地模拟真实世界里的事物(将其视为对象),并把描述特征的数据和代码块(函数)封装到一起。
面向对象包括:类和对象
类介绍
什么是类:
具有相同或相似性质的对象的抽象就是类。 类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。 类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。
类:类是比函数更高级的一种代码组织形式,类是一个抽象的概念,是虚拟化出来的概念。
类 class:默认主类需要加上object 对象:
类的命名规则
1.驼峰式命名法,大驼峰 小驼峰
定义类的三个名词
类名 属性:常用变量来定义 方法:常用函数来定义 self:代表调用者本身,
类包括:
1.类的成员 2.类的成员-变量 3.类的成员-方法 4.类的成员-属性 5.私有
对象介绍
对象:属性 + 方法
属性:属性是方法的信息,比如:颜色,形态,品牌等
方法:方法是对象能做的活动,比如会行走,会唱歌等。
对象同时具有属性与方法两项特性
对象的属性与方法通常被封装到一起,用属性与方法来共同体现事物的特性,二者相辅相成
一个对象就是一个独立空间
初始化和实例化
实例化:创建类的实例对象的过程 初始化:创建对象过程中完成属性赋值操作
调用方法:实例对象.变量
搜索顺序:先在实例对象空间搜索,找不到再去创建类中找。
2.1 对象在代码中的体现
在分析现实生活中的事物时发现,这些事物都有其具体的特点和功能,这些特点和功能就组成了这个特殊的事物 我们来描述一辆小汽车: 分析: 事物的特点(属性): 颜色 品牌 事物的功能: 高速运行 发现:事物其实就是由特点(属性)和行为(功能)组成的。 可以简单的理解:属性就是数据,由变量存储;行为就是功能,就是方法。 小汽车类 颜色 品牌 def 高速运行(): pass 在python语言中定义的类语法: class 类名: # 声明一个类 注意,如果由单词构成类名,建议大驼峰命名。 ''' 解释文档 ''' 类变量 def 实例方法(self,*args,**kwargs): pass
2.2 实例对象
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Person类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
类的成员
首先 什么是类的成员,你能在类中写什么?写的内容就是成员。
class 类名: #属性 def __init__(self,参数1,参数2...) #属性变量 self.属性1 = 参数1 self.属性2 = 参数2 ... #方法 def method(self): pass
#在__init__和method都是属于类的成员方法,又称为实例方法,总之这样的东西需要用对象来访问,而上方的
self.属性1 = 参数1 这个代码的含义是给对象设置属性信息,含义是这个对象的XXX属性是xxx这个东西又被称之为成员变量或者实例变量,再或者被称之为字段,都是一个意思。
也就是说在类中,是存在这实例变量和实例方法的
//self 代表调用者本身 带self的方法叫实例方法
__init__ 初始化方法
__init__ 初始化方法,做属性初始化
实例对象调用实例方法:解释器将实例对象作为第一个实参传入给实例方法。
在分析现实生活中的事物时发现,这些事物都有其具体的特点和功能,这些特点和功能就组成了这个特殊的事物 我们来描述一辆小汽车: 分析: 事物的特点(属性): 颜色 品牌 事物的功能: 高速运行 发现:事物其实就是由特点(属性)和行为(功能)组成的。 可以简单的理解:属性就是数据,由变量存储;行为就是功能,就是方法。 小汽车类 颜色 品牌 def 高速运行(): pass 在python语言中定义的类语法: class 类名: # 声明一个类 注意,如果由单词构成类名,建议大驼峰命名。 ''' 解释文档 ''' 类变量 def 实例方法(self,*args,**kwargs): pass
2.2 实例对象
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Person类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
案例演示:
class Person(object): pass p1=Person() p2=Person() print(id(p1)) print(id(p2))
每一个人的实例对象都应该有自己的属性,比如姓名和年龄,实例变量的赋值如下:
# 实例变量的增删改查 p1.name="alex" p1.age=18 p2.name="yuan" p2.age=22 print(p1.gender) del p2.age
这种方式需要先实例化再赋值实例变量,如何能在实例化对象的时候就将实例变量赋值好呢?这就要利用到类的魔法方法中最重要的构造方法:初始化方法( init)了:
# 定义Person类 class Person(object): def __init__(self,name,age): self.name=name self.age=age print(id(self)) # 实例化Person类的实例对象: 类实例对象=类名(实例化参数) alex=Person("alex",18) yuan=Person("yuan",22) print(id(alex))
注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
2.2 实例方法
实例方法或者叫对象方法,指的是我们在类中定义的普通方法。只有实例化对象之后才可以使用的方法,该方法的第一个形参接收的一定是对象本身。
class Person(object): def __init__(self,name,age): self.name=name self.age=age def print_info(self): print("姓名:%s,年龄:%s"%(self.name,self.age)) yuan = Person("yuan",18) yuan.print_info()
一切皆对象
python语言中,一切皆对象!
我们之前学习过的字符串,列表,字典等等数据都是一个个的类,我们用的所有数据都是一个个具体的实例对象。
区别就是,那些类是在解释器级别注册好的,而现在我们学习的是自定义类,但语法使用都是相同的。所以,我们自定义的类实例对象也可以和其他数据对象一样可以进行传参、赋值等操作。
class Weapon: def __init__(self,name,av,color): self.name=name self.av=av self.color=color jiguangqiang=Weapon("激光枪",100,"red") class Hero: def __init__(self,name,sex,hp,ce,weapon,level=2,exp=2000,money=10000): # 类必不可少的方法,用于实例化 self.name=name # 英雄的名字 self.sex=sex # 英雄的性别 self.hp=hp # 英雄生命值 self.level=level # 英雄的等级 self.exp=exp # 英雄的经验值 self.money=money # 英雄的金币 self.weapon=weapon # 英雄的武器 yuan=Hero("yuan","male",100,80,jiguangqiang) print(yuan.weapon.color) #red
2.4 类对象和类属性
class Person: # 类属性 legs_num = 2 has_emotional = True def __init__(self,name,age): self.name = name self.age = age def standWalking(self): print("直立行走") # 实例对象和类对象可以获取类属性,但是只有类对象才能修改类属性 yuan = Person("yuan",18) alvin = Person("alvin",18) print(yuan.legs_num) print(yuan.name) print(Person.legs_num)
2.5 静态方法和类方法
静态方法
定义:使用装饰器
@staticmethod
。参数随意,没有self
和cls
参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:类对象或实例对象都可以调用。
class Cal(): @staticmethod def add(x,y): return x+y @staticmethod def mul(x,y): return x*y cal=Cal() print(cal.add(1, 4)) #or print(Cal.add(3,4))
类方法
定义:使用装饰器
@classmethod
。第一个参数必须是当前类对象,该参数名一般约定为cls
,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:类对象或实例对象都可以调用。
class Student: # 类属性 cls_number = 68 @classmethod def add_cls_number(cls): cls.cls_number+=1 print(cls.cls_number) Student.add_cls_number()
问题:
- 类对象.实例方法会怎么样?
- 类方法的意义是什么,在实例方法中使用类对象变量不可以吗?
类的成员-变量
在类中变量分为两大类:
1.实例变量(字段)
2.类变量(静态变量)
实例变量:每个实例都应该拥有的变量,比如,人的名字,人的爱好,都是属于实例变量。
类变量:就是这一类事物统一拥有的变量。
class Person: #类变量,表示所有的该类对象都共享这个变量。 country = "中国" def __init__(self,name,num,birthday): #实例变量(字段),表示创建的每一个人都有着三个变量 self.name = name self.num = num self.birthday = birthday p1 = Person("li",18,"2020-10-24") print(p1.name) #li print(p1.num ) #18 print(p1.birthday) #2020-10-24 print(p1.country) #中国 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.num ) #22 print(p2.birthday) #2020-10-24 print(p2.country) #中国
发现对象p1和p2的name都是对象自己的,但是country是类的,大家公用同一个变量,
验证
Person.country = "唐朝" #这这里 把中国换为了唐朝 p1 = Person("li",18,"2020-10-24") print(p1.name) #li print(p1.num ) #18 print(p1.birthday) #2020-10-24 print(p1.country) #唐朝 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.num ) #22 print(p2.birthday) #2020-10-24 print(p2.country) #唐朝
把类中的值修改了,输出的内容也就跟着修改了。
通过图发现,实例变量中都隐含着一个创建这个对象的类,通过这个类就能找到我们类中定义的全部内容,包括方法和属性信息等等。
一个坑
p1 = Person("li",18,"2020-10-24") p1.country = "大清" print(p1.name) #li print(p1.country) #大清 p2 = Person("xing",22,"2020-10-24") print(p2.name) #xing print(p2.country) #中国
//上面是大清,下面是中国,在执行p1.country = “大清”的时候,其实并没有去改变类中的country,而是给对象添加了一个实例变量,并且这个实例变量,只有当前的p1是存在的,在p2是不存在的
p1只是添加了一个实例变量,并没有修改类的变量,通过这里,我们应该能发现,类变量,最好是用类名来访问,当然,我们通过对象名也可以访问,但只能看,不能修改它,想要修改它,需要用类名来修改它。
案例。通过程序来记录当前类被创建了多少个对象
class Foo: count = 0 def __init__(self): Foo.count += 1 print(Foo.count) #0 Foo() Foo() Foo() print(Foo.count) #3
总结
实例变量是给对象用的。
类变量,多个对象共享,最好是用类名来访问,这样更规范
面向对象三大特性
继承(重点掌握)
面向对象的编程带来的主要好处之一就是代码的重用,实现这种重用的方法之一就是通过继承的机制,通过继承创建的新类称之为子类或者派生类,被继承的类被称为基类 父类或超类
class 派生类名(基类名) ...
1.1 继承的基本使用
通过使用继承我们能够非常方便的复用以前的代码,能够大大的提高开发的效率。
实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有的特性。例如猫有抓老鼠,爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替代被继承者,反之则不可以,例如 我们可以说猫是动物,但不能说动物是猫,就是这个道理,其实对于这个我们将其称之为“向上转型”。
诚然,继承定义了类如何相互关联,共享特性,对于若干相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性,方法还可以定义自己独有的属性或者方法。
同时在使用集成时需要记住三句话
1.子类拥有父类非私有化的属性和方法。 2.子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 3.子类可以用自己的方法实现父类的方法
#无继承方法 class dog: def eat(self): print("eating...") def sleep(self): print("sleep...") def swimming(self): print("swimming...") class cat: def eat(self): print("eating...") def sleep(self): print("sleep...") def climb_tree(self): print("climb_tree...") # 继承方式 class Animal: def eat(self): print("eating...") def sleep(self): print("sleep...") class Dog(Animal): def swimming(self): print("toshetou...") class Cat(Animal): def climb_tree(self): print("climb_tree...")
1.2 重写父类方法和调用父类方法
class Person(object): def __init__(self,name,age): self.name=name self.age=age def sleep(self): print("基类sleep....") class Emp(Person): def __init__(self,name,age,dep): super().__init__(name,age) self.dep = dep def sleep(self): if True: # print("子类sleep...") # 调用父类方法 # 方式1 :父类对象调用 父类对象.方法(self,其他参数) # Person.sleep(self) # 方式2: super关键字 super(子类对象,self).方法(参数)or super().方法(参数) super().sleep() print("123") yuan = Emp("yuan",18,"教育部") yuan.sleep() print(yuan.dep)
class Base: def __init__(self): self.func() def func(self): print('in base') class Son(Base): def func(self): print('in son') s = Son()
1.3 多重继承
如果在继承单元组中列了一个以上的类,name他就被称作为“多重继承”。派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后
class SubClassName(ParentClass1,ParentClass2,...)
class Animal: def __init__(self): pass def eat(self): print("eating...") def sleep(self): print("sleep...") class Fly: def fly(self): print("fly...") class Eagle(Animal, Fly): pass e = Eagle() e.fly() e.sleep()
1.4 type和isinstance方法
isinstance
作用:
判断一个对象是某个类或子类的实例。
type
得到传入的object的类型
共同点
type和isinstance都可以判断变量是否属于某个内建类型
不同点
1.type只接收一个参数,不但可以判断变量是否属于某个类型,而且可以得到参数变量未知的所属的类型;而isinstance只能判断是否属于某个已知类型,不能直接得到变量未知的所属的类型
2.isinstance可以判断子类实例对象是属于父类的;而type会判断子类实例对象和父类类型不一样
综上所述,isinstance和type的应用场景是不同的:
type主要用于获取未知变量的类型
isinstance主要用于判断A类是否继承于B类
class Animal: def eat(self): print("eating...") def sleep(self): print("sleep...") class Dog(Animal): def swim(self): print("swimming...") alex = Dog() mjj = Dog() print(isinstance(alex,Dog)) print(isinstance(alex,Animal)) print(type(alex)) print(type(mjj)) print(type(alex)==Dog) print(type(mjj)==Animal)
1.5、dir()方法和__dict__属性
dir(obj)可以获得对象的所有属性(包含方法)列表, 而obj.__dict__对象的自定义属性字典
注意事项:
1. dir(obj)获取的属性列表中,方法也认为属性的一种。返回的是list 2. obj.__dict__只能获取自己自定义的属性,系统内置属性无法获取。返回是dict
class Student: def __init__(self, name, score): self.name = name self.score = score def test(self): pass yuan = Student("yuan", 100) print("获取所有的属性列表") print(dir(yuan)) print("获取自定义属性字段") print(yuan.__dict__)
其中,类似__xx__的属性和方法都是有特殊用途的。如果调用len()函数视图获取一个对象的长度,其实在len()函数内部会自动去调用该对象的__len__()方法
封装(理解)
封装概述
是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装原则
1.将不需要对外提供的内容隐藏起来。 2.把属性隐藏,提供公共方法对其访问。
封装好处
1.隐藏实现细节,提供公共的访问方式 2.提高了代码的复用性。 3.提高安全性
1.1 私有属性
在class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。
如果让内部属性不被外部访问,可以把属性的名称前面加上两个下划线__,在python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
class Student(object): def __init__(self,name,score): self.__name = name self.__score = score alex = Student("alex",66) yuan = Student("yuan",88) print(alex.__score)
改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问
实例变量.__name和实例变量.__score
这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。
增加外部访问
class Student(object): def __init__(self,name,score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score alex = Student("alex",66) yuan = Student("yuan",88) print(alex.get_name()) print(alex.get_score())
增加外部修改代码
class Student(object): def __init__(self,name,score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score def set_score(self,score): self.__score = score alvin = Student("alex",66) print(alvin.get_score()) yuan = Student("yuan",88) alvin.set_score(100) print(alvin.get_score())
你也许会问,原先那种直接通过alvin.score = 100也可以修改啊,为什么要定义一个方法大费周折?因为在方法中,可以设置值时做其他操作,比如记录操作日志,对参数做检查,避免传入无效的参数等等:
class Student(object): ... def set_score(self,score): if isinstance(score,int) and 0 <= score <= 100: self.__score = score else: raise ValueError('error!')
注意
1.这种机制也没有真正意义上限制我们从外部直接访问属性,知道了类名和属性就可以拼出名字:
_类名__属性,然后就可以访问了,如a._A__N
2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形。
class Student(object): def __init__(self, name, score): self.name = name self.__score = score def get_score(self): return self.__score yuan=Student("yuan",66) print(yuan.__dict__) yuan.__age=18 print(yuan.__dict__)
3.单下划线、双下划线、头尾双下划线说明:
__foo__:定义的是特殊方法,一般是系统定义的名字,类似__init__()之类的。 _foo:以单下划线开头的表示的是protected类型的变量,即保护类型只能允许其本身与子类进行访问。(约定成俗,不限语法) __foo:双下划线的表示的是私有类型(private)的变量,只能是允许这个类本身进行访问了
1.2私有方法
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
class Base: def foo(self): print("foo from Base") def test(self): self.foo() class Son(Base): def foo(self): print("foo from Son") s=Son() s.test() class Base: def __foo(self): print("foo from Base") def test(self): self.__foo() class Son(Base): def __foo(self): print("foo from Son") s=Son() s.test()
1.3 property属性装饰器
使用接口函数获取修改数据 和 使用点方法(alex.name='yuan'或者print(yuan.name))设置数据相比, 点 方法使用更方便,我们有什么方法达到既能使用点方法,同时又能让点方法直接调用到我们的接口了,答案就是property属性装饰器。
多态
在Java里,多态是同一个行为具有不同表现形式或形态的能力,即对象多种表达形式的体现,就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向那个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现方法,必须在由程序运行期间才能确定。
java代码示例
/** * 支付抽象类或者接口 */ public class Pay { public String pay() { System.out.println("do nothing") return "success" } } /** * 支付宝支付 */ public class AliPay extends Pay { @Override public String pay() { System.out.println("支付宝pay"); return "success"; } } /** * 微信支付 */ public class WeixinPay extends Pay { @Override public String pay() { System.out.println("微信Pay"); return "success"; } } /** * 银联支付 */ public class YinlianPay extends Pay { @Override public String pay() { System.out.println("银联支付"); return "success"; } } 测试支付 public static void main(String[] args) { /** * 测试支付宝支付多态应用 */ Pay pay = new AliPay(); pay.pay(); /** * 测试微信支付多态应用 */ pay = new WeixinPay(); pay.pay(); /** * 测试银联支付多态应用 */ pay = new YinlianPay(); pay.pay(); } ------>输出结果如下: 支付宝pay 微信Pay 银联支付
多态存在的三个必要条件
继承 重写 父类引用指向子类对象
在Java中 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译报错;如果有,再去调用子类的同名方法。
在python语言中实现多态
#父类引用指向子类对象 class Payment(object): def __init__(self,name,money): self.name = name self.money = money def pay(self,*args,**kwargs): pass #继承 class Alipay(Payment): def pay(self): #支付宝 #重写 print('%s通过支付宝消费了%s元'%(self.name,self.money)) #继承 class WeChatpay(Payment): def pay(self): #微信 #重写 print('%s通过微信消费了%s元'%(self.name,self.money)) class Order(object): """支付接口调用""" def account(self,pay_obj): pay_obj.pay() #消费人员和消费金额 pay_obj = WeChatpay("li",100) pay_obj2 = Alipay("wang",200) # order = Order() order.account(pay_obj) order.account(pay_obj2)
从上述代码可见,在调用order对象的account()方法时,程序并不关心为该方法传入的参数对象 pay_obj是谁,只要求此参数对象pay_obj 包含pay()方法即可,而调用者传入的参数对象类型 pay_obj 是子类对象还是其他类对象,python无所谓!
多态性就是相同的消息(函数方法触发)使得不同的类做出不同的响应,这就是典型的类编程中多态性的应用实例。
#鸭子模型 if something looks like a duck, swims like a duck and quacks like a duck then it’s probably a duck.
反射和魔法方法
反射
反射这个术语在很多语言中都存在,并且存在大量的运行。
反射主要是程序可以访问,检测和修改它本身状态的行为或者一种恩能力,在python中一切皆对象(类,实例,模块等等都是对象),那么我们就可以通过反射的形式操作对象相关的属性
python中反射的常用方法
1.hasateer(object,name) 判断对象中有没有一个name字符串对象的方法或者属性
2.getatter(object,name,default=None) 获取对象name字符串属性的值,如果不存在返回default的值
3.setatter(object,key,value) 设置对象的key属性为value值,等同于 object.key = value
4.delatter(obiect,name) 删除对象name字符串属性
应用一
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender li = Person("li",22,"male") print(li.name) print(li.age) print(li.gender) attr = input(">>>") #判断对象属性中有没有attr字符串对应的方法和属性 if hasattr(li,attr): #获取对象attr字符串属性的值,如果不存在放回None val = getattr(li,attr) #打印val内容 print(val) else: val = input("li没有你该属性信息!请设置该属性>>>") #新增一个属性,设置对象的attr属性为val。 setattr(li,attr,val) #打印新增属性的值 print(getattr(li,attr))
if 成立
if 不成立
应用2
class FTP(object): def __init__(self): self.run() def run(self): print(''' 提示 上传: put 路径/文件名称 下载: get 路径/文件名称 ''') while 1: input_str = input(">>>") action,params = input_str.split(" ") if hasattr(self,action): getattr(self,action)() else: print("不存在方法") def put(self): print("上传...") def get(self): print("下载...") ftp = FTP()
魔法方法
__new__
#构建方法:__new__ class B(object): def __new__(cls,*agrs,**kwargs): print("我是用来开辟一块内存空间的") obj=super().__new__(cls) return obj def __init__(self): print("self就是__new__开辟的空间地址") B()
__init__
# 初始化方法:__init__ class A(object): def __init__(self): print("初始化方法") A()
__str__
# __str__ #如果要把一个类的实例变成 str,就需要实现特殊方法__str__(): #不使用 __str__ ,print打印出来是个对象;使用了就把对象变成字符串 class C(object): def __init__(self,name,age): self.name = name self.age = age def __str__(self): #必须返回字符串类型 return self.name c1 = C("c1",20) c2 = C("c2",30) print(c1) print(c2)
__call__
# __call__ 该方法的功能类似于在类中重载 () 运算符,使得类实例对象可以像调用普通函数那样,以“对象名()”的形式使用。 class D(object): def __call__(self, *args, **kwargs): print("call被调用...") #callable 意为返回对象是否可调用 print(callable(D)) d1 = D print(callable(d1)) d1() D()()
# 析构方法 __del__ class File(object): file="a.txt" def __init__(self): #初始化时打开文件 self.f=open(self.file) def __def__(self): #删除时(回收)关闭文件 self.f.close()
__getitem__
# __getitem__ class G(object): def __init__(self): pass def __getitem__(self, item): print("__getitem__被调用") def __setitem__(self, key, value): print("__setiem__被调用") def __delitem__(self, key): print("__delitem__被调用") g=G() g["name"] = "li" print(g["name"]) del g["name"]
__getattr__
# __getattr__ class H(object): def __init__(self): pass def __getattr__(self, item): print("__getattr__被调用") def __setattr__(self, key, value): print("__setattr__被调用") def __delattr__(self, item): print("__delattr__被调用") h=H() h.name = "li" print(h.name) del h.name
8 __eq__ class I(object): def __init__(self,name,age): self.name=name self.age=age def __eq__(self, other): if self.name==other.name and self.age==other.age: return True else: return False i1=I("alex",30) i2=I("alex",30) print(i1==i2)
class Person(object): def __init__(self,name,age): self.name=name self.age=age def foo(self, other): pass def bar(self): pass def __eq__(self, other): print(1) return True # return self == value alex=Person("alex",30) yuan=Person("yuan",30) print(id(yuan.foo) == id(alex.foo)) print(yuan.foo == alex.bar) print(yuan.foo == alex.foo) print(yuan.foo == yuan.foo)
# __len__ class G(object): def __len__(self): return 100 g=G() print(len(g))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现