Python 类学习总结

1. 类中方法

        在python中,类中方法包括多种,其中有:“魔法”方法普通(公有)方法私有方法类方法静态方法

        “魔法”方法: 形式是:__***__(),如:__init__(self)、__str__(self, *args, **kwargs)等自带的方法,该方法只能通过对象调用,如果不重写,则调用时默认使用自带的实现,例如:

class Test():
    #构造方法
    def __init__(self):  #1
        print("test_init")

if __name__ == "__main__":
    print(Test().__str__())  #2

输出:
<__main__.Test object at 0x0000015D7D7B30B8>

                                                                                         第一段代码

       调用魔法方法__str__输出是一串地址,其实__str__方法实现默认的是返回str(self),因此print(Test().__str__())和print(str(Test()))返回结果是一样的,如下所示。

class Test():
    #构造方法
    def __init__(self):  #1
        return

if __name__ == "__main__":
    print(Test().__str__())  #2
    print(str(Test()))

输出:
<__main__.Test object at 0x0000023FBAA23080>
<__main__.Test object at 0x0000023FBAA23080>

                                                                                          第二段代码

        需要注意的一个概念是,在上述代码中#1的__init__(self)为类的构造方法,而self表示的是对象本身,就如同java中隐式的this,该形参必须存在(当然名字可以不需要使用self, 并非强制要写为self),可以这么理解:把self当成方法的形参,但是该形参对应的实参必须是对象名,如果不显性对该形参传入实参,则默认传入的实参是引用方法的对象;如果显性对该形参传入实参,则需要传入的实参是对象名,但是引用方法时采用的是类名进行引用,以魔法方法__str__为例,其原型是__str__(self),举例如下所示。

class Test():
    #构造方法
    def __init__(self):
        return

if __name__ == "__main__":
    #显性声明一个对象
    test = Test()
    #类名Test引用方法,但是将对象名test作为实参传入
    print(Test.__str__(test))
    #对象名引用方法,不需要显性传实参,默认引用对象传入
    print(test.__str__())

                                                                                       第三段代码

       需要注意的另外一个概念是,在上述第一段和第二段代码中#2号注释,采用的是隐形声明对象(可理解为匿名对象),其与第三段代码中显性声明test对象,然后在引用魔法__str__()不同的是,第一段代码和第二段代码中省略了显性声明对象的步骤,直接采用:类名().方法 的形式引用方法。

       魔法方法如果被重写,输出的将是重写后的结果,以__str__()为例,如下所示(构造方法__init__也被重写了,如果不重写将输出None)。

class Test():
    #构造方法
    def __init__(self):
        return
    def __str__(self):
        return "test_str"

if __name__ == "__main__":
    print(Test().__str__())

输出:
test_str

       是否好奇这些魔法方法是哪里来的?明明在新建Test类时,没有看到魔法方法,其实在python 3.x中,每个类在创建时,默认继承了object类,显性继承object类与非显性继承都是一样的,但是在python 2.x时,显性和非显性继承object类还是有差异的,其默认的魔法方法有区别,而python 3.x没有差异了,如下所示。

python 3.x
显性继承object类:
class Test(object):
    def testPrint(self):
        print("test")

if __name__ == "__main__":
    print(dir(Test))

输出:
#其中testPrint属于普通实现方法,其他的都是继承object得到的魔法方法。
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'testPrint']

非显性继承object类:
class Test:
    def testPrint(self):
        print("test")

if __name__ == "__main__":
    print(dir(Test))

输出:
#输出结果与显性继承object类一样

python 2.x
显性继承object类
class Test(object):
    def __init__(self):
       print("test_init")

        
print dir(Test)

输出:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']


非显性继承object类
class Test:
    def __init__(self):
        print("test_init")

        
print dir(Test)

输出:
['__doc__', '__init__', '__module__']

       普通(公有)方法:形式为def publicMethod(self, ***),至少有一个self,所以方法只能由对象调用,如果采用类名调用,需要显性通过以对象名作为实参传入,例如:

class Test():
    #构造方法
    def __init__(self):
        return
    def __str__(self):
        return "test_str"
    #公有方法,由对象调用,如果类名调用,需要通过显性传入对象名作为实参
    def publicMethod(this):
        return "publicMethod"

if __name__ == "__main__":
    test = Test()
    print(test.publicMethod())
    print(Test.publicMethod(test))

输出:
publicMethod
publicMethod

       私有方法:形式为def __privateMethod(self, ***),在公有函数名前加入两条下划线__,需要区别“魔法”方法,在私有函数名后并没有两条下划线,该方法只能在类的内部能被调用,在类外是不可见的。如果类被继承,其私有方法不可被继承。如果需要使用私有方法,则可通过公有方法进行封装,对外部进行可见,例如:

class Test():
    #构造方法
    def __init__(self):
        return
    def __str__(self):
        return "test_str"
    #公有方法,由对象调用,如果类名调用,需要通过显性传入对象名作为实参
    def publicMethod(this):
        return "publicMethod"
    #私有方法,只能在类中调用
    def __privateMethod(self):
        return "privateMethod"
    def getPrivateMethodContext(self):
        return self.__privateMethod()

if __name__ == "__main__":
    test = Test()
    print(test.getPrivateMethodContext())

输出:
privateMethod

       类方法:形式为def classMethod(cls),该方法直接通过类名进行调用(需要在函数名上加一个@classmethod方可被类名调用,因为在上文中提起类中方法self可以使用其他命名,那么也就是说并非self不可,所以如果self改成cls是否也可以,那么编译器如何识别方法由类可以调用,那么就通过@classmethod进行区分),也可通过对象名调用,例如:

class Test():
    #通过classmethod来使得编译器认识该方法是类方法
    @classmethod
    def classMethod(cls):
        return "classMethod"

if __name__ == "__main__":
    test = Test()
    print(Test.classMethod())
    print(test.classMethod())

输出:
classMethod
classMethod

       静态方法:形式为def staticMethod(***),该方法与其他方法一样,并不需要self,但是需要在方法名上加上@staticmethod使得编译能认识该方法,该方法可直接通过类名或对象名调用,例如:

class Test():
    @staticmethod
    def staticMethod(name):
        return "staticMethod " + name
    @classmethod
    def classMethod(cls):
        return "classMethod"

if __name__ == "__main__":
    test = Test()
    print(Test.staticMethod("can incoming argument"))
    print(test.staticMethod("can incoming argument"))

输出:
staticMethod can incoming argument
staticMethod can incoming argument

2. 类中属性

       在类中可有:类属性对象属性私有属性三种属性之分。

       类属性:该属性属于类所有,可直接通过类名进行引用,也可通过对象名进行引用。类属性修改可通过类名在类外引用进行修改,但是不要试图通过对象名引用去修改类属性,如果通过对象名修改类属性,则会创建一个与类属性同名的对象属性,此时同名的类属性和对象属性存储地址不一样,例如:

class Test():
    classAttribute = 0


if __name__ == "__main__":
    test = Test()
    print("输出未修改类属性值的类属性地址:")
    print("类名引用类属性的内存地址:"+ str(id(Test.classAttribute)))
    print("对象名引用类属性的内存地址:"+ str(id(test.classAttribute)))
    Test.classAttribute = 1
    #并没有对象属性classAttribute,此时通过对象引用类属性进行修改
    test.classAttribute = 2
    print("输出修改类属性值的类属性的值和地址:")
    print("类属性值:" + str(Test.classAttribute), "内存地址:"+ str(id(Test.classAttribute)))
    print("对象属性值:" + str(test.classAttribute), "内存地址:"+ str(id(test.classAttribute)))

输出:
输出未修改类属性值的类属性地址:
类名引用类属性的内存地址:140724108055552
对象名引用类属性的内存地址:140724108055552
输出修改类属性值的类属性的值和地址:
类属性值:1 内存地址:140724108055584
对象属性值:2 内存地址:140724108055616

        对象属性:该属性只能通过对象进行引用,通过构造函数__init__(self, ***)进行初始化,在构造函数中通过self进行引用的属性就是对象属性(注:很多情况下会看到对象属性与构造函数的形参名一样,其实只是命名问题,并不需要名字是一致的),并通过创建对象时进行对对象属性赋值,例如:

class Test():
    classAttribute = 0
    def __init__(self, name, ageAttribute):
        #两个名字一致只是命名习惯而已
        self.name = name
        #对象属性无需跟构造函数__init__中形参名一致
        self.age  = ageAttribute

if __name__ == "__main__":
    #通过创建对象时初始化对象属性的值,self不需要显性传参
    test = Test("python_3", 10)
    print(test.name, test.age)

输出:
python_3 10

3. 类的继承

发布了42 篇原创文章 · 获赞 86 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_33206497/article/details/97829237