当前位置: 首页 > java >正文

Python-15(类与对象)

OOP编程即面向对象编程。

面向对象是一种代码封装的方法。一方面从静态的属性特性入手,另一方面从行为能力入手。

对象 = 属性+方法

生产对象之前必须先编写一个类。

类的首字母需大写(约定俗成)。

属性就是写在类里的变量,方法就是写在类里的函数。

封装

在创建对象之前,通过类将性格的属性方法打包到一起,然后通过类生产相应的对象。

class People:head = 1eyes = 2legs = 2hand = 2def say(self):print("good morning")def eat(self):print("正在吃饭")
p1 = People()
p2 = People()
p2.hand = 1
print(p1.hand)
print(p2.hand)
p1.say()
p2.eat()

注意:不同对象之间是不会共享数据的,更改p2的属性,p1的属性不会随之改变。

可以增加对象的属性。

class People:head = 1eyes = 2legs = 2hand = 2def say(self):print("good morning")def eat(self):print("正在吃饭")
p1 = People()
p2 = People()
p1.mouth = 1
print(dir(p1))
print(dir(p2))

self是实例对象本身,self参数传递的信息让python明白是哪个对象在调用函数,所有类中的方法默认的参数都是self,第一个参数也是self。

class People:def say(self):print(self)
p1 = People()
p1.say()
print(p1)

继承

python的类是支持继承的,可以使用现有类的所有功能,并在无需重新编写代码的情况下,对这些功能进行扩展。通过继承创建的新类我们称之为子类,而被继承的类我们称之为父类、基类或者超类。

class Animal:category = 100def say(self):print("我是动物")
class Dog(Animal):category = 20def say(self):print("我是狗")
a = Animal()
d = Dog()
a.say()
d.say()

注意:子类的属性值和方法会覆盖父类的属性值和方法。

isinstance()函数

用于判断一个对象是否属于某个类。

class Animal:category = 100def say(self):print("我是动物")
class Dog(Animal):category = 20def say(self):print("我是狗")
a = Animal()
d = Dog()
print(isinstance(d,Dog))
print(isinstance(d,Animal))
print(isinstance(a,Dog))

issubclass()函数

用于检测一个类是否为某个类的子类。

class Animal:category = 100def say(self):print("我是动物")
class Dog(Animal):category = 20def say(self):print("我是狗")
a = Animal()
d = Dog()
print(issubclass(Dog,Animal))
print(issubclass(Animal,Dog))

多重继承

一个子类同时可以继承多个父类。

class Father:sex = "男"def say(self):print("我是父亲")
class Monther:sex = "女"def say(self):print("我是母亲")
class Children(Father,Monther):def say(self):print("我是孩子")
c = Children()
print(c.sex)

注意:多重继承的顺序自左向右,只有在当前类中找不到所需的属性才会向下一个父类(右边的)进行寻找。

组合

当类于类的关系不是从属关系,而是并列的关系,这时使用组合,即将相关的实例放到某个类中。

class Father:sex = "男"def say(self):print("我是父亲")
class Monther:sex = "女"def say(self):print("我是母亲")
class Children:def say(self):print("我是孩子")
class Family:f = Father()m = Monther()c = Children()def say(self):self.f.say()self.m.say()self.c.say()
fm = Family()
fm.say()

绑定(self)

self的作用就是将实例对象跟类的方法进行绑定,在实例中除了类的方法,实例的属性却可以是自己。python是一门支持内省的编程语言。其对象在运行的时候拥有自我观察的能力。

__dict__

显示当前对象拥有的私有属性,以字典的形式来保存其属性和其对应的值。

class Father:year = 30def say(self):print("我是父亲")
f = Father()
f.sex = "男"
print(f.__dict__)

注意:在类中定义的公共属性无法显示。

定义属性

可以使用self,利用类中的方法来定义对象自己的属性。self就是实例化对象本身。

class Father:def set_year(self,y):self.year = ydef set_name(self,n):self.name = n
f = Father()
f.set_year(30)
f.set_name("王强")
print(f.__dict__)

注意:如果要修改对象的属性,必须通过self绑定。

构造函数

构造函数即__init__(),只需要在类中定义__init__()方法,就可以在实例化对象的同时实现个性化定制。

class Number:def __init__(self,x,y):self.x = xself.y = ydef add(self):return self.x+self.ydef mul(self):return self.x*self.y
n = Number(3,4)
print(n.add())
print(n.mul())
print(n.__dict__)

注意:等号左边的绑定到实例化对象里的属性,等号右边是传进来的参数。

重写

当父类的方法不能满足子类的需求,我们可以对父类方法重写,其指子类中的方法名与父类方法名称相同,但参数列表和内部代码可以不同。相当于子类对父类的方法进行重新定义。

class Number:def __init__(self,x,y):self.x = xself.y = ydef add(self):return self.x+self.ydef mul(self):return self.x*self.yclass Number2(Number):def __init__(self,x,y,z):Number.__init__(self,x,y)self.z = zdef add(self):return Number.add(self) + self.zdef mul(self):return Number.mul(self) * self.z
n = Number2(3,4,5)
print(n.add())
print(n.mul())
print(n.__dict__)

调用未绑定的父类方法,即直接通过类名访问类里面的方法。但可能造成钻石继承。

钻石继承

  类A的构造方法会被重复调用两次。

class A:def __init__(self):print("我是A")
class B1(A):def __init__(self):A.__init__(self)print("我是B1")
class B2(A):def __init__(self):A.__init__(self)print("我是B2")
class C(B1,B2):def __init__(self):B1.__init__(self)B2.__init__(self)print("我是C")
c = C()

super()函数

super函数能够解决钻石继承的问题,其在父类中搜索指定的方法,并自动绑定后self参数。使用super函数去查找父类的方法,它会自动按照MRO顺序(是Python中用于确定多继承场景下方法调用顺序的算法)去搜索父类的相关方法。

class A:def __init__(self):print("我是A")
class B1(A):def __init__(self):super().__init__()print("我是B1")
class B2(A):def __init__(self):super().__init__()print("我是B2")
class C(B1,B2):def __init__(self):super().__init__()print("我是C")
c = C()

mro()方法

可以使用mro方法来查找一个类的MRO。

class A:def __init__(self):print("我是A")
class B1(A):def __init__(self):super().__init__()print("我是B1")
class B2(A):def __init__(self):super().__init__()print("我是B2")
class C(B1,B2):def __init__(self):super().__init__()print("我是C")
c = C()
print(C.mro())

注意:其中的object类是所有类的基类,就算不写也会被隐式的继承。 

__mro__属性

其功能与mro方法类似。

class A:def __init__(self):print("我是A")
class B1(A):def __init__(self):super().__init__()print("我是B1")
class B2(A):def __init__(self):super().__init__()print("我是B2")
class C(B1,B2):def __init__(self):super().__init__()print("我是C")
print(C.mro())
print(B1.__mro__)

Mixin(Mix-in 混入或乱入)

即后续增添的功能。

多态

多态是指同一个运算符、函数或者对象在不同场景下具有不同作用效果。

运算符的多态

print(3+5)
print(3*5)
print("py"+"thon")
print("py"*3)

len()函数

print(len("python"))
print(len(["","",""]))
print(len({"name":"小强","age":18}))

类的多态

重写就是显示类继承的多态,python允许在子类中定义和父类同名的方法,如果对父类的某个方法不满意,可以在子类中重新定义一个同名的方法进行覆盖。

正方形类和圆形类都继承于Sharp类,但是他们都重写了构造函数和area()方法,这就是多态的体现。

class Sharp:def __init__(self,name):self.name = namedef area(self):pass
class Square(Sharp):def __init__(self,length):super().__init__("正方形")self.length = lengthdef area(self):return self.length * self.length
class Circle(Sharp):def __init__(self,radius):super().__init__("圆形")self.radius = radiusdef area(self):return self.radius * self.radius * 3.14
s = Square(5)
print(s.area())
c = Circle(6)
print(c.area())
print(s.name)
print(c.name)

自定义函数实现多态接口

传入函数的参数不同,所产生的效果也不同。

class Cat:def __init__(self,name,age):self.name = nameself.age = agedef intro(self):print(f"我是一只猫,我叫{self.name},今年{self.age}岁")def say(self):print("喵喵喵")
class Dog:def __init__(self,name,age):self.name = nameself.age = agedef intro(self):print(f"我是一只狗,我叫{self.name},今年{self.age}岁")def say(self):print("汪汪汪")
class Pig:def __init__(self,name,age):self.name = nameself.age = agedef intro(self):print(f"我是一只猪,我叫{self.name},今年{self.age}岁")def say(self):print("哼哼哼")
c = Cat("小喵",3)
d = Dog("小汪",4)
p = Pig("小胖",5)
def animal(x):x.intro()x.say()
animal(c)
animal(d)
animal(p)

私有变量

通过某种手段,使得对象中的属性或方法无法被外部所访问。在python中,进行从一个对象内部才能够进行访问的”私有变量“并不存在。

name mangling(名字改编、名称改写或名称修饰)

语法是在名字的前面加上两个连续的下划线(__)。以两个下划线开头的变量代表是私有变量。

无法直接通过实例对象来访问或更改其私有变量,只能通过其内部函数进行访问或修改。

class C:def __init__(self,x):self.__x = xdef set_x(self,x):self.__x = xdef get_x(self):print(self.__x)
c = C(520)
c.set_x(1314)
c.get_x()

 

注意:python的私有方式只是将程序员想要私有的变量改个名藏起来,我们可以通过以下方式进行访问(但不建议这么做):

_类名__变量名(方法名)

class C:def __init__(self,x):self.__x = xdef set_x(self,x):self.__x = xdef get_x(self):print(self.__x)
c = C(520)
print(c._C__x)

注意:在类实例化对象之后,手动添加私有变量,其名字无法被改编。名字改编是发生在类实例化对象时的事情。

class C:def __init__(self,x):self.__x = xdef set_x(self,x):self.__x = xdef get_x(self):print(self.__x)
c = C(520)
c.__y = 1314
print(c.__dict__)

 

单个下划线开头的变量(_变量名)是仅供内部使用的变量。

单个下划线结尾的变量(变量名_)是将python使用的关键字二次使用,防止报错。

__slots__(节省空间)

对于一个明确自己需要多少属性,也不需要动态的添加属的类来说,那么利用字典来存放属性的方式非常浪费空间。使用__slots__类属性可以避免利用字典来存放造成空间上的浪费。

__slots__ = ["属性1","属性2"......]

其中的属性就是希望此类的实例化对象可以使用的属性名称。

class C:__slots__ = ["x","y"]def __init__(self,x):self.x = x
c = C(520)
c.y = 1314
print(c.x)
print(c.y)
c.z = 888

 注意:继承自父类的__slots__属性是不会在子类中生效的,python只会关注各个具体的类中定义的__slots__属性。

class C:__slots__ = ["x","y"]def __init__(self,x):self.x = x
class D(C):pass
d = D(520)
d.y = 1314
d.z = 666
print(d.__slots__)
print(d.__dict__)

 

__new__(cls[,...])方法

在init方法被调用之前,new放就被调用了。事实上对象就是由new方法创建的。

重写new方法有两种情况,一种情况是在元类中去定制类,另一种情况是在继承不可变数据类型。

class CapStr(str):def __new__(cls, string):string  = string.upper()return super().__new__(cls,string)
c = CapStr("python")
print(c)

之所以能够修改不可变对象,是因为在创建实例对象之前进行拦截,然后再调用super().__new__()去创建真正的实例。

CapStr继承自str类,那么也会继承str类的各种方法。

__del__()方法

只有对象被销毁时才会触发该方法。当检测到对象没有任何引用时,才会将其销毁。

对象的重生

只要在对象被销毁之前将对象送出去,那么理论上del语句就不会调用到__del__()方法。因为此时这个对象还存在引用。

使用全局变量

class D:def __init__(self,name):self.name = namedef __del__(self):global xx= self
d = D("python")
print(d)
print(d.name)
del d
print(d)

输出x发现x其实就是d 

class D:def __init__(self,name):self.name = namedef __del__(self):global xx= self
d = D("python")
print(d)
print(d.name)
del d
print(x)
print(x.name)

使用函数调用

通过参数传递的形式将self传出去。

class D:def __init__(self,name,func):self.name = nameself.func = funcdef __del__(self):self.func(self)
def outter():x = 0def inner(y = None):nonlocal xif y:x = yelse:return xreturn inner
f = outter()
d = D("python",f)
print(d)
del d
g = f()
print(g)

f就是inner,当del d的时候执行inner(self),把self保存到x中,然后g = f(),相当于g = inner(),此时传入的参数为none,就把之前保存的x输出出来。

属性访问

hasattr(对象,属性)函数

判断该对象是否存在指定的属性。

class C:def __init__(self,name,age):self.name = nameself.__age = age
c = C("James",18)
print(hasattr(c,"name"))

getsttr(对象,属性名)函数

获取该对象的指定属性的值。

class C:def __init__(self,name,age):self.name = nameself.__age = age
c = C("James",18)
print(getattr(c,"name"))

注意:如果想获取私有变量的值,需要通过_类名__属性名的方式获取。

setattr(对象,属性,属性值)函数

在该对象中更改指定属性值。

class C:def __init__(self,name,age):self.name = nameself.__age = age
c = C("James",18)
setattr(c,"_C__age",19)
print(getattr(c,"_C__age"))

delattr(对象,属性)函数

删除该对象的指定属性。

class C:def __init__(self,name,age):self.name = nameself.__age = age
c = C("James",18)
delattr(c,"_C__age")
print(hasattr(c,"_C__age"))

http://www.xdnf.cn/news/12502.html

相关文章:

  • 人工智能初学者可以从事哪些岗位?
  • 逻辑卷和硬盘配额(补充)
  • 会计 - 合并1- 业务、控制、合并日
  • 6个月Python学习计划 Day 16 - 迭代器、生成器表达式、装饰器入门
  • 【汇编逆向系列】八、函数调用包含混合参数-8种参数传参,条件跳转指令,转型指令,movaps 16字节指令
  • 第16届蓝桥杯青少Scratch 4月stema——飞翔的小燕子
  • 二叉树基础全解:存储方式、遍历原理与查找树对比
  • Go垃圾回收参数调优:实现低延迟服务的实战指南
  • MongoDB检查慢查询db.system.profile.find 分析各参数的作用
  • 一篇文章实现Android图片拼接并保存至相册
  • 4082N信号频谱分析仪
  • 设置应用程序图标
  • Android设备推送traceroute命令进行网络诊断
  • 晨控CK-FR102ANS与欧姆龙NX系列PLC配置EtherNet/IP通讯配置操作手册
  • 96.如何使用C#实现串口发送? C#例子
  • 数据结构与算法——二叉树高频题目(1)
  • Oracle数据库学习笔记 - 创建、备份和恢复
  • html表格转换为markdown
  • 测试设计技术全解析:黑盒与白盒测试的七种武器与覆盖率指标
  • 深入解析Java中的装箱与拆箱机制
  • CMOS图像传感器系列--(一)像素设计基础
  • BEV和OCC学习-5:数据预处理流程
  • 全生命周期的智慧城市管理
  • Qemu arm操作系统开发环境
  • Python图像处理基础(五)
  • 第34次CCF-CSP认证真题解析(目标300分做法)
  • 预训练语言模型T5-11B的简要介绍
  • 精益数据分析(95/126):Socialight的定价转型启示——B2B商业模式的价格策略与利润优化
  • 外卖大战背后的创始人IP智慧:差异化、护城河与心智占领
  • c++中的输入输出流(标准IO,文件IO,字符串IO)