python3 类方法,静态属性,静态方法,私有属性和私有方法,单例设计模式(重写__new__,值执行一次初始化方法)

1、类对象

  class A():  定义的类属于类对象;

  obj=A()   属于实例对象

  都在程序运行时,类会被加载到内存中;

  每创建一个对象,就是又创建了一个内存空间;

  obj=A():

    第一步:调用__new__方法,创建对象,通俗点说就是有个内存空间

    第二步:__init__————对刚刚申请的空间进行初始化

  在程序运行时,类对象在内存中只有一份,一个类可以创建出多个实例对象

  除了封装实例的属性和方法之外类对象还可以拥有自己的属性和方法。

2.类属性的定义和使用

  类变量指的是定义在类中,但在各个类方法外的变量。类变量的特点是:所有类的实例化对象都可以共享类变量的值,即类变量可以在所有实例化对象中作为公用资源。
  注意,类变量推荐直接用类名访问,但也可以使用对象名访问。可以通过类名访问类属性之外,还可以动态地为类和对象添加类变量

  类属性是大家都共享的,实例属性是自己私有的;

  类属性不会用于记录具体对象的特征;

 对象.类属性=值,只会给对象添加一个属性,而不会影响到类属性的值。

class Tool():
   #使用赋值语句定义类属性,记录所有工具对象的属性了
    count=0
    def __init__(self,name):
        self.name=name
        #类类属性+1
        Tool.count+=1

tool1=Tool("刀")
tool2=Tool("剑")
tool1=Tool("火")
tool1=Tool("箭")
print(Tool.count)


#########################
4
View Code
class Tool():
   #使用赋值语句定义类属性,记录所有工具对象的属性了
    count=0
    def __init__(self,name):
        self.name=name
        #类类属性+1
        Tool.count+=1

tool1=Tool("刀")
tool2=Tool("剑")
tool3=Tool("火")
tool4=Tool("箭")
tool1.count=100
# 使用赋值语句,类对象.类属性不会修改类属性的值
print(tool1.count)
print("%d" %Tool.count)

######################
100
4
View Code

 

3.类方法

   是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象本身,

一般以cls作为第一个参数(cls 参数的命名也不是规定的(可以随意命名),只是 Python 程序员约定俗称的习惯而已。),

能够通过实例对象和类对象去访问。

  类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。

class Tool():
   #使用赋值语句定义类属性,记录所有工具对象的属性了
    count=0
    @classmethod
    def show_tool_count(cls):
        print("工具对象的数量%d"  %cls.count)
    def __init__(self,name):
        self.name=name
        #类类属性+1
        Tool.count+=1

tool1=Tool("刀")
tool2=Tool("剑")
tool3=Tool("火")
tool4=Tool("箭")
# tool1.count=100
# # 使用赋值语句,类对象.类属性不会修改类属性的值
#   调用类方法
Tool.show_tool_count()



##########################
工具对象的数量4
View Code

https://blog.csdn.net/py_ccy/article/details/77127338

 4.静态方法

  静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定,

  也正是因为如此,此方法中无法调用任何类和对象的属性和方法,静态方法其实和类的关系不大。

  不需要访问实例属性或者是调用实例方法;

  也不需要访问类属性或者调用类方法。

    ————那么就可以吧这个方法封装成静态方法。

  静态方法需要用@staticmethod来表示。

  类名.调用静态方法。

class Dog():
    @staticmethod
    def bark():
        print("小动物都会叫喔!")
Dog.bark()

#####################
小动物都会叫喔!
View Code
__author__ = 'Administrator'
class Game():
    # 历史最高分
    top_score=0
    def __init__(self,player_name):
         self.player_name=player_name

    @staticmethod
    def show_help():
        print("帮助信息,让僵尸进入大门")

    @classmethod
    def show_top_score(cls):
        print("历史记录%d" %cls.top_score)

    def start_game(self):
        print("%s开始游戏了,冲啊" %self.player_name)

#1.查看游戏的帮助信息
Game.show_help()
#2.查看历史最高分
Game.show_top_score()
# 3.创建游戏对象
obj=Game("小猪猪")
obj.start_game()

#############################
帮助信息,让僵尸进入大门
历史记录0
小猪猪开始游戏了,冲啊
View Code

 5.实例属性和实例方法:

  实例属性:

    实例变量指的是定义在类的方法中的属性,它的特点是:只作用于调用方法的对象。

    注意,实例变量只能通过对象名访问,无法通过类名直接访问。

    Python 允许通过对象访问类变量,但无法通过对象修改类变量的值。因为,通过对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量。

    修改一个对象的实例变量,既不会影响类变量的值,也不会影响其它对象的实例变量。

  实例方法:

    类的实例方法由实例调用,至少包含一个self参数,且为第一个参数。执行实例方法时,会自动将调用该方法的实例赋值给self。self代表的是类的实例,而非类本身。self不是关键字,而是Python约定成俗的命名,你完全可以取别的名字,但不建议这么做。

三者方法的简单区别: 

class Person():
    name="肖战"
    def normalName(self):
        return self.name
    @classmethod
    def classMethodName(cls):
        return cls.name
    @staticmethod
    def staticMethodName(name):
        return name  #这里的name不是类变量name喔,可以看颜色
obj=Person()#初始化对象
#print(Person.normalName())# 报错 类不能直接访问实例方法(普通方法)
print(obj.normalName())#实例对象访问实例方法
print(Person.classMethodName())#
print(obj.classMethodName())
print(Person.staticMethodName("魏无羡"))
print(obj.staticMethodName("魏无羡"))

obj.name="王一博"
print("实例对象修改属性值后获取的属性值=========::::::")
print("obj.name:{}".format(obj.name))
print("obj.normalName():{}".format(obj.normalName()))
print("obj.classMethodName():{}".format(obj.classMethodName()))
print("Person.classMethodName():{}".format(Person.classMethodName()))
print("obj.staticMethodName(""):{}".format(obj.staticMethodName("蓝忘机")))
print("Person.staticMethodName(""):{}".format(Person.staticMethodName("蓝忘机")))
View Code

 

5.__new__方法

  该方法是一个由object基类提供的内置的静态方法,主要有以下作用:

    在内存中为对象分配空间;

    返回对象的引用。

  重写 __new__ 方法 一定要 return super().__new__(cls)(重写该方法的代码很固定)

     否则 Python 的解释器 得不到 分配了空间的 对象引用,就不会调用对象的初始化方法

     注意:__new__ 是一个静态方法,在调用时需要 主动传递 cls 参数

#重写__new__方法
class MusicPlayer():
    def __new__(cls, *args, **kwargs):
     #  1.创建对象时,new方法会被自动调用
        print("创建对象,分配空间")
    #  2.为对象分配空间
        instance=super().__new__(cls)
    #  3.返回对象的引用
        return instance
    #
    def __init__(self):
        print("播放器初始化")
player=MusicPlayer()
print(player)


###########################
创建对象,分配空间
播放器初始化
<__main__.MusicPlayer object at 0x0000000002B7FDA0>
View Code

 

6.单例

   单例——让类创建的对象,在系统中只有一个唯一的实例; 

内存地址不一样:

class MusicPlayer():
    pass

player1=MusicPlayer()
player2=MusicPlayer()
print(player1)
print(player2)


###################
<__main__.MusicPlayer object at 0x0000000002BEF208>
<__main__.MusicPlayer object at 0x0000000002BEF1D0>
View Code

 

单例设计模式实现内存地址一样:

  • 定义一个 类属性,初始值是 None,用于记录 单例对象的引用
  • 重写 __new__ 方法
  • 如果 类属性is None,调用父类方法分配空间,并在类属性中记录结果
  • 返回 类属性 中记录的 对象引用
class MusicPlayer():
    #  记录第一个被创建对象的引用
    instance=None

    def __new__(cls, *args, **kwargs):
        #  1.判断类属性是不是一个空对象
        if cls.instance is None:
        #  2.调用父类的方法,为第一个对象分配空间
            cls.instance=super().__new__(cls)
        #  3.返回了属性保存的对象引用
        return  cls.instance

player1=MusicPlayer()
player2=MusicPlayer()
print(player1)
print(player2)


########################
<__main__.MusicPlayer object at 0x00000000029CF1D0>
<__main__.MusicPlayer object at 0x00000000029CF1D0>
View Code

 

7.只执行一次__init__()方法

  • 定义一个类属性 init_flag 标记是否 执行过初始化动作,初始值为 False
  • 在 __init__ 方法中,判断 init_flag,如果为 False 就执行初始化动作
  • 然后将 init_flag 设置为 True
  • 这样,再次 自动 调用 __init__ 方法时,初始化动作就不会被再次执行 了
class MusicPlayer():
    #  记录第一个被创建对象的引用
    instance=None
    def __new__(cls, *args, **kwargs):
        #  1.判断类属性是不是一个空对象
        if cls.instance is None:
        #  2.调用父类的方法,为第一个对象分配空间
            cls.instance=super().__new__(cls)
        #  3.返回了属性保存的对象引用
        return  cls.instance

    def __init__(self):
        print("初始化执行")

player1=MusicPlayer()
player2=MusicPlayer()
print(player1)
print(player2)


####################################
初始化执行
初始化执行
<__main__.MusicPlayer object at 0x00000000011CFF28>
<__main__.MusicPlayer object at 0x00000000011CFF28>
View Code
class MusicPlayer():
    #  记录第一个被创建对象的引用
    instance=None
    #  记录是否执行过初始化动作
    init_flag=False
    def __new__(cls, *args, **kwargs):
        #  1.判断类属性是不是一个空对象
        if cls.instance is None:
        #  2.调用父类的方法,为第一个对象分配空间
            cls.instance=super().__new__(cls)
        #  3.返回了属性保存的对象引用
        return  cls.instance

    def __init__(self):
        #  1.判断是否普执行过初始化动作
        if MusicPlayer.init_flag:
            return
        #  2.如果执行过,在执行过初始化动作
        print("初始化执行")
        #  3.修改类属性的标记
        MusicPlayer.init_flag = True
player1=MusicPlayer()
player2=MusicPlayer()
print(player1)
print(player2)


###########################
初始化执行
<__main__.MusicPlayer object at 0x0000000002C7FDA0>
<__main__.MusicPlayer object at 0x0000000002C7FDA0>
View Code

8.私有化  

     私有属性——对象不希望公开的属性

  私有方法——对象不希望公开的方法

   定义方式:举例:

    num:共有变量

    _num:单前置下划线,私有化属性或方法,from module-name import * 禁止导入,类对象和子类可以访问

    __num:双前置下划线,避免与子类中的属性名冲突,无法在外部直接访问(名字重整所有访问不到)

通过name mangling(名字重整(目的就是预防子类意外重写基类的方法或者属性),如:_Class__object)机制就可以访问private了。

    __num__:双下置下划线,用户名字空间的魔法对象或属性,例如:__init__,不要自己发明这样的名字

    num__:单后置下划线,用于避免与python关键词的冲突。

但是,在python中,并没有真正意义的私有,并且在日常开发中,不要使用这种方式,访问对象的私有属性和私有方法。

处理方式:外界如何调用私有属性和私有方法【理论上用不了,但是实际上可以访问的】,但是在实际开发中,不要这样用,面试的时候可以吹一吹!!!! 

  • 在 名称 前面加上 _类名 => _类名__名称(xusanduo._Gun__fire)(类似这样)

 

 

posted @ 2018-09-19 20:20  小猪猪猪  阅读(516)  评论(0)    收藏  举报