对象
OOP
object oriented programming
使得数据的管理更加合理和自动化
减少程序出错
少写代码
程序更易维护
代码耦合性降低
-
类的构成
-
自定义类
-
创建对象
-
属性
属性是对类进行建模必不可少的内容,
方法是用来操作数据的,
而操作的大部分数据都是类自身的属性,以改变类的状态。
- 类属性
class Person(object):
#类属性:
#描述一个类的特征或者通过这个类创建出来所有对象的特征。
#定义在类内部,方法外的属性
country = '中国'
def __init__(self,name,age):
#实例属性(对象属性),描述一个对象的特征
#定义在init方法中,以self,开头标志着实例属性
self.name = name
self.age = age
-
实例属性
-
备注
在类的外部使用对象名获取属性,类的内部使用self获取属性
-
方法
-
实例方法
大部分的都是实例方法,调用的是类的实例 -
类方法
类装饰器
class Person(object):
#私有类属性
__country = '中国'
#自定义类方法
#使用修饰器,修饰方法是一个类方法
#cls ==class ==Person
#取值
@classmethod
def get_country(cls):
return cls.__country
#赋值
@classmethod
def set_country(cls,new_country):
cls.__country = new_country
- 静态方法
class A(object):
def __init__(self):
xxxx
@staticmethod
def hello():
print('hello')
- 备注
-
魔法方法
- _new_
监听对象,开辟空间创建并返回
当实例化对象的时候,第一个调用的就是__new__,是它完成了对象的创建,然后才有__init__,str...这些的
我们所自定义的类都可以理解为object的子类,所以__new__也就是继承于object,
当调用类方法的时候,用new来创建对象,然后找一个变量来接收new的返回值,这个返回值表示创建出来的对象的引用- 单例模式
#我们自定义类中的__new__是对object父类中的重写,
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
#有返回值,才能创建成功。
#如果我们要进行重写__new__,一般是用于单例模式
#当一个类服务于两个或多个类的时候,只针对于方法,不在乎对象。
#如果我们还是实例化对象来调用方法,那么会造成内存空间的浪费。(好多一样的数据)这时#我们就可以定义一个单例,只用一个对象就可以让其他调用
class Tool(object):
__instance = None
def __new__(cls, *args, **kwargs):
if not cls.__instance: #True False
cls.__instance=object.__new__(cls)
return cls.__instance
#完成单例模式,设为私有类属性,外部无法调用,None空值的使用,不占内存,为false。
def add(self,a,b):
return a+b
h1 = Tool()
print(h1.add(1,2))
h2 = Tool()
print(h2.add(2,2))
print(h1,h2)#两个对象的内存地址是一样的,达到了节省内存的目的
- _init_
当系统监听到通过这个类创建对象成功后就会进入这个魔法方法调用,在这个时间节点完成对象属性的初始化- 属性值相同
#属性名和值都一样的情况下
class Dog(object):
def __init__(self):
self.name = 'jm',
self.color = 'gold',
dog1 = Dog()
dog2 = Dog()
dog3 = Dog()
#在实例化创建对象完成,执行类中的魔法方法__init__,给对象属性赋值.
- 属性值不同,有参数传入
class Dog(object):
def __init__(self,name.color):
self.name = name,
self.color = color,
dog1 = Dog('jinmao','gold')
dog2 = Dog('jiwawa','white')
dog3 = Dog('bianmu','black')
#在init中设置形参接收实例化对象时所传入的参数,在init方法内将所接收参数赋值给对象.
- _str_
添加之后,打印的就可以是他的返回值。
def __str__(self):
return '%s的学号是%s,年龄是%s'%(self.name,self.no,self.age)
stu = Stu('小明','001',18)
没有添加之前,print(stu)得到的只是他的16进制内存地址
添加之后,print(stu)得到的就是__str__中的返回值
默认情况下 如果输出自定义对象 打印的是16进制内存地址
如果类中实现了__str__方法那么将打印的是__str__方法的返回值
__str__追踪对象的属性值变化,输出对象的描述信息
必须有一个返回值,且是一个字符串
-
_del_
监听对象销毁,
在程序退出之前,如果没有手动杀死对象,del就会帮我们杀死对象,完成内存的回收
监听对象的引用计数(地址引用)为0的时候调用- 手动销毁对象
del 对象名
del wk - 存在的问题
当对象内存地址被多次引用.必须把所有的引用都杀掉才能销毁对象
- 手动销毁对象
class D(object):
def __del__(self):
print('bye')
d=D()
d1=d
d2=d
d3=d
#d对象多了三个引用,指向的是同一块内存地址,
#所以
#del d 执行不了 __del__
#只有把所有的引用都del掉,才能销毁对象,打印出bye
del d
del d1
del d2
del d3
>>bye
- _call_
对象后面加括号,触发执行 - _doc_
表示类的描述信息,通常是官方的描述文档。 - _module_
表示当前操作的对象在那个模块 - _class_
获取当前操作类的一些属性,继承自object的一些属性
打印类名
class Man(object):
pass
m = Man()
print(m.__class__.__name__) >> Man
- _dict_
类或对象中的所有属性 - _all_
可以在模块的_init__中定义_all,对类进行限制,只有在_all_=[ ]这个列表中声明的类才能被外部所引用,如果没有设置这个列表,那么外部引用将会引用所有的public类及属性(非__开头的都被引用。) - self
那个对象调用了这个实例方法,self就是哪个对象
class Dog(object):
def eat(self):
print(self)
print('狗啃骨头')
dog = Dog()
print(dog)
dog.eat()
self就是dog对象.
-
三大特点
-
封装
-
继承
- 单继承
- 单继承
class Master(object):
def __init__(self):
# 添加属性并赋值
self.kongfu = "祖传古法配方"
# 制作古法煎饼果子
def make_cake(self):
print("制作古法煎饼果子...")
class Prentice(Master):
pass
dm = Prentice()
# 子类继承了父类 子类就继承父类的属性和方法
print(dm.kongfu)
dm.make_cake()
- 多继承
clss A(object):
def __init__(self):
self.name = 'A'
def run(self):
print('A_run')
def one(self):
print('one')
clss B(object):
def __init__(self):
self.name = 'B'
def run(self):
print('B_run')
def two(self):
print('two')
clss C(A,B): C继承了A.B
pass
c = C()
c.name = A
c.run >> A_run
C的实例化对象继承A,B类,在成功创建对象的时候,被监听到创建成功,执行__init__方法,第一个继承的是A类,所以使用的是A的__init__. 且 同名方法只继承第一个的,
c.one >> one
c.two >> two
非同名方法,子类都继承.
- 多继承顺序
class Parent(object):
def __init__(self, name):
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age):
self.age = age
Parent.__init__(self, name)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender):
self.gender = gender
Parent.__init__(self, name)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
Son1.__init__(self, name, age) # 单独调用父类的初始化方法
Son2.__init__(self, name, gender)
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
导致多次调用parent类,占空间
_mro_,打印继承路径,遇见super,在当前位置往上加1,
# 1024文件
# class A(object):
# def __init__(self,num):
# self.num = num
# @property
# def a(self):
# ret = self.num*self.num
# return ret
# b = A(10)
# print(b.a)
#
#
# import builtins
# p=builtins.property()
# a = p.getter('a')
# print(a)
class Parent(object):
def __init__(self, name):
self.name = name
print('parent的init结束被调用')
class Son1(Parent):
def __init__(self, name, age, *args, **kwargs):
self.age = age
super().__init__(name, *args, **kwargs)
print('Son1的init结束被调用')
class Son2(Parent):
def __init__(self, name, gender, *args, **kwargs):
self.gender = gender
super().__init__(name, *args, **kwargs)
print('Son2的init结束被调用')
class Grandson(Son1, Son2):
def __init__(self, name, age, gender):
super().__init__(name, age, gender)
print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print(Grandson.__mro__)
路径:(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
父类.init(self,name) = super().init(name)
传参用*args,**kwargs,防止报错。
- 重写
继承于父类后,用子类创建对象
子类调用一个方法
-如果子类有这个方法,那么久调用子类自己的
-如果没有,
先找第一个父类,有就用
第一个没有,找第二个,有就用
第二个没有,找object类,有就用
object类没有,就报错
1 父类名.同名方法名(self)
class Prentice(Master1,Master2):
def make_cake(self):
print('ooooo')
#注意self的传入
def make_oldcake(self):
Master1.make_cake(self)
# 注意self的传入
def make_newcake(self):
Master2.make_cake(self)
# 自定义古法师傅类
class Master(object):
def make_cake(self):
print("制作古法煎饼果子")
# 自定义现代师傅类
class School(object):
def make_cake(self):
print("制作现代煎饼果子")
class Prentice(Master, School):
# 重写
def make_cake(self):
print("制作猫式煎饼果子")
# 自定义
# 制作古法
def make_old_cake(self):
Master.make_cake(self)
# 自定义
# 制作现代
def make_new_cake(self):
School.make_cake(self)
dm = Prentice()
dm.make_cake()
dm.make_old_cake()
dm.make_new_cake()
调用父类同名方法
1 Master.make_cake(self)
2 super(Prentice,self).make_cake()
3 super().make_cake()
-
多层继承
-
多态
多种形式
不同的对象调用相同的方法,产生不同的结果,增加代码的灵活性
class Person(object):
def __init__(self,name):
self.name = name
def eat(self):
print('food')
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self):
print('狗粮')
定义一个服务于上面两个类的类
class Tool(object):
def fun(self,obj):
print(obj.name + '吃', end='')
obj.eat()
#实例化,目的也就是优化代码
t = Tool()
p2 = Person('peop')
t.fun(p2)
d2= Dog('dog')
t.fun(d2)
class Person(object):
def __init__(self,name):
self.name = name
def eat(self):
print('food')
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self):
print('狗粮')
定义一个服务于上面两个类的类
class Tool(object):
def fun(self,obj):
print(obj.name + '吃', end='')
obj.eat()
#实例化,目的也就是优化代码
t = Tool()
p2 = Person('peop')
t.fun(p2)
d2= Dog('dog')
t.fun(d2)
-
私有属性/方法
class Master(object):
def __init__(self):
#公有属性
self.kongfu = '古法'
#私有属性:
self.__age = 80
def make(self):
print('古法饼子')
self.__hello() #在函数内部调用私有方法
print('至今已有%s年'%self.__age)
def __hello(self):#私有方法
print('hello python')
dm = Prent()
dm.__hello()
这种调用时错误的,将会报错。attributeError
正确格式:(通过dir(对象名字)获得私有格式)
dm._Master__hello()调用成功
class Person(object):
def __init__(self):
self.name = '小明'
self.__age = 19
def get_age(self):
return self.__age
def set_age(self,new_age):
self.__age = new_age
sm = Person()
#取值
print(sm.get_age())
#更改
sm.set_age(20)
print(sm.get_age())
class Goods(object):
def __init__(self):
self.org_price = 1000
self.discount = 0.7
@property
def price(self):
ret = self.org_price * self.discount
return ret
@price.setter
def price(self,new_value): # 直接设置值
self.org_price = new_value
@price.deleter
def price(self):
del self.discount
# print("nihao")
g = Goods()
print(g.price)
g.price = 1500 #setter
print(g.price)
del g.price #deleter
print(g.price)
-
包的导入
name
在自定义模块中,用Python执行__name__时,打印得到的结果是__main__字符串,
当别的模块需要导入这个模块的时候,打印得到的结果就是这个模块的名字。
所以在用于自身测试的时候,用一个判断语句
if name =='__='main':
方法名()
方法名2()
加上这个语句,在自身测试可以出结果,在当做模块导入的时候不执行。