一个小白的网安学习之路之Python入门五:Python面向对象(函数、类、封装继承多态、模块)

Python面向对象

函数

函数的调用和创建

  • 函数的创建:

    def calc():
        c = 1+2
        print(c)
    
  • 函数的调用

    result = calc(3,6)
    print(result)
    

函数的参数调用

  • 位置实参

    在这里插入图片描述

  • 关键字实参

    在这里插入图片描述

  • 调用参数时,若传递值,则函数内的改变不影响原参数值;若传递列表,则追加操纵会改变原列表的值

    #可用以下代码验证
    def fun(arg1, arg2):
           print (' arg1=', arg1)
           print (' arg2=' , arg2)
           arg1=100
           arg2[1] = 55
           print (' arg1=', arg1)
           print(' arg2=', arg2)
    n1=11
    n2=[22,33,44]
    print(n1)
    print(n2)
    print('------')
    fun(n1, n2)
    print(n1) #11
    print(n2) #[22, 55, 44]
    

函数的默认参数

  • 函数定义时,可以给形参设置默认值,只有与默认值不符的时候才需要传递实参

    在这里插入图片描述

个数可变的参数

  • 个数可变的位置参数

    定义函数时,可能无法事先确定传递的位置实参的个数时,使用可变的位置参数

    使用*定义个数可变的位置形参

    结果为一个元组

    def func(*abc):  #可变的位置参数
        print(abc)
    
    func(10) #(10,)
    func(10,20,30) #(10,20,30)
    
  • 个数可变的关键字形参

    定义函数时,无法事先确定传递的关键字实参的个数时,使用可变的关键字形参

    使用**定义个数可变的关键字形参

    结果为一个字典

    def func1(**args): #个数可变的关键字形参
        print(args)
        
    func1(age=10) #{'age':10}
    func1(age=10,name='james') #{'age':10,'name':'james'}
    

变量的作用域

  • 局部变量

    在函数内定义并使用的变量,只在函数内部有效,局部变量使用global严明,这个变量就会就成全局变量

  • 全局变量

    函数体外定义的变量,可作用于函数内外

函数的返回值

  • 函数返回多个值时,结果为元组

    def fun(num):
        odd=[]#存奇数
        even=[]#存偶数
        for i in num:
            if i%2:
                odd.append(i)
            else:
                even.append(i)
        return odd, even
    
    lst = [10,29,34,23,44,53,55]
    print (fun(lst)) #([29, 23, 53, 55], [10, 34, 44])
    
    

递归函数

  • 什么是递归函数

    如果在一个函数的函数体内调用了该函数本身,这个函数就称为递归函数

  • 递归的调用过程

    每递归调用一次函数,都会在栈内存分配一个栈帧

    每执行完一次函数,都会释放相应的空间

    #计算阶乘
    def func(n):  #n=4--n=3--n=2--n=1
        if n == 1:
            return 1
        else:
            result = n * func(n-1) 
            return result
    
    print(func(4))
    

类的创建

  • 类的组成:类属性、实例方法、静态方法、类方法

    class Student:
        #类属性
        name = 'James'
        age = 18
    
        #实例方法
        def eat(self):
            print('James能干3碗饭')
        def calc(self): #self固定写法,不要问为什么 
            print(1+2)
        def __init__(self,name1,age1): #用于生成和初始化类属性,name、age1在这里已经是属性了
            self.name1 = name1 #self.name 实体属性,赋给实体属性
            self.age1 = age1
    
        #静态方法
        @staticmethod
        def method():
            #无法访问类或实例属性
            print('我使用staticmethod对方法进行了修饰, 所以我是静态方法')
    
        #类方法
        @classmethod
        def classmethod(cls):#cls表示类本身
            #可以访问类属性
            print('我是类方法, 因为我加@classmethod进行修改')
    

对象的创建

  • 对象的创建又称为类的实例化

  • 语法:实例名=类名()

    #创建出来的对象
    stu1 = Student('李四', 20) #参数会复制给类的实例方法中__init__(self,name1,age1)方法
    
    print(stu1) #打印类的地址
    
  • 类属性和实例方法的调用

    stu1.eat()
    stu1.calc()
    print(stu1.name1)
    print(stu1.age1)
    

类属性、类方法、静态方法

  • 类属性:类中方法外的变量称为类属性,被该类的所有对象所共享

  • 类方法:使用@classmethod修饰的方法,使用类名直接访问的方法

  • 静态方法:使用@staticmethod修饰的主法,使用类名直接访问的方法

    print(Student.native_place)#访问类属性
    
    Student.sm() #调用静态方法
    
    Student.cm() #调用类方法
    
    • 实例方法和类级别的属性、方法、静态方法的区别是:使用类级别的属性、方法、静态方法不需要创建对象即可调用,使用实例方法必须要创建对象。
    • 类属性和对象属性是一个关系是:共性和个性的关系
    • 静态方法和类方法的区别是:静态方法不可以访问类或静态属性,类方法可以访问类属性

对象可以动态创建属性和方法

  • Python是动态语言,在创建对象之后,可以为某对象动态地创建属性和方法。但是该属性和方法是该对象专属,而不是创建给类的。这个功能体现了对象的定制化。

    #定义一个类--学生类
    class Student:
    
        #定义吃饭这个行为
        #实例方法
        def eat(self):
            print('James能干3碗饭')
    
        def __init__(self,name,age):
            self.name = name #self.name 实体属性,赋给实体属性
            self.age = age
    
    stu1 = Student('James', 30)
    stu2 = Student('Kate', 26)
    
    
    print('----stu1对象动态绑定属性-------')
    stu1.address = 'changsha' #类没有该属性,但可为该对象动态添加专属属性
    print(stu1.name, stu1.age,stu1.address)
    #print(stu2.name, stu2.age,stu2.address)  虽然创建了属性,但没有给stu2创建,stu2没有address,会报错
    
    print('----stu2对象动态绑定方法-------')
    def playBall():
        print('定义在类的外面,叫函数')
    stu2.playBall = playBall
    stu2.playBall() #给stu2创建了专属对象方法
    #stu1.playBall() #报错,stu1没有拓展该方法
    

浅拷贝和深拷贝

变量的赋值
  • 只是形成两个变量,实际上还是指向同一个对象

    class Father:
        pass
    class Mother:
        pass
    
    class Family:
        def __init__(self,father, mother):
            self.father = father
            self.mother = mother
    
    #变量的赋值
    fa1 = Father()
    fa2 = fa1 #赋值操作使f1和f2指向相同的地址块,当其中某个属性或方法改变时,才创建新的地址块
    print(fa1, fa2)
    
浅拷贝
  • Python拷贝一般都是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象。

  • 也即:拷贝对象和被拷贝的对象是同一块空间。只有其中一个改变时,才会开辟新的空间

    fa1 = Father()
    mo1 = Mother()
    family = Family(fa1,mo1) #创建一个家庭对象, 家庭对象的属性有真实存在的爸 妈对象
    
    #浅拷贝
    import copy
    family2 = copy.copy(family) #family和fanily2是同一个对象,father和mother也是一样的
    print(family, family.father, family.mother)
    print(family2, family2.father, family2.mother)
    
深拷贝
  • 使用copy模块的deepcopv函数﹒递归地对对象和对象的所有子对象进行拷贝。

  • 也即:拷贝对象和被拷贝对象的对象不是同一块地址空间,在深拷贝时,就创建了一块新的地址用于存放拷贝对象

    #深拷贝
    import copy
    family3 = copy.deepcopy(family)
    print(family, family.father, family.mother)
    print(family3, family3.father, family3.mother)
    

面向对象的三大特征

封装

  • 封装:提高程序的安全性

  • 在Python中没有专门的修饰符用于属性的私有,如果该属性不希望在类对象外部被访问,前边使用两个“_”。

    #定义一个类--学生类
    class Person:
    
        def __init__(self,name,age):
            self.name = name #self.name 实体属性,赋给实体属性
            self.__age = age #私有属性
        def study(self):
            print('开始学习了, James今年'+str(self.__age)+'岁')
    
    james = Person('James', 30)
    james.study() #__age私有属性封装在study()内部,保护了数据的安全
    
    print(james.name) #可以通过对象直接访问公共属性
    #print(james.__age) #但不可以通过对象访问私有属性
    
    #那么如何访问呢?
    #在类的外部使用 __age
    print(dir(james)) #['_Person__age',……
    
    print(james._Person__age) #通过这个方式可以访问
    

继承

继承的定义
  • 继承:提高代码的复用性

    • 如果一个类没有继承任何类,则默认继承object

    • 定义子类时,必须在其构造函数中调用父类的构造函数

    • 语法格式:

      ​ class 子类类名(父类1,父类2…) :

      ​ pass

    class Person(object): #默认object
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def info(self):
            print(self.name, self.age)
    
    #定义子类时,必须在其构造函数中调用父类的构造函数
    class Student(Person):
        def __init__(self, name, age, stu_no):
            super().__init__(name, age) #super表示直接调用其父类__init__
            self.stu_no = stu_no
    
    class Teacher(Person):
        def __init__(self, name, age, address):
            super().__init__(name, age) #super表示直接调用其父类__init__
            self.address = address
    
    stu = Student('James', 30, '999')
    stu.info()
    
    teacher = Teacher('Kate', 34, 'changsha')
    teacher.info()
    
多继承
  • Python支持多继承

    #多继承
    class A(object):
        pass
    class B(object):
        pass
    
    class C(A, B):
        pass
    
方法重写
  • 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写

  • 子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法

    class Person(object): #默认object
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def info(self):
            print(self.name, self.age)
    
    class Student(Person):
        def __init__(self, name, age, stu_no):
            super().__init__(name, age) #super表示直接调用其父类__init__
            self.stu_no = stu_no
        #父类的info方法满足不了子类, 子类按自己的需求对info二次重写
        def info(self):
            super().info()
            print(self.stu_no)
    
    class Teacher(Person):
        def __init__(self, name, age, address):
            super().__init__(name, age) #super表示直接调用其父类__init__
            self.address = address
    
    stu = Student('James', 30, '999')
    stu.info()
    
类的祖宗object类
  • object类是所有类的父类,因此所有类都有object类的属性和方法。

  • 内置函数dir()可以查看指定对象所有属性

  • Object有一个__str__()方法,用于返回对象的地址

    class Student:
        def __init__(self, name ,age):
            self.name = name
            self.age = age
    
        def __str__(self): #重写object父亲__str__
            return '我的名字叫{0}, 我的年纪{1}'.format(self.name,self.age)
    stu = Student('james', 18)
    print(dir(stu)) #可以查看指定对象的所有属性
    print(stu) #打印对象时,默认调用对象的__str__()函数,打印对象地址。重写__str__()后,打印对象时,打印重写内容。'我的名字叫{0}……'
    

多态

多态的定义
  • 多态:提高程序的可扩展性和可维护性

  • 简单地说,多态就是“具有多种形态",它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法。

    class Animal(object):
        def eat(self):
            print('动物会吃东西')
    
    class Dog(Animal):
        def eat(self):
            print('狗吃肉')
    
    class Cat(Animal):
        def eat(self):
            print('猫吃老鼠')
    
    class Person(object):
        def eat(self):
            print('人吃饭')
    
    
    def fun(obj):
        obj.eat()
    
    fun(Cat()) #省略了cat=Cat(),的变量定义操作,传入了Cat(),则默认使用Cat()中的eat方法
    fun(Dog())
    fun(Person())
    

    个人理解,多态是重写的应用

静态语言与静态语言
  • 静态语言实现多态的三个必要条件
    • 继承
    • 方法重写
    • 父类引用指向子类对象
  • 动态语言的多态崇尚“鸭子类型"当看到一只鸟走起来像鸭子、游泳起来像鸭子、收起来也像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象是什么类型,到底是不是鸭子,只关心对象的行为。

Python的特殊属性与特殊方法(了解)

  • __dict__、__len__()、__add__()、__new__()、___init__()

    在这里插入图片描述

  • __dict__

    class A:
        pass
    class B:
        pass
    class C(A,B):
        def __init__(self, name , age):
            self.name = name
            self.age = age
    
    
    obj = C('james', 18)
    print(obj.__dict__) #输出obj对象有哪些属性参数
    print(C.__dict__)
    
    print(obj.__class__) #obj由C类创建的
    print(C.__bases__) #C类所有的父类
    print(C.__base__) #打印离C最近的父类
    print(C.__mro__) #打印C类所有的继承关系
    
  • __add__()、__len__()

    #先讲__add__()
    a = 1
    b = 2
    c = a+b #a+b实际上调用的是a.__add__(b)
    cc = a.__add__(b)
    print(c)
    print(cc)#c与cc相同
    
    class Teacher:
        def __init__(self, name):
            self.name = name
        def __add__(self, other):#重写__add__()方法
            return self.name+other.name
        def __len__(self):#重写__len__()方法
            return len(self.name)
    
    t1 = Teacher('James')
    t2 = Teacher('Kate')
    
    s = t1+t2 #t1和t2指向的是对象的内存地址,地址相加没有意义,我们的目的是让两个对象的字符串相加,那么我们就需要通过重写object类的__add__()方法达到此效果
    ss = t1.__add__(t2)
    print(s)
    print(ss)
    
    #再讲__len__()
    lst = [1,2,3,4,5]
    print(len(lst)) #len()实际上是调用__len__()方法
    print(lst.__len__())
    
    print(len(t1)) #对于t1这个对象,无法使用len(),则可以通过重写__len__()方法,让内置函数的len()方法的参数可以是任意类型
    
  • __init__()

    class Student(object):
        def __new__(cls, *args, **kwargs): #__new__()该方法下面的过程会在父类Object中自动重写
            print('__new__方法被调用,cls的id值{0}'.format(id(cls)))  #相当于类对象Student
            obj = super().__new__(cls) #创建一个真实的对象 obj = Student()
            print('obj 对象被创建出来后, id值{0}'.format(id(obj)))  #相当于真实对象
            return  obj
        def __init__(self, name, age): #这里self的作用就是把obj传进来,所以id和obj是一样的
            print('__init__被调用, self对象的id值{0}'.format(id(self)))
            self.name = name
            self.age = age
    obj = Student('James', 18)
    print('obj对象的id值{0}'.format(id(obj)))
    

    __new__()讲解:

    • 是静态方法,第一个参数必须是cls
    • 所有对象实例的诞生都必须经过__new__()创建对象–>__init__()初始化对象
    • 重写__new__()之后必须调用super.__new__()

模块

模块的定义

  • 一个模块中可以包含N多个函数。在Python中一个扩展名为.py的文件就是一个模块。

模块的好处

  • 方便其它程序和脚本的导入并使用
  • 避免函数名和变量名冲突
  • 提高代码的可维护性
  • 提高代码的可重用性

模块的导入

  • 创建模块
    新建一个.py文件,名称尽量不要与Python自带的标准模块名称相同导入模块

  • 导入模块

    • import 模块名称 [as别名]
    • from 模块名称 import 函数/变量/类
    #导入自带模块
    #import math
    from math import pi,pow,ceil,floor
    print(pi)
    
    #自定义模块calcDemo.py
    def add(a,b):
        return a+b
    def reduce(a,b):
        return a-b
    
    #导入自定义模块calcTestModel
    import calcDemo
    print(calcDemo.add(1,4))
    print(calcDemo.reduce(6,2))'''
    
    from calcDemo import add,reduce
    print(add(1,4))
    print(reduce(6,2))
    

如何以主程序模式运行模块

  • 在每个模块的定义中都包括一个记录模块名称的变量__name__,程序可以检查该变量,以确定他们在哪个模块中执行。

  • 如果一个模块不是被导入到其它程序中执行,那么它可能在解释器的顶级模块中执行。

  • 顶级模块的__name__变量的值为__main__

    if __name__= '__main__' :
    	pass
    
  • 举例说明

    #自定义模块calcdemo.py
    def add(a,b):
        return a+b
    
    print(add(3,6))
    
    #引用模块
    import calcdemo
    print(calcdemo.add(7,9)) #会打印9和16,我们至引用了add,不应该执行print(add(3,6))
    

    在自定义模块中加上一行

    #自定义模块calcdemo.py
    def add(a,b):
        return a+b
    
    if __name__ == '__main__': #加上这个以后表示这行代码的执行仅在该文件执行时执行
        print(add(3,6))
    

python中的包

什么是包
  • 包是一个分层次的目录结构,它将一组功能相近的模块组织在一个目录下
包的作用
  • 代码规范
  • 避免模块名称冲突
包与目录的区别
  • 包含_init__.py文件的目录称为包
  • 目录里通常不包含__init__py文件
包的导入
  • import 包名、模块名
包的创建与引用
  • 右键new选择python package,给文件夹明明packagedemo,创建包

  • 包下放置不同的模块model1.py

  • 如图

    在这里插入图片描述

  • 项目如果想引用该模块,只需要

    import packagedemo.model1
    print(packagedemo.model1.a)
    
    #为了方便使用,可用以下方式
    import packagedemo.model1 as mu
    print(mu.a)
    
    #或者
    from packagedemo import model1 
    print(model1 .a)
    
    #或者
    from packagedemo.model1 import a
    print(a)
    

python中常用的内置模块

  • 如下

    在这里插入图片描述

    #选几个重要的讲一下
    import sys
    print(sys.getsizeof(34)) #28字节,python真费内存
    print(sys.getsizeof(77))
    print(sys.getsizeof(True))
    print(sys.getsizeof(False))
    
    import time
    print(time.time()) #非格式化的时间
    print(time.localtime(time.time())) #格式化
    
    import urllib.request
    print(urllib.request.urlopen('http://www.baidu.com').read()) #相当于在浏览器访问网页后用read读取html
    
    from math import pi,pow,ceil,floor
    print(dir(math)) #查看math内有哪些方法、参数可以用
    print(pi)
    print(pow(2,4)) #2的4次方
    print(ceil(9.001)) #向上取整,10
    print(floor(9.8)) #向下取整,9
    

python使用第三方模块

安装第三方模块
  • 在windows命令行工具中输入:

    pip install schedule #以此模块为例
    
  • 在pychram下方有个terminal窗口,相当于命令行工具,同样输入

    pip install schedule
    
验证是否安装成功
  • terminal中输入python,尝试引入

    import schedule
    
使用模块
  • 以schedule为例

    import schedule
    import time
    
    def job():
        print('每隔3S打印一下')
    schedule.every(3).seconds.do(job) #每隔3S来执行一下job函数,加入计划
    while True:
        schedule.run_pending() #执行计划
        time.sleep(2) #计划未启动成功则休眠2s
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值