Day8笔记

这篇笔记详细介绍了Python面向对象的编程概念,包括封装、继承和多态的原理与应用。讲解了如何通过实例属性和类属性、动态添加属性、类方法和静态方法来实现对象的特性。还重点讨论了函数重写,包括系统函数和自定义函数的重写规则,以及运算符重载的概念。
摘要由CSDN通过智能技术生成

1.定义一个类,其中定义实例属性和成员函数,并将实例属性私有化,在类外面进行传值和获取值的操作【封装】

"""
封装
1.什么是封装:将类中的属性私有化的过程,函数和类的定义,被称为封装
2.属性私有化:对实例属性前面添加两个下划线,被私有化的属性只能在当前类中被直接访问
3.如果在外界访问私有化属性,在类中定义公开函数
4.property装饰器:将公开函数转换为属性使用
"""
class Check(object):
  #构造函数
  def __init__(self,num):
    self.__num = num
    
    
  #成员函数
  def func(self):
    pass
    
  @property
  def num(self):
    return self.__num
  
  @num.setter
  def num(self,num):
    self.__num = num
  
c = Check(18)
#注意:此处的num并不是变量num,而是函数名
print(c.num)
c.num = 20

2.分别定义一个子类和父类,在子类构造函数中调用父类构造函数【继承】

class SuperClass(object):
  def __init__(self,name):
    self.name = name
    
    
class SubClass(SuperClass):
  def __init__(self,name,age):
    self.age = age
    #调用父类中的构造函数
    #super(SubClass,self).__init__(name)
    #super().__init__(name)
    SuperClass.__init__(self,name)
    
"""
1.什么是继承:有一个子类和父类,子类可以继承父类中所有未被私有化的属性和方法
	子类   继承自   父类  /   父类   派生了   子类
2.单继承和多继承的特点
	a.所有类的超类或者根类都是object
	b.子类对象可以直接访问父类中未被私有化的属性和方法
	c.父类对象不能访问子类中特有的属性和方法
	d.一个类至少有一个父类,如果不写,则默认为object
3.优缺点
	
"""

3.分别简述封装和继承


2.知识点回顾

1.get函数和set函数:@property装饰器的工作原理

2.方法私有化:跟变量的私有化用法完全相同

3.继承树:广度解析

二、继承

1.函数重写【掌握】

override

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

作用:如果父类中的成员函数实现的功能无法满足子类的需求,则在子类中需要对父类中的成员函数进行重写【将函数重新实现一次:声明部分是一样的,实现部分重新操作】

1.1系统函数的重写

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

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

    #3.__str__的重写:重新书写函数的实现部分,返回一个当前对象的属性信息
    #当重写了str的函数之后,打印对象的时候,会默认返回str函数的返回值
    def __str__(self):
        return "name=%s age=%d score=%d height=%f" % (self.name,self.age,self.score,self.height)

    # def __repr__(self):
    #     return  "hello"

    #让repr引用指向str所指向的函数
    __repr__ = __str__

p1 = Person("zhangsan",17,87,180.0)
#1.如果直接打印对象,得到的结果为当前对象的地址
print(p1)  #<__main__.Person object at 0x000001268D310E10>
#print(p1.__str__())
print(p1.name,p1.age,p1.score,p1.height)

p2 = Person("lisi",17,87,180.0)
print(p2)  #<__main__.Person object at 0x000001CDED7983C8>
#print(p2.__str__())
print(p1.name,p1.age,p1.score,p1.height)

#2.__str__;是object的函数,返回一个字符串,
#__str__是有返回值的,默认情况下,该函数返回的该对象的地址字符串
#问题:当打印对象的时候,返回该对象的属性信息,则需要重写__str__函数

#4
"""
1.当str和repr未被重写的时候,使用对象,调用的是str函数,此时str返回的是对象的地址
2.当str和repr都被重写之后,使用对象,调用的是str函数,此时str返回的是属性相关的信息
3.当没有重写str,但是重写repr,使用对象,调用的是repr函数,返回的是repr指定的字符串
4.当只重写str,则调用的是str

一般写法:
def __str__(self):
    return "xxxx"
__repr__ = __str__

以后在类中包含下面的内容:
    1.构造函数[定义实例属性,并给实例属性赋值]
    2.成员函数
    3.重写__str__
"""
1.2自定义函数的重写

注意:并不是所有的子类都需要重写父类中的函数,当父类的实现满足不了子类的需求的时候才需要重写

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

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

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

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


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


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

    # 2.当父类中实现的功能满足不了子类需求的时候,则需要重写
    #4.重写函数的规则:只要函数名一致,则就是重写
    def show(self,num1,num2):
        s = num1 + num2
        print("子类~~~show",s)

#1.当父类中的函数实现的功能满足子类需求的时候,子类对象直接调用
c = Cat("fhajg")
c.show()
t = Tiger("ahhf")
t.show()

#3.当在子类中重写了父类中的函数,则通过子类对象调用函数【就近原则】
#重写:后出现的函数将原来的函数覆盖的过程【改变一个函数变量指向的过程】
d = Dog("aaa")
d.show(12,34)

三、多态

一种事物的多种体现形式,比如:动物有很多种

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

注意:继承是多态的前提

函数的重写其实也是多态的一种体现

#父类
class Animal(object):
    pass

#子类
class Cat(Animal):
    pass

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

#isiantance(变量,类型):判断一个变量是否是指定的数据类型
print(isinstance(a,list))
print(isinstance(b,Animal))
print(isinstance(c,Cat))

#结论:在继承关系中,如果一个对象的数据类型是子类,则该对象的数据类型同时也是父类
print(isinstance(c,Animal))
#父类的对象不属于子类的数据类型
print(isinstance(b,Cat))   #False

案例:

"""
案例:人可以喂动物【动物有好多种】
"""
from duoTai02.person import Person
from duoTai02.cat import Cat
from duoTai02.dog import Dog
from duoTai02.tiger import Tiger

p = Person()

c = Cat("xiaobai")
p.feedAnimal(c)

d = Dog("大黄")
p.feedAnimal(d)

class Person(object):
    # def feedCat(self,cat):
    #     print("给食物")
    #     cat.eat()
    #
    # def feedDog(self,dog):
    #     print("给食物")
    #     dog.eat()
    #
    #
    # def feedTiger(self,tiger):
    #     print("给食物")
    #     tiger.eat()
    #多态的体现
    def feedAnimal(self,ani):
        print("给食物")
        ani.eat()

四、获取对象信息

1.type()

获取指定对象的类型

2.isinstance()

获取指定对象的类型

3.dir()

获取一个对象所有的属性和方法

import types
#1.type

print(type(123))  #<class "int">

#直接比较两个变量或者常量的类型是否一致
print(type(11) == type(22))

print(type("abc") == str)

#可以判断函数的类型
#导入types
print(type(abs) == types.BuiltinFunctionType)
print(type(lambda  x:x) == types.LambdaType)

def fn():
    pass
print(type(fn) == types.FunctionType)

print(type((x for x in range(10))) == types.GeneratorType)

#2.isinstance()
print(isinstance(11,int))
print(type(11) == int)

#判断参数一的类型在参数二的元组中是否存在,存在则返回True
print(isinstance([1,2,3],(dict,tuple)))
print(isinstance((1,2,3),(list,tuple)))


#3.dir()
print(dir("abc"))

#注意:类似于__xxx__的属性在Python中一般有特殊用法,自定义的标识符尽量不要使用
print(len("abc"))
#等价于
print("abc".__len__())

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

t = Text(18)
print(dir(t))

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

1.实例属性和类属性

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

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

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

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

​ d.优先级不同:如果类属性和实例属性重名的情况下,通过对象访问,则优先访问实例属性

class Person(object):
    #1.定义的位置不同
    #类属性
    #name = "abc"
    #age = 36
    school = "千锋"


    def __init__(self,name):
        #实例属性
        self.name = name
        # self.age = age

        self.score = 100

#2访问的方式不同
#类属性:对象.    类名.
#实例属性:对象.
print(Person.name)
p1 = Person("jack")
print(p1.age)

print(p1.score)
#print(Person.score)  #报错:AttributeError: type object 'Person' has no attribute 'score'


#3.优先级
del p1.name
print(p1.name)

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

per1 = Person("tom")
per2 = Person("bob")
print(per1.name,per2.name)   #tom  bob
print(per1.age,per2.age)   #36

#实例属性
print(id(per1.name) == id(per2.name))   #False
#类似属性
print(id(per1.age) == id(per2.age))  #True

"""
总结:
    不同的对象访问同一个类属性,指向的是同一块内存空间
    不同的对象访问同一个实例属性,指向的是不同的内存空间
"""

#注意:尽量避免类属性和实例属性重名
2.动态添加属性和方法
from types import  MethodType

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

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

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

#2.动态绑定函数
c1.func()
#一个变量指向函数,该变量就可以被当做函数使用
f = c1.func
print(f)
f()

#c1.属性  = 函数    c1.属性()
# def show(self):
#     print("showing")
#
# c1.text = show
# c1.text(c1)

#使用系统的类MethedType创建一个函数对象
def show(self):
    print("showing~~~~~")

#参数:需要绑定的函数的名称   绑定给哪个对象
c1.text = MethodType(show,c1)
c1.text()
3.类方法和静态方法

成员方法

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

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

​ b.类方法是属于整个类的,并不属于某个具体的对象,则在类方法中不能出现self,替代self的是一个cls的参数,代表的是当前类,在类方法中通过cls创建对象,也可以通过cls调用类中的其他的类方法

​ self:当前对象

​ cls:当前类

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

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

​ b.参数部分没有任何限定,不需要出现self,也不需要出现cls

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


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

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

    #4.类方法
    #self和cls一样,都不是Python的关键字,只是为了约定,cls是class的缩写
    @classmethod
    def func1(cls):
        print("func1:",id(cls))
        print("func~~~111",cls)   #<class '__main__.Check'>

        #cls的用法:代表就是当前类,所以可以通过cls创建对象
        c2 = cls(26)
        #通过cls创建出来的对象可以和普通方式创建的对象一样使用,可以调用成员函数和访问变量
        print(c2.show())
        print(c2.num2)


    #5.静态方法
    @staticmethod
    def func2(a,b):

        print("func~~~~22")
        return  a + b


c1 = Check(7)
#c1.show()
#c1.func1()
#print("c1:",id(c1))

#Check.func1()

print(c1.func2(2,3))
print(Check.func2(3,4))

#总结:类方法和静态方法可以不创建对象,直接通过类名调用,一般使用工具类中
#工具类:封装类,类中提供了各种功能的封装,此时如果在其他的模块中调用工具类中的函数,只需要通过类名调用
class SuperClass(object):
    @staticmethod
    def func1():
        print("静态方法")

    @classmethod
    def func2(cls):
        print("类方法")

class SubClass(SuperClass):
    @staticmethod
    def func1():
        print("静态方法~~~1111")

    @classmethod
    def func2(cls):
        print("类方法~~~~111")


s1 = SubClass()
#1.子类对象可以调用父类中的静态方法和类方法
#2.在子类中也可以重写父类中的静态方法和类方法
s1.func1()
s1.func2()

工具类:

class ListTool(object):
    #冒泡排序
    @classmethod
    def bubbleSort(cls,newList):
        pass

    #选择排序
    @classmethod
    def selectSort(cls, newList):
            pass


    #二分法查找
    @staticmethod
    def searchBykey(key):
        pass
from listtools import ListTool

list1 = [23,3,1,2,4,54,5]
ListTool.bubbleSort(list1)
4.常用的系统属性
__name__:获取类名的字符串
	通过类类访问,对象访问会报错

__dict__:返回一个字典
	通过类名访问:获取的是该类的所有的信息,不包括对象的信息
	通过对象访问:获取该对象的实例属性
	

__bases__:获取指定类的所有的父类【基类】
	通过类名访问、
#1.__name__
if __name__ == "__main__":
    pass


class A(object):
    pass

class B(object):
    pass
class Animal(A,B):
    num1 = 10
    def __init__(self,num2):
        self.num2 = num2


    @staticmethod
    def func1():
        pass

    @classmethod
    def func2(cls):
        pass

    def func3(self):
        pass

a = Animal(17)
#print(a.__name__)
print(Animal.__name__)  #Animal


#2.__dict__
print(a.__dict__)   #{'num2': 17}
print(Animal.__dict__)
"""
{'__module__': '__main__', 'num1': 10, '__init__': <function Animal.__init__ at 0x000001C980647488>,
'func1': <staticmethod object at 0x000001C980649320>,
'func2': <classmethod object at 0x000001C980649390>,
'func3': <function Animal.func3 at 0x000001C980647620>,
'__dict__': <attribute '__dict__' of 'Animal' objects>,
 '__weakref__': <attribute '__weakref__' of 'Animal' objects>, '__doc__': None}
"""

#3.__bases__:得到的当前类的所有的父类,返回一个元组
print(Animal.__bases__)  #(<class 'object'>,)

六、运算符重载【掌握】

重写:override

重载:overload

重写:在具有继承关系的类中,在子类中重新实现父类中的函数

重载:两个类,如果在其中一个类中重新实现了某个方法,一般是系统的方法

#+普通使用
print(30 + 26)   #56
#+:拼接
print("hello" + "Python")

#print("abc" + 17)
#print(17 + "abc")
#不同类型的数据相加得到不同的解释

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

    def __str__(self):
        return "%d" % (self.num)

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


p1 = Person(21)
p2 = Person(7)
print(type(p1))
print(type(p2))

print(p1 + p2)   #28
p3 = p1.__add__(p2)
print(p3.__str__())  #28

print("*********")

#int + int = int   str+ str = str   person + person = person

num1 = 20
num2 = 36
print(num1.__add__(num2))
print(num1 + num2)

s1 = "hello"
s2 = "Python"
print(s1 + s2)
print(s1.__add__(s2))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值