python新手入门笔记(九)——面向对象的常见术语

私有属性和方法

私有化,在外部无法被访问,也无法被继承。

class Women:
    def __init__(self, name):
        self.name = name
        # 私有属性,外界无法直接获取的属性
        self.__age = 18
        # self._类名__age 私有化属性实际样式


    # 私有方法,不可被其他类继承
    def __secret(self):
        print(f'我的年龄是{self.__age}')

    def get_age(self):
        print(f'我的年龄是{self.__age}')

class Girl(Women):
    def get_age(self):无法
        print(f'我的年龄是{self.__age}')

if __name__ == '__main__':
    xiaohong = Women('小红')
    tiezhu = Girl('铁柱')
    print(tiezhu.name)
    tiezhu.get_age() # 'Girl' object has no attribute '_Girl__age',私有化方法无法继承,此处找不到私有化属性
    print(xiaohong.name)
    print(xiaohong._Women__age) # 常规写法不能用这个
    # print(xiaohong.__age)  # 'Women' object has no attribute '__age',外部不能直接访问私有化属性
    xiaohong.get_age()
    xiaohong._Women__secret() # 常规写法不能用这个

这里需要提的一点是:python的私有化是假的,它只是在被私有化的属性上加上了类名,即self._类名__age,包括私有化方法也是一样的。但是我们常规写法并不能使用该方法,被定义了私有化,就应使用私有化应有的调用方法来实现,否则便失去了私有化的意义。

类方法和静态方法

类方法:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法)。
静态方法:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法。

class Person:
    country = 'China'

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

    # 类方法
    @classmethod
    def get_country(cls):
        print(cls.country)
        cls.country = 'UK'
        print(cls.country)
     
    @staticmethod
    def info():
    	print('hahaha')
    
if __name__ == '__main__':
    xm = Person('小埋')
    print(xm.country)
    xm.get_country()

附一个小栗子:

class Game:
	class Game:
    # 游戏最高分,类属性
    top_score = 0

    @staticmethod
    def show_help():
        print('玩法说明:让僵尸走进房间')

    @classmethod
    def show_top_score(cls):
        print(f'游戏最高分{cls.top_score}')

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

    def start_game(self):
        print(f'{self.player_name}开始游戏')
        # 直接使用类名修改类属性
        Game.top_score = 777

if __name__ == '__main__':
    Game.show_help()# 静态方法的通过类对象直接调用
    Game.show_top_score()# 类方法的通过类对象直接调用

    game = Game('xm') # 创建实例对象
    game.start_game() # 实例对象的实例方法
    game.show_top_score() # 实例对象调用类方法

注:实例方法也可调用静态方法。

单例、单例模式

1、一个类同一时间只能有一个实例,比如电脑只能打开一个回收站。
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

class MusicPlayer:
    flag = None # 记录第一次被创建的对象
    flag_init = False#记录是否执行过init初始化操作
    # 为对象分配内存空间、将对象的引用返回
    #1 判断是否是空对象(空对象说明对象还没被创建)
    def __new__(cls, *args, **kwargs):# 创建实例对象前先被__new__方法分配内存空间
        if cls.flag is None:
            #2 调用父类的方法,为第一个对象分配空间,并把对象本身赋值给类属性cls.flag
            cls.flag = super().__new__(cls)
            # 返回生成的对象的引用给init
        return cls.flag
    print()
    #3 接收到对象、定义实例属性
    def __init__(self):# 分配完内存空间后再从__new__方法中拿回实例对象
        if not MusicPlayer.flag_init:
            print('初始化播放器对象')
            MusicPlayer.flag_init = True

player1 = MusicPlayer()
player2 = MusicPlayer()
print(id(player1))# 这两个实例对象的id是相同的
print(id(player2))

property属性

property是一个属性,而非函数,但它是用函数形式表示属性的。
当我们遇到需要进行一系列运算之后才能得到的属性时,就会用到property。

class Foo:
    def __init__(self,cur_page):
        self.cur_page = cur_page
        self.page_items = 10

    @property
    def start(self):# 这是一个属性
        # 有时候属性需要经过一系列运算得到,于是就产生了property
        val = (self.cur_page-1) * self.page_items + 1
        return val

    @property
    def end(self):
        val = self.cur_page * self.page_items
        return val

    def run(self):
		# 对于在别的函数中进行对property属性的调用,直接用self.所谓的函数名如self.start即可
        print(f'目前是第{self.cur_page}页,显示第{self.start}到第{self.end}条数据')


if __name__ == '__main__':
    foo_obj = Foo(2)
    foo_obj.run()

对于在别的函数中进行对property属性的调用,直接用self.所谓的函数名如self.start即可

对于getter和setter的调用

property的另一种用法。和java的getter和setter的用法相似,都是对私有化属性的调用。

class Person:
    def __init__(self,):
        self.__name = '小埋'
        self.__age = 18

    def set_name(self,name):
        self.__name = name

    def get_name(self):
        return self.__name

    def set_age(self,age):
        if 0 < age <= 120:
            self.__age = age
        else:
            print('你没了')

    def get_age(self):
        return self.__age

	# 这里需要注意的是,一个property只能有一对getter和setter,且getter在setter前面。
    name = property(get_name,set_name) 
    age = property(get_age,set_age)

xm = Person()
print(xm.name,xm.age)
xm.name = 'xx'
xm.age = 17
print(xm.name,xm.age)

动态添加属性和方法

属性和方法不仅能在类中添加,还能在类外部向类添加。

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

lbw = Man('lwb',18)
lbw.info = '赌怪'
print(lbw.info) #动态添加实例属性
Man.skill = '吃显示器' # 动态添加类属性
print(Man.skill)
# print(lbw.skill)

# 动态添加静态方法
@staticmethod
def say():
    print('卡布奇诺')
Man.say = say # 动态添加静态方法
lbw.say()

# 动态添加类方法
@classmethod
def zhibo(cls):
    print(cls.skill)
    print('--------------------')
Man.zhibo = zhibo # 动态添加类方法
lbw.zhibo()


def run(self):
    print(f'{self.name}说{self.info}')
lbw.run = run # 错误方法
lbw.run()

上述栗子表名可直接动态添加的属性和方法有——实例属性、类属性、静态方法、类方法。
实例方法不能直接添加,需要导入types包。

import types
class Man:
    def __init__(self,name,age):
        self.name = name
        self.age = age
def run(self):
    print(f'{self.name}说{self.info}')
Man.run = run # 此方法错误,但能运行得到正确结果
lbw.run()
lbw.run = types.MethodType(run,lbw) # 给对象绑定实例方法
lbw.run()

利用同样给静态方法、类方法的方式动态添加实例方法的确是可行的,但实例方法是给实例对象用的,而不是给类用的,用类名.实例方法名 = 实例方法名就相当于在类中添加了该方法,此时不仅特定的实例对象能用,还可以给别的实例对象用,这样的动态添加没有意义,还不如直接写进类中。

__ slots __

这算是动态添加的拓展。

__slots__属性限制了只有在__slots__序列中的属性才能被动态添加。
__slots__属性不会被继承
__slots__限制的是实例属性的添加

简单示例:

class A:
    __slots__ = ('name','age')# 动态添加指定,其他的无效

class B(A):
    pass
a = A()
a.name = '小埋'
a.age = 17
a.height = 170 # 这一步会报错
print(a.name,a.age,a.height)
b.height = 170
print(b.height)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值