python面向对象编程

python中的类python中的类 面向对象与面向过程的本质的区别 面向对象与面向过程的本质的区别

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

可以拿生活中的实例来理解面向过程与面向对象,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用不同的方法来实现。

如果是面向对象的设计思想来解决问题。面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。

属性用来描述具体某个对象的特征。比如小志身高180M,体重70KG,这里身高、体重都是属性。

面向对象的思想就是把一切都看成对象,而对象一般都由属性+方法组成!

属性属于对象静态的一面,用来形容对象的一些特性,方法属于对象动态的一面,咱们举一个例子,小明会跑,会说话,跑、说话这些行为就是对象的方法!所以为动态的一面, 我们把属性和方法称为这个对象的成员!

类:具有同种属性的对象称为类,是个抽象的概念。比如“人”就是一类,期中有一些人名,比如小明、小红、小玲等等这些都是对象,类就相当于一个模具,他定义了它所包含的全体对象的公共特征和功能,对象就是类的一个实例化,小明就是人的一个实例化!我们在做程序的时候,经常要将一个变量实例化,就是这个原理!我们一般在做程序的时候一般都不用类名的,比如我们在叫小明的时候,不会喊“人,你干嘛呢!”而是说的是“小明,你在干嘛呢!”

面向对象有三大特性,分别是封装性、继承性和多态性。


B站 Leofaith教程

万物皆对象(object),在别的语言中有的数据类型可能不属于对象,但是在python里所有的数据类型都可以是对象。面向对象——在解决问题的时候,关注的是解决问题所需要的对象。

面向过程需要关心做事的每一个步骤,全部由自己来实现;而面向对象要做一件事,都是在找这件事情可以分配给哪个对象来做,对象也可以把任务继续交给下面的对象来做。面向对象做这件事情的步骤并没有减少,只不过它把不同功能的步骤划分到了某一个对象里,所以面向对象是对面向过程的封装

面向对象编程的步骤:

  1. 列举出一个任务的具体实现步骤

  1. 试图分离这些实现步骤中的功能代码块

  1. 将这些功能代码块,划分到某一个对象中

  1. 根据这个对象以及对应的行为,抽象出对应的类 。 —设计类

是对某一个具体对象特征的抽象。属性是一些静态的特征值,方法是动态的动作。

张三这个具体的对象,抽象出一个类叫不良青年,这是一个抽象的概念,并不是某一个具体的人。这个不良青年的这个类,也具有一些属性,比如身高体重;也有一些行为,比如吃喝嫖赌。但是这些都是抽象的概念,并没有具体的数值。

不良青年应该有一个年龄的属性,但是不同的不良青年,比如张三李四王五,有不同的年龄。

类的作用:根据抽象的类,生产出具体的对象。

类是这些它生成的对象的模板

类的组成:类的名称、属性、方法。(类的属性和方法都是抽象的概念,没有具体的值;类在产生对象后,对象才有具体的属性值和方法实现)

对象和类的关系:对象可以抽象出一个类,类可以实例化一个对象。

创建类 class Money:#要注意类名的首字母要大写,这是规范;不要小括号。这个Money除了是个类名(类名不可修改),还是个变量名称(可以被改名,如Money=abc,但改了之后好像就不是指向Money这个类了)。视频讲解

一旦定义一个类,就会开辟一块内存给它

还可以通过type元类来创建类,比较高级的用法 教程

创建对象

class Money:
    pass
#根据这个类,实例化一个对象
one = Money()  #类+()可以实例化一个对象,赋值给one变量,接下来就可以通过one这个变量
               #来操作这个对象

one指向了Money实例化的对象的地址(实例化对象的时候也开辟了一块内存)

Money类产生的对象里有一个属性值__class__,是类的地址。所以在操作one变量的时候会先找到Money类产生的对象,然后通过__class__关联到Money这个类。当我们操作one这个变量时,其实操作的是one这个变量所引用的对象。

对象属性

怎样让一个对象拥有一些属性?

方法一:直接通过对象,动态添加 语法: 对象.属性 = 值

p.__dict__ dict这个属性是python自动加的,功能是可以查看对象的所有属性和值,会返回一个字典

#定义一个类,类名首字母必须大写
class Person:
    pass
#根据类,创建一个对象
p = Person()
#给p对象增加一些属性
p.age = 18
p.height = 180
#验证是否有添加成功
print(p.age)
print(p.height)
print(p.__dict__)  
#p.__dict__  __dict__这个属性是python自动加的,功能是可以查看对象的所有属性和值

方法二:通过类的初始化方法(构造方法 ) __init__方法

修改对象属性

p.pets = ["小花","小黑"]

p.pets = ["小花","小黑","小黄"] #新开辟一块地址,里面是["小花","小黑","小黄"]

p.pets.append("小黄") #在原地址上增加一个小黄

p.age = 10

p.age = 18

执行第二行代码时,又开辟了一块新内存放18,然后p.age去指向18,而不是在原来的地址上修改内容

删除对象属性

p.age = 18
del p.age

类属性

万物皆对象,类也是一个对象。

怎样让一个类拥有属性 ?

方法一:类名.类属性 =值

class Money:
    pass

Money.count = 1
print(Money.count)
print(Money.__dict__) #__dict__是系统内置的属性,功能是可以查看对象的所有属性和值(类也是对象)

方法二:直接在class Money:里面添加(更常用)

class Money:   # 类属性
    age = 18
    count = 1
    num = 666
    
print(Money.age)
print(Money.count)
print(Money.num)
print(Money.__dict__)

怎样查询一个类的属性?

方法一:通过类名.类属性Money.age这种方式来查询

方法二:用类实例化出来的对象也可以查询类的属性,对象.类属性

class Money:
    age = 18
    count = 1
    num = 666

one = Money()
print(one.age) #用Money实例化出来的one对象也可以查询Money类的属性
print(one.count)
print(one.num)

为什么可以通过对象访问到类属性 ?

答 :和Python对象的属性查找机制有关。优先到对象自身去查找属性,找到则结束。如果没有找到,则根据__class__找到对象对应的类,然后到这个类里面查找。

内存关系

怎样修改一个类的属性

方法一:通过类名来修改

class Money:
    age = 18
    count = 1
    num = 666
Money.age = 22

方法二:不能通过对象来修改类的属性 (不能!)

one.age = 40 这样是不能修改Money.age的,和查询不一样,查询是可以这样来查询到Money.age的。因为one.age = 40 相当于直接给one这个对象增加了一个age属性,值是40。

怎样删除一个类的属性?

通过类名删除,del 类名.属性

不能通过对象来删除!

属性的内存存储

通过one访问属性,其实访问的是__dict__字典里的值。一般情况下,属性存储在__dict__ 的字典当中,

有些内置对象没有这个__dict__属性。

的__dict__是只读的,不支持修改和赋值(可以通过setattr方法修改)。对象的__dict__是支持修改和赋值的。

class Money:
    age = 18
    count = 1
    num = 666
one = Money()
one.__dict__ = {"name":"Sz","age": 20}
print(one.name)  #输出是Sz

类属性被各个对象共享

类实例化了多个对象,这些对象都可以访问类属性,那么类属性只要一改,那所有对象访问的时候也都会跟着改变。

限制对象属性的添加__slots__

用了__slots__之后,类实例化出来的对象就不可以随便添加属性了,只能添加__slots__规定的属性。

class Person:
    __slots__ = ['age','height']
p1 = Person()
p1.age = 18
p1.height = 180
p2 = Person()
p2.age = 18
p2.height = 180

方法

方法是在描述一个目标的行为动作,调用时必须是 目标.方法 目标可以是对象,也可以是类。

class Person:
    def shilifangfa(self):  #self表示被调用时会接收一个实例本身,
                        #它也只是个形参,名字可以随便取的;其他还有参数的话写在后面就行了
        print("这是一个实例方法")

    @classmethod
    def leifangfa(cls):
        print("这是一个类方法")

    @staticmethod
    def jingtaifangfa():
        print("这是一个静态方法")

p = Person()

p.shilifangfa() #此时实例p传给了self
p.leifangfa()   #实例也可以调用类方法,只是传参数的时候会把实例对应的类传给第一个参数
Person.leifangfa()  #类 调用类方法
Person.jingtaifangfa()
p.jingtaifangfa()

方法的存储问题

实例方法、类方法、静态方法都存储在类的__dict__字典里面。万物皆可对象,函数也是个对象,也可以被当成字典的value。

实例方法

标准调用法:使用实例调用实例方法,解释器会自动把调用对象本身传递给第一个参数,也就是self。除了self,其他参数加在后面就行。

class Person:
    def eat(self,food):
        print("早饭吃"+food)

p =Person()
p.eat('包子')  #self参数不用管,会自动传进去的
#输出 早饭吃包子

其他调用(不常用):教程里讲的很清楚,有助于理解。本质就是找到函数的本身来调用,而不是以方法来调用。

类方法

类可以调用类方法;实例也可以调用类方法,只是传参数的时候会把这个实例对应的类自动传给第一个参数。

装饰器的作用:在保证原本函数不改变的前提下,直接给这个函教增加一些功能。

静态方法

类和实例都可以调用,解释器不会自动往里面传第一个参数。

不同类型的方法访问不同类型的属性

实例方法既可以访问实例属性,也可以访问类属性。因为实例本来就可以查询对应的类属性,但是类查询不了它的实例的属性。self会被传入实例,所以就是实例在访问属性。

class Person:
    age = 18
    def shilifangfa(self):
        print(self.age)
        print(self.height)

p =Person()
p.height = 188
p.shilifangfa()

元类(创建类对象的类)

万物皆可对象。

10,'abc'这些也都是实例化出来的对象,只不过它们对应的类是int和str。所以说像我们自己定义的类比如Person,它的级别和int、str其实是一样的。

int、str、Person这些类也是对象,也可以通过__class__找到它们对应的类,也就是元类type。

还可以通过type元类来创建类,比较高级的用法 教程

__init__方法

主要作用:当我们创建好一个实例对象之后,会自动的调用这个方法,来初始化这个对象,就不需要自己手动去添加一些实例属性了。

class Person:
    def __init__(self):
        self.age = 18 # 这样每次实例化一个对象之后都会自动调用这个实例方法,
                      # 然后创建一个实例属性age = 18,就不需要次次都自己手动添加了
p1 = Person()
P2 = Person()
p3 = Person()

super( ).__init__( )

super( )用来调用父类(基类)的方法,__init__( )是类的构造方法;super( ).__init__( ) 就是调用父类的init方法, 同样可以使用super( )去调用父类的其他方法。 super().__init__()_ 讲的很易懂

super().__init__()  或者 super(B,self).__init__()

分别理解super()和 __ init __()

super()

__ init __()

super(). __ init __()

如果子类B和父类A,都写了init方法,那么A的init方法就会被B覆盖。想调用A的init方法需要用super去调用。

有人可能会误解“覆盖”的意思,认为“覆盖”了就是没有,为什么还能通过super调用?

覆盖了并不是没有了,A的方法终都还在,但需要在B内部用super调用。

__setitem__,__getitem__,__delitem__方法

是一种索引方法,把对象当成像列表或者字典一样来索引,例如p[1]=666, p['name']="ysy"。对应中括号

class Person:
    def __setitem__(self, key, value):
        print("setitem",key,value)

    def __getitem__(self, item):
        print("getitem",item)

    def __delitem__(self, key):
        print("delitem",key)

p = Person()
p[1] = 255
p["name"] = 'ysy'
输出:
setitem 1 255
setitem name ysy

p[1] = 255,p["name"] = 'ysy' 当我们这么写语句的时候,它会自动调用__setitem__方法,[ ]里的是key,等于号后面的是value。是一种自动触发的方法。触发之后具体要实现什么就可以写在def的函数里了。

class Person:
    def __setitem__(self, key, value):
        print("setitem",key,value)

    def __getitem__(self, item):
        print("getitem",item)

    def __delitem__(self, key):
        print("delitem",key)

p = Person()
a = p['name']
输出:
setitem 1 255
setitem name ysy
getitem name

只要尝试去通过列表或者字典的形式去索引,就会自动触发__getitem__方法

综合运用:

class Person:
    def __init__(self):
        self.cache = {}

    def __setitem__(self, key, value):
        print("__setitem__被调用了")
        self.cache[key] = value

    def __getitem__(self, item):
        print("__getitem__被调用了")
        return self.cache[item]

    def __delitem__(self, key):
        print("__delitem__被调用了")
        del self.cache[key]

p = Person()
p[1] = 255
p["name"] = 'ysy'

print(p['name'])
del p[1]
输出:
__setitem__被调用了
__setitem__被调用了
__getitem__被调用了
ysy
__delitem__被调用了

__len__方法

class UseLen(object):
    def __init__(self, age):
        self.age = age
        self.li = ['a', 'v', 's']

    def __len__(self):
        return len(self.li)

U = UseLen(12)
print(len(U))

__call__方法

可以让实例像函数一样调用,比如p是个实例对象,本来p( )这么写是不行的,更别说( )还有参数了。但现在有了__call__方法,就可以这么做,一旦调用,自动触发__call__方法。对应圆括号。

class Person:
    def __call__(self, *args, **kwargs):
        print("哈哈", args, kwargs)

p = Person()
p(1, 2, 3, name = "ysy", a = 1)
输出:哈哈 (1, 2, 3) {'name': 'ysy', 'a': 1}
class Person:
    def __call__(self, name):
        print("call", name)

    def hello(self, name):
        print("hello", name)

p = Person()
p("zhangsan")  # 其实等价于p.__call__("zhangsan")
p.hello("lisi")

staticmethod静态方法的用法

在开发的时候, 可以使用类对方法进行封装,如果某一个方法需要访问到对象的实例属性,可以把这个方法封装成一个实例方法。如果某一个方法不需要访问对象的实例属性,但是需要访问到类的类属性,这个时候就可以考虑把这个方法封装成一个类方法。一个实例方法, 一个类方法,这是两种方法类型,但是在开发中还有一种情况,如果要封装的某一个方法,既不需要访问到对象的实例属性,也不需要访问类的类属性,这个时候就可以考虑把这个方法封装成一个静态方法。 静态方法staticmethod用法

在开发中,如果类中的某个方法既不需要访问实例属性或者调用实例方法,同时也不需要访问类属性或者调用类方法,这个时候就可以把这个方法封装成静态方法。需要在def关键字上方增加一个静态方法的修饰符,@staticmethod。

静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls )。

静态方法能够通过实例对象和类对象去访问。取消了不需要的参数传递 ,有利于减少不必要的内存占存和性能消耗。

class Dog(object):
    @staticmethod
    def info_print():
        print('这是⼀个狗类,⽤于创建狗实例....')

wangcai = Dog()
# 静态⽅法既可以使⽤对象访问⼜可以使⽤类访问
wangcai.info_print()
Dog.info_print()

class Static(object):
    @staticmethod
    def test_static():
        print('I am staticmethod')
 
    def test_def(self):
        print('I am not staticmethod')
 
#  调用静态方法
Static.test_static()
#  实例化调用静态方法
obj = Static()
obj.test_static()

这套教程我看到这里就没再往下看了。标记点

私有化属性

公有属性:

全部可以访问

私有属性_y

只加一个下划线的私有属性,除了最后一个在其他python文件中用from module import *这种形式导入并且没有用__all__指明对应变量外,其他情况都可以被调用,只不过有可能警告,但是还是能调用。

如果用__all__指明对应变量,那就可以被其他模块用from所调用。 __all__ = [ "_y"]

私有属性__z

在跨模块访问时,__z和_z的效果一样。

不管是_y还是__y这种私有属性,都必须写在类的内部才有用,写在外面(包括写在实例里)都是没用的(不能被实例对象调用)。因为写在类内部,解释器会自动改名成_类_y和_类__y,假如你在实例中这么写p1.__age = -1,其实根本没有修改对应的私有属性__age,因为人家已经被改名成了_Person__age,你这么写只会新增一条__age实例属性。

所以想访问或者修改__age私有属性,只能在类里面写方法来访问或者修改。

继承

继承教学

class Animal:
    pass

class Dog(Animal):
    pass
### RT-DETRv3 网络结构分析 RT-DETRv3 是一种基于 Transformer 的实时端到端目标检测算法,其核心在于通过引入分层密集正监督方法以及一系列创新性的训练策略,解决了传统 DETR 模型收敛慢解码器训练不足的问题。以下是 RT-DETRv3 的主要网络结构特点: #### 1. **基于 CNN 的辅助分支** 为了增强编码器的特征表示能力,RT-DETRv3 引入了一个基于卷积神经网络 (CNN) 的辅助分支[^3]。这一分支提供了密集的监督信号,能够与原始解码器协同工作,从而提升整体性能。 ```python class AuxiliaryBranch(nn.Module): def __init__(self, in_channels, out_channels): super(AuxiliaryBranch, self).__init__() self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1) self.bn = nn.BatchNorm2d(out_channels) def forward(self, x): return F.relu(self.bn(self.conv(x))) ``` 此部分的设计灵感来源于传统的 CNN 架构,例如 YOLO 系列中的 CSPNet PAN 结构[^2],这些技术被用来优化特征提取效率并减少计算开销。 --- #### 2. **自注意力扰动学习策略** 为解决解码器训练不足的问题,RT-DETRv3 提出了一种名为 *self-att 扰动* 的新学习策略。这种策略通过对多个查询组中阳性样本的标签分配进行多样化处理,有效增加了阳例的数量,进而提高了模型的学习能力泛化性能。 具体实现方式是在训练过程中动态调整注意力权重分布,确保更多的高质量查询可以与真实标注 (Ground Truth) 进行匹配。 --- #### 3. **共享权重解编码器分支** 除了上述改进外,RT-DETRv3 还引入了一个共享权重的解编码器分支,专门用于提供密集的正向监督信号。这一设计不仅简化了模型架构,还显著降低了参数量推理时间,使其更适合实时应用需求。 ```python class SharedDecoderEncoder(nn.Module): def __init__(self, d_model, nhead, num_layers): super(SharedDecoderEncoder, self).__init__() decoder_layer = nn.TransformerDecoderLayer(d_model=d_model, nhead=nhead) self.decoder = nn.TransformerDecoder(decoder_layer, num_layers=num_layers) def forward(self, tgt, memory): return self.decoder(tgt=tgt, memory=memory) ``` 通过这种方式,RT-DETRv3 实现了高效的目标检测流程,在保持高精度的同时大幅缩短了推理延迟。 --- #### 4. **与其他模型的关系** 值得一提的是,RT-DETRv3 并未完全抛弃经典的 CNN 技术,而是将其与 Transformer 结合起来形成混合架构[^4]。例如,它采用了 YOLO 系列中的 RepNCSP 模块替代冗余的多尺度自注意力层,从而减少了不必要的计算负担。 此外,RT-DETRv3 还借鉴了 DETR 的一对一匹配策略,并在此基础上进行了优化,进一步提升了小目标检测的能力。 --- ### 总结 综上所述,RT-DETRv3 的网络结构主要包括以下几个关键组件:基于 CNN 的辅助分支、自注意力扰动学习策略、共享权重解编码器分支以及混合编码器设计。这些技术创新共同推动了实时目标检测领域的发展,使其在复杂场景下的表现更加出色。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值