python继承 +python多态+获取对象的信息+类中特殊的属性和方法+运算符重载+单例设计模式

一、继承

1.函数的重写

override

前提:在具有继承关系的类中

作用:将父类中已有的函数在子类中进行重新的实现【声明部分一样的,实现部分不一样】

1.1系统函数的重写

注意:并不是所有的系统函数都需要重写

__str__
__repr__

代码演示:

class Person(object):
    def __init__(self,name,age,height,score):
        self.name = name
        self.age = age
        self.height = height
        self.score = score

    #3.__str__的重写:返回一个对象信息的字符串
    def __str__(self):
        return "name=%s age=%d height=%f score=%d" % (self.name,self.age,self.height,self.score)

    """
    def __repr__(self):
        return "hello"
    """
    #4.str和repr都和对象有关,让二者的实现返回相同的结果, __repr__ =  __str__可以省略
    __repr__ =  __str__
    #等价于下面的写法:
    """
    def __repr__(self):
        return "name=%s age=%d height=%f score=%d" % (self.name,self.age,self.height,self.score)
    """

p1 = Person("abc",19,17,37)
print(p1.name,p1.score,p1.age,p1.height)
#1.如果直接打印对象,获取的是对象的地址
print(p1)   #<__main__.Person object at 0x000001C7E4190DD8>

p2 = Person("abc",19,17,37)
print(p2.name,p2.score,p2.age,p2.height)

#2.函数的重写:
# __str__:返回一个字符串,但是,如果没有重写该函数,默认返回该对象的地址
#当重写了__str__之后,直接使用对象,则返回的是str函数中的返回值
#print(p1.__str__())


"""
总结:
    a.当str和repr都未被重写的时候,使用对象,调用的是str,此时的str返回的是对象的地址
    b.当str和repr都被重写之后,使用对象,调用的是str,返回的是指定的字符串
    c.当没有重写str,但是,重写repr,使用对象,调用的是repr,返回的是指定的字符串
    d.当只重写了str,调用是str
"""

#优点或者使用场景:当一个对象的属性很多,并且都需要通过打印来查看相应的值,就可以重写str函数,简化代码
p3 = Person("abc",19,17,37)
print(p3)

1.2自定义函数的重写

一个父类可以有多个子类

函数重写的时机:当父类中的函数的功能不满足子类的需求时,就需要重写

注意:并不是所有的子类都需要重写父类中的函数

重写的规则;子类中出现和父类中重名的函数,则子类中的会覆盖掉父类中

代码演示:

#父类
class Animal(object):
    def __init__(self,name):
        self.name = name

    def show(self):
        print("父类~~show")

#子类
class Dog(Animal):
    def __init__(self,name):
        super().__init__(name)

class Cat(Animal):
    def __init__(self,name):
        super().__init__(name)

class Tiger(Animal):
    def __init__(self,name):
        super().__init__(name)

    #重写父类中的函数
    #声明相同,实现不同的
    def show(self,num):
        #调用父类中的函数
        super().show()

        print("子类~~~show")

d = Dog("fah")
d.show()

t = Tiger("abc")
t.show(3)
#函数名就是一个变量名,重写函数的过程其实就是变量的指向发声改变的过程
#不管子类中的函数有没有参数,和父类的参数列表相不相同,不影响重写,只看函数名
#t.show()

二、多态

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

定义时的类型和运行的类型不一样,也就是说,定义时不确定调用的是哪个方法,只有运行之后才能确定调用的是哪个方法

注意:继承是多态的前提

函数的重写和运算符的重载也是多态的一种体现

代码演示:

#父类
class Animal(object):
    pass

#子类
class Cat(Animal):
    pass


#定义变量
a = []
b = Animal()
c = Cat()

#isinstance():判断一个变量是否属于指定的数据类型
print(isinstance(a,list))
print(isinstance(b,Animal))
print(isinstance(c,Cat))
#结论:在继承关系中,如果一个对象的数据类型是子类,也可以说,该对象的数据类型也是父类
print(isinstance(c,Animal))   #True
#父类的对象不属于子类的数据类型
print(isinstance(b,Cat))  #False

class Dog(object):
    def myPrint(self):
        print("dog")

class SmallDog(Dog):
    def myPrint(self):
        print("SmallDog")


#定义时的类型和运行的类型不一样,也就是说,定义时不确定调用的是哪个方法,只有运行之后才能确定调用的是哪个方法
#temp:定义的时候temp不确定是哪种数据类型,只有运行的时候,才能确定
def show(temp):
    temp.myPrint()


d = Dog()
s = SmallDog()
show(d)
show(s)

三、获取对象的信息

1.type()

获取对象的数据类型

2.isinstance()

3.dir()

代码演示:

import  types,os
#1.type()
#1.1获取类型
print(type("123"))
print(type(23))
print(type(True))
print(type(None))

#注意:type返回的是对应的Class类型
print(type(type("123")))   #<class 'type'>

"""
<class 'str'>
<class 'int'>
<class 'bool'>
"""

#1.2比较
print(type(123) == type(56))
print(type("123") == type(123))
print(type(True) == type(False))

print(type(123) == int)
print(type("abc") == str)
print(type(True) == bool)

#1.3判断一个对象是否是函数
#借助于types模块
print(type(abs) == types.BuiltinFunctionType)   #是否是系统内置的函数
print(type((x for x in range(1,10))) == types.GeneratorType)   #是否是生成器
print(type(lambda  x : x) == types.LambdaType)  #是否是匿名函数

def func():
    pass
print(type(func) == types.FunctionType)  #是否是自定义函数

#2.isinstance();判断一个对象是否属于某种数据类型
print(isinstance(3,int))
print(isinstance("abc",str))

#注意:判断某个对象是否属于元组中的其中一种数据类型    或
print(isinstance([1,2,3],(list,tuple)))
print(isinstance((1,2,3),(list,tuple)))

#3.dir():获取任意对象的所有信息,包含从父类中继承的内容【属性和方法】
print(dir(os))
print(dir("abc"))

"""
在Python中.变量的前后各有两个下划线,是有特殊用途的,比如__len__是len()在底层存在的形式

"""
print(len("abc"))
print("abc".__len__())

class Check(object):
    nanme = "gagj"
    def show(self):
        pass

c = Check()
print(dir(c))

四、类中特殊的属性和方法

1.实例属性和类属性

实例属性【对象属性】和类属性的区别

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

​ b.访问方式不同:实例属性必须用对象访问,类属性可以使用类名或者对象访问

​ c.在内存中出现的时机不同:类属性随着类的出现而出现,实例属性随着对象的出现而出现【在代码中,类优先于对象出现的】

​ d.调用的优先级不同:如果类属性和实例属性重名的情况下,对象优先调用实例属性

代码演示:

class Person(object):
    #1.定义的位置不同
    # 类属性:直接定义在类中
    name = "abc"
    num = 10

    #实例属性:定义在构造函数中
    def __init__(self,name):
        self.name = name

#2.调用的方式
#类属性:对象.属性  或者  类名.属性
#实例属性;对象.属性
p = Person("javk")
#3.优先级不同:实例属性的优先级高

print(p.name)
print(Person.name)

del p.name
print(p.name)

print(p.num)

#总结;如果是多个对象的共享数据,则定义为类属性,如果是对象特有的数据,则定义为实例属性

#注意:尽量避免类属性和实例属性重名

2.动态添加属性和方法

代码演示:


from types import MethodType

class Check(object):
    num = 0
    __slots__ = ("num1","num2")

    def func(self):
        print("func")

#1.动态绑定属性
c1 = Check()
c1.num1 = 10
print(c1.num1)

#2.动态绑定方法
"""
def show(self):
    print("show")

c1.func()
#一个变量可以指向函数,该变量就可以被当做函数进行调用
c1.num2 = show
#当对象调用一个成员函数的时候,self不需要手动传参的,参数表示的当前对象
c1.num2(c1)
"""

#使用系统的MethodType类创建一个函数
def show(self):
    print("show")

# 参数:需要绑定的函数的名字    绑定给哪个对象
c1.num2  = MethodType(show,c1)
c1.num2()

3.类方法和静态方法

类方法:在一个类中,如果一个方法被@classmethod装饰器修饰,则被称为类方法

​ a.可以使用对象调用,也可以使用类名调用

​ b.类方法是属于整个类的,并不属于某个对象,所以在类方法中不能出现self

​ c.必须有一个参数,为cls,代表的是当前类,在类方法中可以直接通过cls创建对象,也可以通过cls直接调用当前类中的其他的类方法

静态方法:在一个类中,如果一个方法被@staticmethod装饰器修饰,则被称为静态方法

​ a.类似于类方法,可以使用对象调用,也可以使用类名调用

​ b.参数部分没有任何限定

代码演示:

class Check(object):
    #1.类属性
    num1 = 0

    def __init__(self,num2):
        #2.实例属性
        self.num2 = num2

    #3.成员函数:只能通过对象调用
    def show(self):
        print("show")
        return  10

    #4.类函数:对象或者类名调用
    @classmethod
    def func1(cls):
        print("func~~~1",cls)

        #cls的用法;代表的是当前类,所以可以通过cls创建对象
        c2 = cls(67)
        #通过cls创建出来的对象调用成员函数
        c2.show()

    #5.静态方法:对象或者类名调用
    @staticmethod
    def func2():
        print("hgjhg")

c1 = Check(76)

c1.func1()
Check.func1()
#Check.show()  #TypeError: show() missing 1 required positional argument: 'self'

#print(type(c1))

c1.func2()
Check.func2()

#使用场景:类方法和静态方法 一般用于工具类的封装中

代码演示:

class SuperClass(object):
    @staticmethod
    def func2():
        print("hgjhg")

    @classmethod
    def func1(cls):
        print("func~~~1")

class SubClass(SuperClass):
    @staticmethod
    def func2():
        print("子类~~~hgjhg")

    @classmethod
    def func1(cls):
        print("子类~~~~~func~~~1")


s1 = SubClass()
s1.func1()
s1.func2()

#结论:通过子类对象可以调用类方法和静态方法,同时也可以在子类中重写类方法和静态方法

4.常用的属性

__name__:获取类名的字符串
	通过类名访问,对象访问会报错

__dict__:
	通过对象访问:获取的是该对象的属性和方法,返回一个字典
	通过类名访问:获取的是该类的所有的信息

__bases__:获取指定类的所有的父类
	通过类名访问

代码演示:

#1.__name__
class Animal(object):
    num1 = 10
    def __init__(self,name,age):
        self.name = name
        self.age = age

    @staticmethod
    def func2():
        print("~~~hgjhg")

    @classmethod
    def func1(cls):
        print("~~~~~func~~~1")

    def func3(self):
        print("func3")

a = Animal("abc",19)
#print(a.__name__)  #AttributeError: 'Animal' object has no attribute '__name__'
print(Animal.__name__)  #Animal

#2.__dict__
print(a.__dict__)  #对象.__dict__:实例属性
print(Animal.__dict__) #类名.__dict:该类中的所有的内容,除了实例属性


#3.__bases__:获取父类,返回是一个元组
#print(a.__bases__)  #AttributeError: 'Animal' object has no attribute '__bases__'
print(Animal.__bases__)

五、运算符重载

overload

重载:两个类,如果在 一个类中重新实现了一个方法

对专有的方法进行重载

代码演示:

#+普通用法
#数字和数字相加:数学运算
print(24 + 49)
#字符串和字符串相加:拼接
print("fdh" + "ghaur")

#print("ahfg" + 16)  #ypeError: must be str, not int
#不同的数据类型的加法操作会有不同的解释

class Person(object):
    def __init__(self,num):
        self.num = num

    def __str__(self):
        return "num = " + str(self.num)

    #运算符重载
    #在程序中,但凡涉及到+运算,在底层都会调用__add__,
    def __add__(self, other):
        return Person(self.num + other.num)

p1 = Person(23)
p2 = Person(12)


print(p1,p2)

#int+int = int   str+str = str   person+person = person
p3 = p1 + p2
print(p3)
print(p3.__str__())   #35
print(p1.__add__(p2))   #p1 + p2 =====>p1.__add__(p2)

"""
def text(str1,num1):
    return  str1 + str(num1)

text("abc" + 18)
"""

#使用场景:当系统的某些功能满足不了需求时,就可以在类中进行重载,函数的实现体部分完全可以自定义

六、单例设计模式

1.案例

小彩旗,见代码

2.概念

什么是设计模式?

​ 设计模式是别人已经总结好的可以解决问题的方案

​ 设计模式23种,常用的是单例设计模式,工厂设计模式,生产者消费者设计模式,代理委托设计模式等

什么是单例设计模式?

​ 单例:单个的实例,单个的对象

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

单例设计模式的核心;一个类有且只能有一个对象,并且该对象可以应用于整个程序中

3.使用

3.1使用new

类似于构造函数,优先于构造函数

代码演示:

#__new__:在__init__之前创建对象

class Sigleton(object):
    #定义一个类属性【可以通过类名】
    #作用:用于返回当前类的实例
    instance = None

    #重写new函数
    def __new__(cls, *args, **kwargs):
        #将当前类的对象和instance变量联系起来
        #思路;如果cls.instance为None,则创建对象并赋值,如果不为None,则直接返回对象
        if not  cls.instance:
            cls.instance = super(Sigleton,cls).__new__(cls,*args, **kwargs)
        return cls.instance


s1 = Sigleton()
s2 = Sigleton()
s3 = Sigleton()
print(id(s1) == id(s2))  #True
print(id(s1) == id(s3))

print(s1 is s2)

3.2装饰器

代码演示:

#装饰器:作用于一个函数,也可以作用域一个类
def sigleton(cls):
    instance = {}
    #getInstance/defaultxxx/ currentxxx
    def getInstance(*args, **kwargs):
        #思路1:可以类似于new,通过是否为NOne
        #思路2:将cls作为key,cls对应的实例作为value存储到字典中
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)   #dict[key] = value
        return  instance[cls]

    return  getInstance

@sigleton
class Test(object):
    pass

t1 = Test()
t2 = Test()
print(id(t1) == id(t2))
print(t1 is t2)
3.3自定义类

代码演示:

class Check(object):
    instance = None

    @classmethod
    def getInstance(cls,*args, **kwargs):
        if not cls.instance:
            cls.instance = cls(*args, **kwargs)

        return cls.instance

c1 = Check.getInstance()
c2 = Check.getInstance()

c3 = Check()

print(id(c1) == id(c2))
print(c1 is c2)
print(c1 is c3)  #False

#弊端:还是可以通过类名创建对象,但凡在类外面创建的对象,都属于不同的对象

猜你喜欢

转载自blog.csdn.net/herogxw4/article/details/88779851
今日推荐