Python从入门到放弃(3)-python中的类

Posted by 高庆东 on November 5, 2019

类的由来

在python中所有都是对象和类,所有类的基类都是object ,object是type类的实例,type也是object的子类

类介绍

类作为python最核心的东西,贯穿了所有代码,不论是函数,变量统统都是类对象,python中的int,float,list等等都是对象,都有一些方法
和属性,这些特殊属性和方法上一章介绍。 对于一个变量 我们可以观察他的类型确定它包含的属性和方法。在python中所有的东西都是object的子
类,所谓子类就是继承了object父类而实现的类
类同时也是type类的实例,我们定义的类都是type类的实例

a=[1,2,3]
print(isinstance(a,object))
help(a)#查看a对象所包含的所有说明,当对象中有r```help显示部分 ```,这个时通过help()会显示r后面的部分

类的创建和函数创建一毛一样,调用的时候也一求样,两中主要的方式,一是加括号二是不加括号。
在函数中我们不加括号表示对函数重命名,可以使用重命名的函数继续执行,类如果不加括号表示类自身的调用。

#首先是函数
def fun(a):
    print(a)
    #注意一个函数中没有属性,不可以通过`.`的方式对函数进行操作
fun(1)
#结果: 1
a=fun
#结果:fun被重命名

#类
class cla():
    print(123)
    x=10
    def fun(self,x):
        print(x)
cls=cla()
cls.fun(2)
#结果:2
cls=cla   #类自身其中的函数可以通过这种方式调用,同时self会被看成一个参数
#结果:123 

类的私有属性

在类中某些变量或者方法只能在类内部使用创建这样的方式是在名字前加__两下划线
私有属性只能被self访问。继承的外部实例的对象都无权访问,只要变量加了__

class a():
    def __init__(self):
        self.aa=1
        self.__ba=2
    def p(self):
        print(self.__ba)
a().p() #可以设定某个函数修改私有属性

类的创建

创建一个类首先是继承object类,默认都是继承了的,我们要区分开类自身和类对象,同时类的初始化,和类中的装饰器也需要明确。首先确定类名,我
经常犯的错是将 关键字class 写成def 同时需要加空格。一个类写好后需要类的初始化,初始化说的是类对象初始化,当类没有实例化的时候,无
所谓初始化,初始化函数是__init__()。 我们要区分开类自身和类对象。 类自身就是类当前的样子,类对象是类初始化后的类。

class test(): #创建类
    def a(x):
        print(123)
        
test.a(2)  #类自身,调用的时候和直接用。类自身中的函数如同外部函数
#结果:123

test().a() #类对象,类后加()表示实例化类,类对象中的方法,第一个参数必须是类对象自己。也就是x表示类对象,通常使用self表示
#结果:123

类中的属性也是如此,类对象和类自身有区别

class test():
    a=1
    def __init__(x):  #当实例化类后,x和self一样
        x.a=2
print(test().a) #类对象,实例化就是产生类对象,类对象默认首先执行`__init__()`,其他函数不执行,只执行这个
#结果:2
print(test.a) #类自身
#结果:1

当需要调用类对象的方法时,该方法传入的第一个参数必须时类自身也就是self,而使用类自身的方法时就没有这个限制,当我们创建类后,根据
实际问题来制定某些方法作为类自身或者类对象的方法,可以使用某些装饰器,来实现这个过程。
在类中的方法,在使用类对象时,不论方法中的第一个参数是啥都表示类自身,即使两个方法中第一个参数不一样

class fun():
    w=1
    def f1(self):
        self.w=10
        print("f1")
    def f2(cls,x):   #f1和f2中第一个参数都表示类自身虽然不一样
        print(x)
        print(cls.w)
func=fun()
func.f1()
func.f2(2)
#结果:1,2

类继承

类继承作作为类最重要的特性经常用在pytorch各个部分,比如在构建模型时,必须继承nn.Modules模块,同时继承super()__init__()它中
的初始化方法,同时也需要复写某些函数如forward()
类继承就是继承之前类类中的所有东西,包括类自身和对象的方法和属性

class A(object):
    x=1
    def __init__(self):     #self表示类对象初始化的方法,必须由slef                                     
        print("213")                    #创建类要加·
    def a(self):
        print(1) 
    def b(self):
        self.a()
        print(123)
class B(A):      #继承A类
    def __init__(self):                                         
        print("111") 
    def a(self):
        print("fuck a")
print(B.x) #继承A类中类自身的属性
#结果:1 

B() #B中复写了初始化
#结果:'111'
B().b() #B继承了A中的b()方法 ,虽然b方法在A中是调用A中的a方法,但是当B继承时,我们只看B的方法。不去考虑A,相当于把A的方法全部
        #复制到B中然后再B中进行修改。
       
#结果:123 "fuck a"

@staticmethod装饰器

这个装饰器可以让方法变成类方法不是对象方法

class A():
    def __init__(self):
        self.a=1
        self.b=2
    @staticmethod
    def prin():
        print(self.a)
        print(self.b)
 A.prin() #是错误的因为在prin方法中不能使用self也就是类对象

类的表面继承

当类实现继承后只是表面继承没有继承类对象的属性,只继承了类属性和方法。类对象和类都可以调用类属性

class Fu(object):
    a=3
    def __init__(self,a=1):
        self.a=a
    def fu(self):
        print(self.a)
        
class Zi(Fu):   #继承了类父类的方法和类变量a 没有继承self.a
    def __init__(self,a=2):
        pass
        
Zi().fu()
#结果:3
Zi().a #结果3
Fu().a #结果1  #没有继承类对象的方法
Fu.a   #结果3

类的表面继承体现在使用super上,当需要使用类对象的方法或属性时时子类可以通过super实现

class B(object):
    def __init__(self):
        pass
    def test_1(self):
        self.x=12
class A(B):
    a = 0
    b = 1
    def __init__(self):
        self.a = 2
        self.b = 3
    def test_1(self):
        super(A,self).test_1()  #当重写父类方法的时候我们可以使用super将原始父类方法内容全部拿过来
        print(321)   
    def test(self):
        print ('a normal func.')
    @staticmethod
    def static_test(self):
        print( 'a static func.')
    @classmethod
    def class_test(self):
        print ('a calss func.')
print (A.__dict__)   #查看类的所有成员
print('**')
print (A().__dict__)  #查看类对象的属性不看方法

有些特殊量在继承中是不会传递的__dict__

这个表示的是类和对象的广义属性,分为类自身的__dict__和对象的__dict__,通过
.__dict__来查看属性,在继承过程中子类有子类的__dict__父类有父类的__dict__
互不影响,这是针对类自身来说,当我们查看类对象的时候。查看类对象的__dict__会发现继承
发生了

class A():
    w=2
    def __init__(self):
        self.w=1
        self.r=2
    def a(self):
        print(123)

class B(A):
    def b(self):
        print(456)
B().__dict__
### mappingproxy是python的一种数据结构

多继承

可以有多个父类,可以实现多重继承

class A():
    def __init__(self):
        self.a=2
    def __getattr__(self,key):
        return 123
class B():
    def b(self):
        print(1233)
class C(A,B):
    def c(self):
        print(456)
dir(C) ## c查看类所有的方法,也可以看对象的

类中属性的修改

我们需要修改类中属性时可以使用setattr(class,name,value)

class test(object):
    def __init__(self):
        pass
    def fun(self):
        self.x=3
setattr(test,'w',3)
te=test()
te.w
#结果:3

类中方法的使用

当我们使用类中的方法时,该方法的定义必须包含self关键字,也就是类自身,再实例化的类调用
时使用,当没有self参数时,使用实例化的类调用该方法会报错,除非再方法上加上@staticmethod
装饰器

装饰器

非常简单,装饰器是个函数,这个函数的参数是一个函数,也就是我们被装饰的函数,
这里有个问题,在python中函数到底是什么,在python中所有都是类和对象,需要理解这个,