Python基础知识_day8_类的私有属性方法_装饰器_继承_组合

1. 方法的动态性

Python是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。

class Person:
    def work(self):
        print('努力上班')

def play_game(s):
    print(f'{s}在玩游戏')

def work2(s):
    print('tomorrow will be better')

Person.play = play_game
p = Person()
p.play() #等价于Person.play(p)
# <__main__.Person object at 0x0000026E4E877370>在玩游戏

Person.work = work2
p.work()
# tomorrow will be better

2. 私有属性和私有方法

关于私有属性和私有方法,有如下要点:

  • 通常我们约定,两个下划线开头的属性是私有的,其他为公共的
  • 类内部可以访问私有属性(方法)
  • 类外部不能直接访问私有属性(方法)
  • 类外部可以通过"_类名__私有属性(方法)名"访问私有属性(方法)

注:方法本质上也是属性,只不过是可以通过()执行而已。

2.1 私有属性举例

class Employee:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
p1 = Employee('Peter',23)

print(p1.name)
print(p1.age) #'Employee' object has no attribute 'age'
print(p1._Employee__age) #23

2.2 私有方法举例

class Employee:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def __work(self):
        print('好好工作')
        print(f'{self.__age}')
p1 = Employee('Peter',23)

p1._Employee__work()
#好好工作
#23

3. @property装饰器

3.1 @property

可以将一个方法的调用方式变成“属性调用”

class Employee:
    @property
    def salary(self):
        print('salary running...')
        return 10000
    
p1 = Employee()
print(p1.salary)
# salary running...
# 10000

3.2 setter,deleter

class Foo:
    @property
    def bmi(self):
        print('get的时候运行我啊')
        # 可以设置返回值

    @bmi.setter
    def bmi(self, value):
        print(value)  # 666
        print('set的时候运行我啊')
        # 无法得到返回值

    @bmi.deleter
    def bmi(self):
        print('delete的时候运行我啊')
        # 无法得到返回值

obj = Foo()
obj.bmi  # 改变了obj.bmi()的调用方式
obj.bmi = 666  # 操作命令,这个命令并不是改变bmi的值,而是执行被bmi.setter装饰器装饰的函数
del obj.bmi  # 操作命名,没有删除bmi,而是执行被bmi.deleter装饰器装饰的函数

4. 继承

如果在类定义中没有指定父类,则默认父类是object类。也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,比如__new__

子类以及对象可以调用父类的属性、方法,但不能改变

4.1 从类名执行父类的属性

class Animal:
    live = '有生命的'

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

    def eat(self):
        print('动物都需要进食')

class Person(Animal): # 括号内为父类
    pass

print(Person.__dict__) #虽然__dict__没有live属性,但子类可以执行父类的属性和方法
#{'__module__': '__main__', '__doc__': None}
print(Person.live)
#有生命的
Person.eat(1) #父类名.的方式调用父类方法。类名调用时,self需手动传,需手动写上要传递的内容
# 动物都需要进食

4.2 从对象角度执行父类的属性、方法

class Animal:
    live = '有生命的'

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

    def eat(self):
        print('动物都需要进食')

class Person(Animal):
    pass

p1 = Person('liye',21,'laddy_boy')
print(p1.__dict__) #从父类__init__为子类封装三个属性
# {'name': 'liye', 'age': 21, 'sex': 'laddy_boy'}
print(p1.live)  #有生命的
p1.eat()    #动物都需要进食

4.3 如何既要执行父类方法又要执行子类方法

  • 方法一
class Animal:
    live = '有生命的'

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

    def eat(self):
        print('动物都需要进食')

class Person(Animal):
    def __init__(self,name,age,sex,hobby): #p1自动传给self, self = p1
        Animal.__init__(self,name,age,sex) #这里的self等于上一行的self,也就是等于p1
        # 父类名.的方式调用父类方法,类名调用时,self需手动传,需手动写上要传递的内容
        # 这样实现通过父类__init__函数封装了name,age,sex三个属性
        self.hobby = hobby
    def eat(self):
        print('人类需要进食')

p1 = Person('怼怼哥',23,'不祥','music')
print(p1.__dict__)
# {'name': '怼怼哥', 'age': 23, 'sex': '不祥', 'hobby': 'music'}
  • 方法二
class Animal:
    live = '有生命的'

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

    def eat(self):
        print('动物都需要进食')

class Person(Animal):
    def __init__(self,name,age,sex,hobby):
        super().__init__(name,age,sex)
        self.hobby = hobby
    def eat(self):
        print('人类需要进食')

p1 = Person('怼怼哥',23,'不祥','laddy_boy')
print(p1.__dict__)
#{'name': '怼怼哥', 'age': 23, 'sex': '不祥', 'hobby': 'laddy_boy'}

4.4 object根类

object类是所有类的父类,因此所有的类都有object类的属性和方法。

4.4.1 mro()

通过类方法mro()或者类的属性__mro__可以输出这个类的继承层次结构

class A:pass
class B(A):pass
class C(B):pass
print(C.mro()) #或者 print(C.__mro__)
# [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

4.4.2 dir()查看对象属性

内置函数dir(),可以让我们方便的看到指定对象所有的属性。

方法实际上也是属性。只不过这个属性的类型是‘method’而已

class Animal:
    live = '有生命的'

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


    def eat(self):
        print('动物都需要进食')

class Person(Animal):
    def __init__(self,name,age):
        super().__init__(name)
        self.age = age
    def eat(self):
        print('人类需要进食')

p1 = Person('怼怼哥',23)
print(p1.__dict__)#{'name': '怼怼哥', 'age': 23}
print(type(p1.name)) #<class 'str'>
print(type(p1.eat)) #<class 'method'>
print(dir(p1))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat', 'live', 'name']

4.4.3__str__

打印一个对象就会触发__str__方法:打印对象传递给__str__方法的self

class Person:
    def __init__(self,name):
        self.name = name
    def __str__(self): #__str__必须返回字符串类型,print函数括号内的对象(即打印对象)传给self
        return '名字是{}'.format(self.name)
s = Person('ALEX')
print(s) #名字是ALEX 

4.5 多重继承

Python支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父类”的特点。但是这样会被“类的整体层次”搞的异常复杂,尽量避免使用。

如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索。
在这里插入图片描述

5. 特殊属性

Python对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。

特殊方法含义
obj.__dict__对象的属性字典
obj.__class__对象所属的类
class.__bases__类的基类元组(多继承)
class.__base__类的基类
class.__mro__类层次结构
class.__subclasses__()子类列表
class A:pass
class B:pass
class C(A,B):
    def __init__(self,name):
        self.name = name
dog = C('Puppy')

print(dir(dog))
print(dog.__dict__) #{'name': 'Puppy'}
print(dog.__class__) #<class '__main__.C'>
print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>)
print(C.mro()) #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
print(A.__subclasses__()) #[<class '__main__.C'>]

6. 组合

将一个类的对象封装成另一个类的对象的属性

'''需求:
1. 创建男生、女生类
2.在男生类中定义见面和吃饭方法,并实现吃完饭后去逛街(该方法在女生类中)
'''

class Boy:
    def __init__(self,name):
        self.name = name

    def meet(self,girl_friend = None):
        self.girl_friend = girl_friend #  girl_friend 的属性值 即为 flower 对象

    def have_a_dinner(self):
        if self.girl_friend:
            print('%s 和 %s 一起晚饭'%(self.name,self.girl_friend.name))  
            #self.girl_friend 整体相当于与flower对象
            self.girl_friend.shopping(self) 
            #等同于flower.shopping(),括号里的self为wu的对象空间
        else:
            print('单身狗,吃什么饭')

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

    def shopping(self,boy_friend): 
        #self == flower ,boy_friend 接收的是wu的对象空间
        #这里直接调用boy_friend即wu这个空间,没有对flower这个空间进行属性封装,当调用 boy_friend.name 时,boy_friend相当于一个变量而已,这个变量指向了 wu 这个空间,因此是可以执行的。
        #总结:对象空间里可以引用变量(变量未定义),但是变量指向了其他空间,因此是可以正常调用的
        print(f'{self.name}和{boy_friend.name}一起去逛街')

wu = Boy('吴超')

flower = Girl('如花',48) #实例化一个Girl对象
#组合:将一个类的对象封装成另一个类的对象的属性
wu.meet(flower)
# 给吴超这个对象封装一个 girl_friend 属性,属性值是 flower 这个对象,可以调用 flower 对象的属性和方法
wu.have_a_dinner()

7. 设计模式

7.1 工厂模式

class CarFactory:
    def create_car(self,brand):
        if brand == '奔驰':
            return Benz()
        elif brand == '宝马':
            return BMW
        elif brand == '比亚迪':
            return BYD()
        else:
            return '未知品牌,无法创建'
class Benz():
    pass
class BMW():
    pass
class BYD():
    pass
factory = CarFactory()
c1 = factory.create_car('奔驰')
c2 = factory.create_car('比亚迪')
print(c1) #<__main__.Benz object at 0x0000016F90739250>
print(c2) #<__main__.BYD object at 0x0000016FA9668AC0>

7.2 单例模式

单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。

单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个’单例对象’,然后永久驻留内存中,从而极大的降低开销。

class MySingleton:
    __obj = None
    __init_flag =True
    
    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)
        return cls.__obj
    
    def __init__(self,name):
        if MySingleton.__init_flag:
            print('init...')
            self.name = name
            MySingleton.__init_flag = False

a = MySingleton('AA') #init...
b = MySingleton('BB')
print(a)
# <__main__.MySingleton object at 0x000001DF072A9250>
print(b)
# <__main__.MySingleton object at 0x000001DF072A9250>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值