day01 python面向对象

本文详细介绍了面向对象编程的核心概念,包括类、对象、属性和方法,以及Python中的类方法、静态方法、单例模式、继承和多态的使用。重点讲解了`__init__`、`__new__`、私有属性和方法,以及类与对象的交互方式。
摘要由CSDN通过智能技术生成

1. 面向对象的思想:将变量和函数绑定到一起,分类进行封装,每个程序只要负责分配给自己的分类,这样能够更快速的开发程序,减少了重复代码。

2. 面向对象编程的关注点在于“谁来做”:

  • 在完成某一个需求前,首先确定职责 —— 要做的事情(方法)
  • 根据 职责 确定不同的 对象,在对象内部封装不同的方法(多个)
  • 注重 对象和职责,不同的对象承担不同的职责。

3. 对象是面向对象编程的两个核心概念。

  1. 特征其实就是一个变量,在类里我们称之为属性。
  2. 行为其实就是一个函数,在类里我们称之为方法。
  3. 类其实就是由 属性 和 方法 组成的一个抽象概念。
  4. 对象是由类创建出来的一个具体存在,可以直接使用。由哪一个类创建出来的 对象,就拥有在哪一个类中定义的属性和方法。
  5. 类中定义了什么属性和方法,对象中就有什么属性和方法。
  6. 不同对象对应的属性值也会不同。
  7. 通过内存空间变化理解
    1.创建实例对象:
    2.类方法
    3. 私有属性 私有方法 通过内部接口函数方法去调用;因外部无法访问私有属性和私有方法

4. Python 的类里提供的方法--魔法方法

  1. __init__() 方法:父类object中默认存在__init__方法,在使用类创建一个对象时默认被调用,在内存开辟一块空间存放该类;在开发中,如果希望在创建对象的同时,就设置对象的属性,可以在类中重写__init__ 方法进行改造。
  2. 调用__new__方法,申请一段内存空间;
    调用__init__方法,并让self指向申请好的那段内存空间
    将实例对象的属性参数传入到那段内存空间
    即使是创建两个相同名字的对象,但开辟的内存空间是不一样的
  3.  __init__()方法里的self参数,在创建对象时不需要传递参数,python解释器会把创建好的对象引用直接赋值给self
    # 在类的内部,可以使用self来使用属性和调用方法;在类的外部,需要使用对象名来使用属性和调用方法。
    # 如果有多个对象,每个对象的属性是各自保存的,都有各自独立的地址。
    # 类中的方法是所有对象共享的,只占用一份内存空间,方法被调用时会通过self来判断是哪个对象调用了实例方法。
    class Cat:
        """这是一个猫类"""
    
        def __init__(self, x, y):  # 重写了 __init__ 魔法方法
            self.name = x
            self.color = y
            self.__age = 5  # 私有属性需要在类中做一个函数方法接口用来调用
    
        # 访问私有属性
        def get__age(self, age):
            self.__age = age
        # 修改私有属性
        def set__age(self):
            self.__age+=1
            return self.__age
    
        def __str__(self):
            return '小猫是:{},颜色是{}'.format(self.name, self.color)
    
        def __del__(self):
            print('__del__方法被调用了,删除此对象')
    
        def eat(self):
            return "%s爱吃鱼" % self.name
    
        def drink(self):
            return '%s爱喝水' % self.name
    
        """
            tom = Cat()
            TypeError: __init__() missing 2 required positional argument: 'name','color'
            这种写法在运行时会直接报错!因为 __init__ 方法里要求在创建对象时,必须要传递 name,color 属性,如果不传入会直接报错!
        """
    
    
    # 创建对象时,必须要指定name属性的值
    tom = Cat("Tom", "blue")
    tom.set__age()
    print(tom.get__sge())
    
    del tom  # 当删除对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法。
    
    # tom.eat()   # 对象被删除,再次调用对象方法报错

5. 实例对象的私有属性和私有方法
   类内部通过定义函数方法去访问实例对象的私有属性,也可定义函数方法去调用实例对象的私有方法
   实例对象的私有属性:不能在类的外部被使用或直接访问
   实例对象的私有方法:只能在类的内部调用 ,不能在类的外部调用。

#类内部通过定义公有方法去访问私有属性,也可定义公有方法去调用私有方法
class Person:
    publicCount = 0    # 公开变量
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__money = 2000  # __money 是私有变量,外部无法访问

    # 定义了get_money 方法,在这个方法里获取到 __money
    def get_money(self):  
        return self.__money  # 内部可以访问 __money 变量

    # 定义了set_money 方法,在这个方法里,可以修改 __money
    def set_money(self, money):  
        self.__money = money
    # 私有方法外部不能直接调用,只能在内部使用 
    def __foo(self):
        print("这是私有方法") 
    def foo(self):
        print("私有方法被调用了")
        self.__foo()  # 私有方法被调用 

p = Person('王五', 21)

# 外部通过调用 get_money 和 set_money 这两个接口的公开方法获取和修改私有属性变量
print(p.get_money())
p.set_money(8000)
print(p.get_money())
# 外部通过访问公有方法的接口去调用私有方法
p.foo()        # 正常输出
6.类方法、属性和静态方法的使用:
  类属性只能通过类对象修改,不能通过实例对象修改
  类属性也可以设置为 私有,前边添加两个下划线
class Person(object):
    type = "人类"  # 类属性

    # 类方法,需要@classmethod去定义
    @classmethod
    def test(cls):  # 如果一个函数只用到了类属性,可以定义成一个类方法
        # 类方法中的cls参数不需要手动传参,会自动传参,
        # cls指的是类对象,cls就是Person;
        print("哈哈哈哈" + cls.type)

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self, food):  # def创建的都是对象方法,self指的是实例对象
        print(self.name + "正在吃" + food)

    # 如果一个方法里没有用到实例对象的任何属性,可以将这个方法定义成staticmethod,
    # 静态方法
    @staticmethod
    def demo():
        print("hello")


p1 = Person("张三", 18)
# 实例对象调用类内公共方法eat(不是私有方法__eat),直接用 对象名.方法名(),
# 不需要传递self,会自动将实例对象名传递给self
print(p1.eat("红烧牛肉面"))

# 对象方法还可以用类名.方法名(),这种方式不会自动给self传参,
# 需要手动指定self,如 传p1给self
print(Person.eat(p1, "红烧牛肉面"))  # Person类对象,类名

Person.demo()
p1.demo()
# 类方法可以使用实例对象和类对象调用
print(p1.test())
print(Person.test())  #哈哈哈哈人类


# 静态方法:既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。
# 即可以用实例对象.add()  也可以类对象.add()  去调用静态方法
# 适用于不创建实例对象的场景
class Calculator(object):
    @staticmethod
    def add(a, b):
        return a + b


# 没有创建对象的必要, 直接使用类名.方法名(),
# c=Calculator()
# c.add(1,2)

Calculator.add(2, 3)

7.单例模式的设计:保证实例对象在全局的唯一性,(如 电脑的回收站)
  1.思想:创建两个私有的类的属性 __instance_01=None, __is_first=True,利用类的私有属性只能通过类对象修改这一该特点;且在外部无法随意修改;
                重写父类object的__new__方法:定义为类方法,获取类属性保证该类开辟的内存空间只此一块;
                重写父类object的__init__方法,
  2.单例模式:

# 单例设计模式:保证对象在全局里唯一;(电脑 回收站 唯一)
class Singleton(object):
    # 类属性在类空间中;
    # 如果 类属性和实例属性 同名,实例对象优先访问实例属性;
    # 但 类属性只能通过类对象进行修改;
    __instance1 = None
    __is_first = True

    # 定义为类方法,是为了获取类属性instance1
    # 改为__instance1私有属性更好,使外部无法访问此类方法,无法随意修改;
    @classmethod
    def __new__(cls, *args, **kwargs):
        if cls.__instance1 is None:
            cls.__instance1 = object.__new__(cls)  # 创建一个对象,申请内存,并把对象类型设置为cls
        return cls.__instance1

    # 改写__init__方法
    def __init__(self, a, b):
        # 类属性初始为true,__is_first是类属性,类属性可以用类对象或实例对象进行调用;
        # 第一次执行if段后,在实例对象内存空间中就添加了__is_first这个属性,且为false,
        # 后面的实例对象s2,s3首先会访问自己的实例属性 __is_first ,值为false,进行if判断, 
        # 所以之后的实例对象属性就无法覆盖第一次的属性值了
        # 这样就保证了属性值的唯一
        if self.__is_first:
            self.a = a
            self.b = b
            self.__is_first = False  # 在实例对象空间中添加了一个实例属性:__is_first
        # 执行后,在实例对象空间中有 a,b,__is_first 三个属性


# s1=Singleton('恭恭','喜喜')
# s2=Singleton('发发','财财')
# 普通创建s1 和 s2实例对象;是两个不同的实例对象,有两块内存空间,如何让它变成一个对象呢?
# 或者说:创建了一个实例对象s1,第二个创建的只能用第一个对象的地址空间

# 如何实现呢?
# 1.调用__new__方法申请内存空间,创建实例对象时,内部自动申请的
# 2.s1,s2都申请了内存空间,改写__new__方法限制实例申请空间,只能申请一次
# 3.  3.1 如果不重写__new__方法,会去调用object里的__new__方法,并申请内存空间
#     3.2 重写__new__方法,就需要自己手动申请内存空间了

# 开辟一段空间存放s1,此时空间中有 '恭恭', '喜喜', __is_first=False
s1 = Singleton('恭恭', '喜喜')
# 当类创建s2时,发现__new__方法行不通,且自己共用的s1空间中有 __is_first=False该属性,然后拿去判断if,也行不通
# 此时 公共实例对象空间的属性值将不会再被改变,单例模式设计成功
s2 = Singleton('发发', '财财')
s3 = Singleton('平平', '安安')

print(id(s1), id(s2))  # 29069168 29069168
print(s1 is s2)  # 此时为true,同一个对象,内存空间

# 同一块内存空间中:后面的值会覆盖前面的值,即此时 s1变为了 '发发','财财'
print(s1.a, s1.b)

 3.练习示例:

# 示例 : 计数 创建了几个实例对象
class Person(object):
    # count=0 # 定义为普通属性,
    __count = 0  # 定义为私有属性,外部无法访问,要在内部做一个接口函数get_count

    # 方法一:new方法中计数
    def __new__(cls, *args, **kwargs):
        cls.__count += 1
        return object.__new__(cls)

    # 方法二:init方法中计数
    def __init__(self, a, b):
        # Person.count += 1
        self.a = a
        self.b = b

    @classmethod
    def get_count(cls):
        return cls.__count


p1 = Person('张三', 18)
p2 = Person('张四', 19)
p3 = Person('李五', 20)

8. 封装继承多态的使用:
    封装:将类的属性或函数方法限制在类中使用,而外部无法调用。私有化就是必要的操作
    继承:1. 在类与类之间人为的建立父子关系,父类的属性和方法子类可以使用;支持多继承,如果有不同的父类名,但有相同的方法,遵从先到先得的顺序,先继承挨得近的父类及其父类的父类;如果这条路线上没找到所需方法,就换另一条树枝;遵从深度优先继承,然后再广度搜索;
               2. 类的私有属性和私有方法都不能通过对象直接访问,但可以在类内部使用;
                  类的私有属性和私有方法,都不会被子类继承;

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

    def sleep(self):
        print(self.name + "正在睡觉")


class Dog(Animal):
    def bark(self):
        print(self.name + "正在狗叫")


class Student(Animal):
    def study(self):
        print(self.name + "正在学习")


class weapon(object):
    def gutou(self):
        print(self.name + "用骨头当武器")


class Xiaotianquan(Dog, weapon):
    def fight(self):
        print(self.name + "在打狗")


# Dog() 会先调用__new__方法,再调用 __init__方法
# 1.Dog()没有__new__方法,会查看父类是否重写了__new__方法
# 2.父类也没有__new__方法,就会去查找父类的父类,找到了object,有__new__方法

# 调用__init__方法,Dog类没有,就会去找Animal父类的__init__
d1 = Dog("大黄", 2)  # 调用父类的__init__,需要传两个参数
print(d1.name)
d1.sleep()
d1.bark()
d2 = Xiaotianquan("哮天犬", 500)
d2.sleep()
d2.bark()
d2.fight()
d2.gutou()


# 私有属性和私有方法的继承特点: 父类中的私有属性方法不会被子类继承;

class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__money = 1000  # 父类的私有属性

    def eat(self):
        print(self.name + "正在吃东西")

    def __test(self):  # 父类的私有方法
        print("我是Animal类里的test方法")


class Person(Animal):
    def __demo(self):
        print("我是Person里的私有方法")

    def _Animal__test(self):
        pass


p = Person("张三", 18)
print(p.name)
p.eat()
p._Person__demo()  # 自己类里的定义的私有方法, 对象名._类名__私有方法名()
p._Animal__test()  # 父类的方法可以通过 对象名._父类名__私有方法名() 调用
p._Animal__money  # 父类的属性可以通过 对象名._父类名__私有属性名 调用


# 子类无法继承父类的私有属性和方法,
# print(p._person__test())  # 父类的私有方法,子类不能继承 'Person' object has no attribute '_person__test'
# print(p._Person__money)  # 继承的子类无法获取父类的私有属性  'Person' object has no attribute '_Person__money'

# 子类重写父类的方法
# 1.子类的实现和父类的实现完全不一样,子类可以选择重写父类的方法
# 2.子类在父类的基础上又添加了新的功能;
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sleep(self):
        print(self.name + "正在睡觉")


class Student(Person):
    def __init__(self, name, age, school):
        # 再写一次属性麻烦,继承调用父类有的属性 super().__init__(name,age)
        # self.name=name
        # self.age=age
        # 调用父类的两种方法:建议使用super()
        # 1. 父类名.方法名(self,形参)
        Person.__init__(self, name, age)
        # 2. 使用super() 直接调用父类的方法
        super().__init__(name, age)
        self.school = school  # 新加自己的属性

    def sleep(self):  # 重写该方法,调用的时候优先选取子类的同名方法
        print(self.name + "学生不能在课堂上睡觉")


s = Student("herry", 15, "忻州市一中")
s.sleep()
print(Student.__mro__)


     多态:一种技巧,提高代码灵活度;

# 多态的使用:
# 基于继承,通过子类重写父类的方法,达到不同的子类对象调用相同父类方法,
# 得到不同的结果
# 提高代码灵活度

# 不用多态的示例: 新增一个品类的狗 就要新建一种狗类,
# 代码构建冗余,不能灵活使用
class PoliceDog(object):
    def attack_enemy(self):
        print("警犬正在攻击敌人")


class BlindDog(object):
    def lead_road(self):
        print("导盲犬正在领路")


class DrugDog(object):
    def search_drug(self):
        print("缉毒犬正在搜查")


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

    def work_with_pd(self):
        print(self.name + "正在工作")
        self.dog.attack_enemy()

    def work_with_bd(self):
        self.dog.lead_road()

    def work_with_dd(self):
        self.dog.search_drug()






class Dog(object):
    def work(self):
        print("正在工作")
class PoliceDog(object):
    def work(self):
        print("警犬正在攻击敌人")


class BlindDog(object):
    def work(self):
        print("导盲犬正在领路")


class DrugDog(object):
    def work(self):
        print("缉毒犬正在搜查")


class Person1(object):
    # 此时self.dog=bd 
    def __init__(self, name, dog):
        self.name = name
        self.dog = dog

    def work_with_dog(self):
    # 实例对象bd调用work()实例方法
        self.dog.work()

bd = PoliceDog()
# 将实例对象bd作为参数传入Person类中
police = Person1("祁厅长", bd)
police.work_with_dog()

dd = DrugDog()
police = Person1("祁厅长", dd)
police.work_with_dog()

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贪财的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值