python学习笔记13(类)

一、上堂回顾

1.默写题目

1.定义一个类,其中定义成员变量和成员方法,并将成员变量私有化,在类外面进行传值和获取值

"""
1.封装:将属性私有化的过程【面向对象】
2.好处:提高了数据的安全性,提高了代码的复用性
3.属性私有化:被私有化的属性只能在当前类中被直接访问
4.get函数和set函数:帮助理解暴露给外界可以访问私有化属性的方法
5.@property @属性名.setter:相当于get函数和set函数的作用【将函数转换为属性进行访问】
6.函数私有化:和属性私有化类似,只能在当前类中被调用
7.变量的不同形式:xxx  _xxx __xxx __xxx__
"""
class Check(object):
    def __init__(self,name):
        self.__name = name
        
    def show(self):
        pass
    
    @property
    def name(self):
        return self.__name
    
    @name.setter
    def name(self,name):
        self.__name = name
        
c = Check("")
print(c.name)
c.name = ""

2.分别定义一个父类和子类,在子类中调用父类的构造函数,并创建子类对象

"""
1.继承:有一个子类和一个父类,子类可以继承父类中所有未被私有化的属性和方法
2.单继承和多继承
    a.所有类的父类【超类,根类】都是object
    b.如果子类要继承父类中的未被私有化的成员变量,需要手动调用父类中的构造函数【三种方式】
    c.子类对象可以使用父类中所有未被私有化的属性和方法,父类对象不能访问子类中特有的属性和方法
"""
class SuperClass(object):
    def __init__(self,name):
        self.name = name
        
class SubClass(SuperClass):
    def __init__(self,name,age):
        self.age = age
        SuperClass.__init__(self,name)
        super().__init__(name)
        super(SubClass,self).__init__(name)

2.知识点回顾

二、函数重写

前提:必须出现在继承关系的类中

本质:函数的声明部分相同,实现部分不同【覆盖父类中函数的过程】

1.系统函数的重写

__str__:在调用print打印对象的时候,会被自动调用,默认返回的对象的地址【给程序员使用的】
__repr__:在Python解释器中调用的方法【给计算机使用的】

代码演示:

#系统函数的重写
class Animal(object):
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height
​
    #__str__:获取一个对象的字符串表示形式
    #注意2:如果在直接访问对象的时候,想要获取对象相关的成员变量的值,则直接重写__str__函数
    def __str__(self):
        return "%s-%d-%f" % (self.name,self.age,self.height)
​
    def __repr__(self):
        return "hello"
​
​
#创建对象【实例化对象】
a = Animal("大黄",10,40.0)
#注意1;直接访问对象的时候,默认调用的是__str__函数,默认返回的是该对象的地址
print(a)  #<__main__.Animal object at 0x00000249142FA048>  ----》大黄-10-40.000000
print(a.__str__())  #<__main__.Animal object at 0x00000249142FA048>----->大黄-10-40.000000
print(a.__repr__())
print(a.name,a.age,a.height)
​
"""
总结:
1.__str__和__repr__都未被重写的时候,直接访问对象默认调用的是__str__,但是,此时,__str__和__repr__返回的都是对象的地址
2.__str__和__repr__都被重写的时候,直接访问对象调用的是__str__,返回的是和成员变量有关的字符串
3.__repr__被重写,但是__str__未被重写,直接访问对象调用的是__repr__
4.__str__被重写,但是__repr__未被重写,直接访问对象调用的是__str__
"""
#总结;当一一个对象的属性很多的时候,并且都需要被打印,可以重写__str__,将所有成员变量的值拼接成一个字符串返回

2.自定义函数的重写

代码演示:

#自定义函数的重写:将父类中需要被重写的函数的实现部分重新实现一次
#父类
class Animal(object):
    def run(self):
        print("animal ruhning~~~")
​
#子类
class Cat(Animal):
    def run(self):
        print("cat running~~~~~")
​
class Dog(Animal):
    pass
​
#子类中的函数将父类中的函数覆盖掉【就近原则】
c = Cat()
c.run()  #子类中的run
​
d = Dog()
d.run()  #父类中的run
​
#注意:重写的意义:当一个父类有多个子类的时候,如果其中的某个子类调用父类中的 函数,发现满足不了需求,则需要进行重写,
# 但是,其他的子类还可以调用父类中的函数

三、多态

1.概念

一种事物的多种体现形式,举例;动物有多种

在Python中,多态指的是父类的引用指向子类的对象 ani = c c = Cat()

注意:继承是多态的前提

函数重写就是多态的体现形式

代码演示:

class Animal(object):
    pass
​
class Cat(Animal):
    pass
​
class Pig(Animal):
    pass
​
​
a = list()
b = Animal()
c = Cat()
​
#isinstance(变量,类型)
print(isinstance(a,list))
print(isinstance(b,Animal))  #True
print(isinstance(c,Cat))  #True
​
print(isinstance(c,Animal))  #True
​
print(isinstance(b,Pig))  #False
​
#在继承关系中,如果一个对象的类型是某个子类,则它的数据类型也可以被看做是对应的父类,反之,则不可以

2.使用

代码演示:

#需求;饲养员喂养猫和老鼠,老虎等动物
"""
分析:
1.定义饲养员的类和动物类
2.定义老鼠类,猫类,,继承自动物类
3.在饲养员的类中定义成员函数;喂养
"""
from duotai.animal import Animal
from duotai.person import Person
from duotai.cat import Cat
from duotai.tiger import Tiger
from duotai.mouse import Mouse
​
​
#1.创建一个饲养员的对象
p = Person()
​
#2.创建Cat的对象
c = Cat("小花")
​
#3.饲养员执行自己的行为
p.feedAnimal(c)
​
m = Mouse("aaaa")
p.feedAnimal(m)
​
#使用多态,可以简化代码,不同的子类对象可以共用一个函数,调用
​
​
class Person(object):
    """
    def feedCat(self,cat):
        print("喂养" + cat.name)
​
    def feedMouse(self,mouse):
        print("喂养" + mouse.name)
​
    def feedTiger(self,tiger):
        print("喂养" + tiger.name)
    """
    def feedAnimal(self,ani):   #c = Cat()   ani = c  c.eat()
        print("喂养" + ani.name)
        ani.eat()
​
class Animal(object):
    def __init__(self,name):
        self.name = name
    def eat(self):
        print("eating")
        
from duotai.animal import Animal
​
class Mouse(Animal):
    def __init__(self,name):
        super(Mouse,self).__init__(name) 

四、获取对象信息

type():判断对象所属的数据类型 结果:<class "int">

isinstance():判断一个对象是否属于某种数据类型 结果:布尔值

dir():获取一个对象所有的属性和方法 结果:字符串列表

代码演示:

import  types
#1.type()
print(type(123))
print(type("abc"))
print(type(None))
​
"""
<class 'int'>
<class 'str'>
<class 'NoneType'>
"""
​
#不同的数据类型之间可以使用==比较
print(type("123") == type(123))  #False
print(type("abc") == str)
​
#如果要判断一个对象是否是函数,需要使用types模块
def fun():
    pass
​
print(type(fun) == types.FunctionType)  #是否是自定义函数
print(type(abs) == types.BuiltinFunctionType)  #是否是内置函数
print(type(lambda  x:x) == types.LambdaType)  #是否是匿名函数
print(type((x for x in range(10))) == types.GeneratorType)  #是否是生成器
​
​
#2.isinstance()
print(isinstance("abc",str))
print(isinstance([1,2,3],list))
#参数1 只要是参数2中任意一种,则直接返回True【or】
print(isinstance([1,2,3],(list,tuple)))
​
#3.dir()
print(dir("abc"))
​
#等价
#在Python中,一切皆对象   s1 = "hello"  p = Peron()
print(len("hello"))
print("hello".__len__())  #工作原理

五、类中特殊的属性和方法【掌握】

1.实例属性和类属性

1.1实例属性和类属性的使用

实例【对象】属性和类属性之间的区别:【面试题】

​ a.定义的位置不同,类属性直接定义在类中,对象属性定义在构造函数中

​ b.访问的方式不同,类属性使用类名直接访问,对象属性使用对象访问

​ c.在内存中出现的时机不同,类属性随着类的加载而出现,对象属性随着对象的创建而出现

​ d.优先级不同,对象属性的优先级高于类属性

代码演示:

class Person(object):
    #1.定义位置
    #类属性;直接定义在类中
    name = "person"
​
    def __init__(self,name):
        #实例【对象】属性:定义在构造函数中
        self.name = name
​
#2.访问方式和在内存中出现的时机
print(Person.name)   #类名.属性  或者 对象.属性【类属性随着类的加载而出现】
per = Person("jack")
print(per.name)   #对象.属性   【对象属性随着对象的创建而出现】
​
#3.优先级;实例属性高于类属性
print(per.name)  #jack
#删除对象属性,会调用和实例属性同名的类属性
del per.name
print(per.name)
​
#注意;在实际的应用中,尽量避免类属性和实例属性重名的情况

1.2动态添加实例属性和方法

__slots__:可以限制属性和方法【动态添加】

代码演示:

from types import MethodType
​
class Person(object):
    #限制可以动态添加的属性
    __slots__ = ("name","age","func")
​
​
#1.动态添加属性
per = Person()
#动态添加
per.name = "jack"
​
#2.动态添加方法
"""
def show(self):
    print("showing")
​
per.func = show   #变量可以指向函数
#per.func()     #指向函数的的变量可以被当做函数调用
per.func(per)
"""
​
#Python中提供了动态添加函数的方式:MethodType
def show(self):
    print("showing")
​
#参数:需要被动态添加的函数名,需要被添加的对象
per.func = MethodType(show,per)
per.func()
​
#原理:动态爱添加属性,MethodType创建了函数,类似于偏函数【MethodType在现有函数show的基础上生成了一个新的函数,赋值给了func】

2.类方法和静态方法

类方法:使用@classmethod装饰器修饰的方法被称为类方法,类方法可以使用类名调用,也可以使用对象调用,但是,一般使用类名调用类方法

特点:

​ a.必须有一个参数,一般写为cls【class】,代表当前类

​ b.类方法属于整个类,并不是属于某个对象,在类方法中禁止出现self

​ c.在类方法中,可以直接通过cls调用当前类的方法以及访问当前类的属性

静态方法:使用@staticmethod装饰器修饰的方法被称为静态方法,静态方法可以使用类名调用,也可以使用对象调用,但是,一般使用类名调用静态方法

代码演示:

#成员方法,类方法,静态方法
class Pig(object):
    #1.类属性
    age = 5
    def __init__(self,age):
        #2.实例属性
        self.age = age
​
     #3.成员方法
    #self代表的当前类的实例【对象】
    def func1(self):
        print("func~~~1111")
​
    #4.类方法
    #cls代表的是当前类Pig
    @classmethod
    def func2(cls):
        print("func~~~22222")
​
        #6.在类方法的内部通过cls创建当前类的对象,并且可以调用当前类中成员方法
        p = cls(10)
        p.func1()
        print(p.age)    #优先访问的是实例属性
​
    #5.静态方法
    #参数:对参数没有任何限制
    @staticmethod
    def fun3():
        print("func~~~3333")
​
#7.调用
pig = Pig(9)
​
#调用类方法
Pig.func2()
pig.func2()
​
#调用静态方法
Pig.fun3()
pig.fun3()
​
#调用成员方法
#注意;成员方法中必须有一个参数self,传值的时候,传的是当前对象,如果使用类名进行调用,没有对象,则self没有传值
pig.func1()
#Pig.func1()  #TypeError: func1() missing 1 required positional argument: 'self'
​
print("~~~~~")
​
#8.继承
class SubClass(Pig):
    def __init__(self,age):
        super().__init__(age)
​
    def func1(self):
        print("子类~~~1111")
​
    @classmethod
    def func2(cls):
        print("子类~~~~~2222")
​
    @staticmethod
    def fun3():
        print("子类~~~333")
​
s = SubClass(20)
s.func1()
s.func2()
s.fun3()

总结:

​ 成员方法【实例方法】、类方法和静态方法之间的区别

​ a.在写法上

​ 实例方法:第一个参数必须是实例对象,一般用self表示

​ 静态方法:参数没有要求

​ 类方法;第一个参数必须是当前类,一般使用cls表示

​ b.在继承中的相同点:子类可以继承父类中的未被私有化的实例方法,静态方法,类方法,如果三种方法都被重写,仍然优先调用子类中的方法

3.类常用属性

__name__:
    通过类名访问
    获取类名相关字符串
    注意:使用对象访问报错
    
__dict__:
    通过类名访问,获取该类的信息,包含类方法,类属性,静态方法,成员方法,返回的是一个字典
    通过对象访问:获取的是该对象的信息,包含该对象的所有属性和值,返回是一个字典
    
__bases__:
    通过类名访问
    查看当前类的所有的父类【基类】

代码演示:

class Animal(object):
    pass
​
​
class Tiger(Animal):
    age = 10
    name = "abc"
​
​
    def haha(self):
        print("haha")
​
    @classmethod
    def show(cls):
        print("show")
​
    @staticmethod
    def check():
        print("check")
​
print(Tiger.__name__)
t = Tiger()
#print(t.__name__)
​
print(Tiger.__dict__)
print(t.__dict__)
​
print(Tiger.__base__)  #<class '__main__.Animal'>
​
#使用频率最广是__name__,if __name__ == "__main__"

六、运算符重载

重写:override 重载:overload

运算符的重载:和重写类似,对类的专有方法进行重载【将系统函数的实现部分重新实现】

和重写的区别:重写必须出现在具有继承关系的类中,重载没有要求

代码演示:

#__add__()
#使用+进行运算,在计算机底层实质上相当于对象调用了__add__,num1 + num2---->num1.__add__(num2)
print(1 + 2)  #3
print("1" + "2")  #12
print("1".__add__("2"))
#print("1" + 1)
#不同的类型会有不同的解释
​
#思考问题:如果两个对象相加会怎样?
class Person(object):
    def __init__(self,num):
        self.num = num
​
    #方法重写__str__
    def __str__(self):
        return  "num = %d" %(self.num)
​
    #方法重载
    def __add__(self, other):
        #两个Person类型的数据相加,得到的结果应该也是Person类型
        return  Person(self.num + other.num)
​
p1 = Person(10)
p2 = Person(20)
print(p1,p2)
​
print(p1 + p2)   #30
#p1 + p2 --->p1.__add__(p2)
print(p1.__add__(p2))

七、单例设计模式【掌握】

1.概念

存在的问题:如果在指定情况下,如果需要使用的对象是同一个,就没有必要浪费内存空间创建不同的对象

解决办法:单例设计模式

什么是设计模式?

​ 已经存在的可以解决特定问题的方案【模板】

​ 23种,其中比较常用的单例设计模式,工厂设计模式,代理委托设计模式,装饰者设计模式

什么是单例设计模式?

​ 程序在运行的过程中,确保某一个类只有一个实例【对象】,不管在哪个模块中获取该实例,获取到的都是同一个实例

单例设计模式的核心:一个类有且只有一个实例,并且这个实例需要应用在程序的各个位置

2.使用

2.1使用模块

Python中的模块本身就是一个单例

模块的工作原理:当模块被第一次导入的时候,会生成一个.pyc文件,当第二次导入的时候,会直接加载.pyc文件,跟原来的py文件没有关系

2.2使用new

__new__();从无到有的过程
为了保证一个类只有一个实例,使用__new__来控制实例的创建过程

代码演示:

class Singleton(object):
    #1.声明一个类属性:可以使用类名访问
    instance = None
​
    #2.重写new
    #new函数是一个类函数
    def __new__(cls, *args, **kwargs):
        #3.如果instance为None,则创建对象,并给instance赋值;如果instance不为None,则直接将instance返回
        #cls.instance
        if cls.instance == None:
            cls.instance = super(Singleton,cls).__new__(cls,*args, **kwargs)
            print("~~~~~~")
        return cls.instance
​
        #super(Singleton,self).__init__()
​
class MyClass(Singleton):
    pass
​
#注意:__new__类似于构造函数,是在创建对象的时候调用
one = MyClass()   #只有第一次调用的时候在创建对象
two = MyClass()  #在获取对象
​
​
print(id(one) == id(two))  #True

2.3装饰器

代码演示:

#装饰器;将其应用于一个类上
#将装饰器应用于一个函数上,则外部函数需要传一个函数,应用到一个类上,则需要传一个类,使用cls代表类
def singleton(cls):   #cls = Test
    #变量
    instance = {}
​
    #成员方法
    def getSingleton(*args, **kwargs):
        #思路:如果cls在字典中,则直接将结果【对象,实例】返回,如果cls不存在,则cls作为key,实例作为value存储到字典中
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)    #{Test:Test()}
        return  instance[cls]
​
    return  getSingleton
​
@singleton
class Test(object):
    pass
​
"""
f = singleton(Test)
result = f()
"""
​
t1 = Test()
t2 = Test()
​
print(id(t1) == id(t2))

2.4使用在类中

代码演示:

猜你喜欢

转载自blog.csdn.net/weixin_42569562/article/details/81809236