1、新式类和旧式(经典)类
新式类:以object为基类的类
经典类:不以object为基类的类
在python3.X中定义的类时,如果没有指定父类,会默认使用object作为基类–python3.x中定义的类都是新式类
在python2.x中定义类时,如果没有指定父类,则不会以object作为基类
为保证编写的代码能够同时在python2.x和python3.x运行,今后在定义类时,如果没有父类,建议统一继承自object
2、类属性和类方法
类属性:针对类本身定义的属性, 使用赋值语句在class关键字下可以定义类属性,这类属性归类本身所有。使用类名.属性
调用类属性
当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到,当实例并没有该属性,所以会继续查找class的该属性
class Animal(object):
name = 'Animal' #定义类属性
def run(self):
print('animal is running')
print(Animal.name) # 输出类属性
cat = Animal() # 实例化一个对象
print(cat.name) # 实例没有name属性,继续访问类属性
#输出结果:
Animal
Animal
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为实例属性优先级高于类属性。相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性
class Animal(object):
name = 'Animal' # 定义类属性name
def __init__(self,name):
self.name = name # 定义实例属性name
def run(self):
print('animal is running')
cat = Animal('tom') # 实例化一个实例
print(cat.name) # 打印类的name属性,由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
del cat.name #如果删除实例的name属性
print(cat.name) #再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
类方法:针对类定义的方法 在类方法内部可以直接访问类属性或者调用其他的类方法,直接使用 类名.类方法名称
调用类方法
格式:
@classmethod
def 方法名称(cls): # cls表示调用该方法的类本身
操作
class Animal(object):
name = 'Animal'
def run(self):
print('animal is running')
@classmethod
def speak(cls):
print(' %s can speak english' %cls.name)
cat = Animal()
Animal.speak()
#输出结果:
Animal can speak english
**应用实例:**统计创造的学生对象的数量
class Student(object):
count = 0
def __init__(self,name):
self.name = name
Student.count += 1
@classmethod
def Student_count(cls):
print(Student.count)
a = Student('tom')
b = Student('xixi')
c = Student('erpang')
Student.Student_count()
#输出结果:
3
3、私有属性和私有方法
私有属性:前面带两个下划线表示对变量进行私有化,私有化之后的属性属于类内部的属性,可以在内部进行访问,为不无法随便进行访问或者修改。
私有方法:方法名称前面带两个下划线表示方法私有化,可以在内部进行调用,不能使用实例在外部调用私有化方法。
定义方法
在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法
class Animal(object):
def __init__(self,name,color,weight):
self.name = name
self.color = color
self.__weight = weight # 定义私有属性
def run(self):
print('animal in running')
def weight(self):
print('animal is %s weight' %self.__weight)
def __speak(self): #定义私有方法
print('can speak english')
cat = Animal('tom','blue','35')
print(cat.name)
print(cat.color)
print(cat.__weight) # 无法直接访问私有属性
#输出结果:
tom
blue
print(cat.__weight)
AttributeError: 'Animal' object has no attribute '__weight' # 出现报错
cat = Animal('tom','blue','35')
cat.weight()
cat.run()
cat.__speak() #外部无法调用该私有方法
#输出结果:
Traceback (most recent call last):
File "/home/kiosk/PycharmProjects/20190523/6.13/练习7.py", line 21, in <module>
cat.__speak() # 出现报错
AttributeError: 'Animal' object has no attribute '__speak'
animal is 35 weight # 其他方法正常可以被调用
animal in running
4、静态方法
如果需要在类中定义一个方法,这个方法,既不需要访问实例属性也不需要调用实例方法;既不需要访问类属性也不需要调用类方法,这个时候就可以把这个方法封装成静态方法。使用@staticmethod关键字进行设置
格式:
class Cat(object):
@staticmethod
def run():
print('running')
可以直接使用类名.方法名
进行调用静态方法
class Cat(object):
@staticmethod
def run():
print('running')
Cat.run() #直接使用`类名.方法名`进行调用静态方法
tom = Cat()
tom.run() # 实例化对象,然后通过对象调用静态方法。
#输出结果:
running
running #两种方法输出一致
5、设计模式——单例
设计模式:
设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟解决方案,使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性
单例设计模式:
目的:让类创建对象,在系统中只有唯一的一个实例,每一次执行类名()返回的对象,内存地址是相同的
使用__new__(cls)方法实现单例设计模式:
我们用 类名. 的方式创建对象的时候,python解释器会帮我们做两件事情,
1.为对象分配空间
- __new__是一个由object基类提供的内置的静态方法,主要有两个作用: 在内存中为对象分配空间 返回对象的引用
- new:负责给对象分配空间,并返回对象的引用给初始化方法
2.对象初始化
__init__
(初始化方法)负责给对象初始化.- 解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法
重点
在Python3中,class定义的时候,如果不显式的写继承object,也是会默认自动继承object的,所以也会有__new__(cls)
也就是说在使用类名创建对象的时候,会自动的调用object基类中的__new__(cls)方法生成对象并返回对象的引用。
我们可以在类中对__new__(cls)方法进行重写,使其达到效果是:如果是第一次使用该类创建对象,那就在内存中为对象分配内存空间,并且返回对象的引用,如果已经创建过对象,那就不在重新分配内存空间,直接返回上依次创建好的内存空间即可。
所以需要一个类属性来记录是否已经创建过对象,以及存储第一次创建对象时分配的内存地址空间。
单例设计模式 示例:
class Dog(object):
__instance = None #定义类属性,判断是否第一次创建对象以及记录对象内存地址
def __new__(cls): #对父类方法进行重写
if cls.__instance == None: # None 就表示还没创建过对象
#调用object父类方法创建对象分配地址以及返回对象引用,由设定的类属性接收
cls.__instance = object.__new__(cls)
return cls.__instance # 如果是第一次创建 返回这个创建好的实例对象引用
else:
# 不是第一次创建,那么之前创建的对象地址的引用就是在cls.__instance中,直接返回。
return cls.__instance
多次创建对象,但是其内存地址只有一个:
a = Dog()
b = Dog()
c = Dog()
d = Dog()
print(a)
print(b)
print(c)
print(d)
#输出结果:
<__main__.Dog object at 0x7fa674e9b400>
<__main__.Dog object at 0x7fa674e9b400>
<__main__.Dog object at 0x7fa674e9b400>
<__main__.Dog object at 0x7fa674e9b400> # 创建的所有的对象均引用同一个内存地址。