Python 面向对象
Python 面向对象
简介
编程有俩种编程方式:
- 面向过程
- 面向对象
创建对象
在python中使用 class关键字声明对象 注意命名方式 一般使用大驼峰命名法
class Student(object):
#class Student: 第二种声明方式
def __init__(self,name,age):
self.name=name
self.age=age
def sayhello(self):
print('Hello Object')
if __name__ == '__main__':
s1 = Student('zzy',20)
print(s1.name)
print(s1.age)
s1.sayhello()
对象中的魔法方法:
对象中的魔法方法 是自动调用的
- __ init__ 对象创建时调用
- __ del __ 对象销毁时调用
- __ call __ 可以让对象变成可以调用的函数
- __ repr __ 重写输出的对象的格式
- __ str __ 重写输出的对象的格式
- __ eq __ 对比表面值是否相等
- __ slots __ 设置属性是否可以在外部调用和添加
class Student(object):
#class Student:
__slots__ = ('name','age') # 对象中的对象是否可以让外部调用 可以调用的属性或者方法放入其中 如果没有在其中声明外部不可以给对象添加属性 和 方法
def __init__(self,name,age): # 对象创建的时候调用
self.name=name
self.age=age
def __del__(self): # 对象销毁的时候调用
print('对象已经删除')
def __call__(self, *args, **kwargs): # 可以让对象变成一个可调用的函数 外部可以直接使用s1() 调用对象中的__call__方法
pass
def __repr__(self): # 对象在输出的时候会输出 对象类型 和 对象的内存地址 重写这个 或者 str 方法 可以改变输出的内容
pass
def __str__(self): # repr 方法 注重的是 str 方法 注重的是 显示 一般使用str
pass
def __eq__(self, other): # == 在外部使用==号使用的就是对象中的eq方法 对象的比较使用 is 关键字 is对比的是内存地址 eq重写对比的是表面值
return self.name==other.name and self.age==other.age
def __gt__(self, other): # >
pass
def __ge__(self, other): # >=
pass
def __ne__(self, other): # !=
pass
def __lt__(self, other): # <
pass
def __le__(self, other): # <=
pass
def __int__(self): # int()
pass
def sayhello(self):
print('Hello Object')
if __name__ == '__main__':
s1 = Student('zzy',20)
s2 = Student('zzy',20)
print(s1 is s2) # flase is对比的是内存地址
print(s1 == s2) # true == 调用的是对象中的 __eq__方法
print(s1.name)
print(s1.age)
s1.sayhello()
内置属性
class Student(object):
# __slots__ = ('name','age') # 对象中的对象是否可以让外部调用 可以调用的属性或者方法放入其中 如果没有在其中声明外部不可以给对象添加属性 和 方法
def __init__(self,name,age): # 对象创建的时候调用
self.name=name
self.age=age
def hello(self):
print('hello python')
if __name__ == '__main__':
s1 = Student('zzy',20)
dir(s1)
print(s1.__class__) # <class '__main__.Student'> 模块名
print(s1.__dict__) # {'name': 'zzy', 'age': 20}把对象转化为字典
print(s1.__doc__) # 输出类的描述对象
print(s1.__module__) # 模块名
# print(s1.__slots__)
把对象当作字典使用
- setitem(self, key, value)
- getitem(self, item):
class Student(object):
# __slots__ = ('name','age') # 对象中的对象是否可以让外部调用 可以调用的属性或者方法放入其中 如果没有在其中声明外部不可以给对象添加属性 和 方法
def __init__(self,name,age): # 对象创建的时候调用
self.name=name
self.age=age
def __setitem__(self, key, value): # 当使用操作字典的 方式来设置对象属性时 会自动调用 setitem方法
self.__dict__[key]=value
def __getitem__(self, item): # 当使用操作字典的 方式来获取对象属性时 会自动调用 setitem方法
return self.__dict__[item]
def __str__(self):
return "name:{},age:{}".format(self.name,self.age)
def hello(self):
print('hello python')
if __name__ == '__main__':
s1 = Student('zzy',20)
print(s1['name'])
s1['age']=22
print(s1)
类属性和对象属性
class Student(object):
# __slots__ = ('name','age') # 对象中的对象是否可以让外部调用 可以调用的属性或者方法放入其中 如果没有在其中声明外部不可以给对象添加属性 和 方法
type='学生'
def __init__(self,name,age): # 对象创建的时候调用
self.name=name
self.age=age
def hello(self):
print('hello python')
if __name__ == '__main__':
s1 = Student('zzy',20)
s2 = Student('zjw',22)
print(Student.type) #学生
s1.type='hhh' # 注意 这里无法修改 类属性 只是在自己的内存中创建了一个新的属性
print(s1.type) # hhh
print(s2.type) # 学生
print(Student.type) # 学生
Student.type='xxx'
print(Student.type) # xxx 修改类属性
print(s2.type) # xxx s2没有type属性 所以使用的是 Student的类属性
print(s1.type) # hhh s1 拥有自己type属性 所以用自己的
私有方法 和 私有属性
以 __ 双下划线开头 表示 是 私有的属性 在外部不能直接获取
获取私有属性的方法
class Student(object):
def __init__(self,name,age,__money): # 对象创建的时候调用
self.name=name
self.age=age
self.__money=__money
def hello(self):
print('hello python')
def get_money(self):
return self.__money
def set_money(self,v):
self.__money=v
if __name__ == '__main__':
s1 = Student('zzy',20,300)
# print(s1.__money) 私有变量 无法获取
# 获取方式 1
print(s1._Student__money) # 私有方法同理
# 2 定义get set 方法获取
print(s1.get_money())
s1.set_money(20)
print(s1.get_money())
类方法和静态方法
class Student(object):
type='zzy'
def __init__(self, name, age): # 对象创建的时候调用
self.name = name
self.age = age
@staticmethod # 当你不需要对象的属性是可以使用static方法 类 或 对象 都可以调用
def hello():
print('hello python')
@classmethod # 类方法 如果一个函数只用到类属性 那么这个函数 可以定义为类方法 cls==Student true
def demo(cls):
print(cls.type) # 类方法可以调用本类中的属性 而静态方法不行
print('yes')
def eat(self):
print('eat')
if __name__ == '__main__':
s1 = Student('zzy', 20)
s1.eat() # eat
Student.eat(s1) # eat
Student.hello() # hello python
s1.hello() # hello python
Student.demo() # zzy yes
s1.demo() # zzy yes
# 总结 静态方法 无论是对象 还是 实列 都可以调用
## 类方法 无论是对象 还是 实列 都可以调用 但是 类方法可以使用类属性
# 实列方法 无论是对象还是 实列 都可以调用 但是类调用时 需要自己传参 而 实列对象 不需要
单例设计模式
简介 : 在一个范围内 只允许一个实列对象 把地址执行同一个地址
class Student(object):
__instance=None
__first = True
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls) # 改变对象的执行地址
return cls.__instance
def __init__(self, name, age): # 对象创建的时候调用
if self.__first:
self.name = name
self.age = age
self.__first=False # 只修改一次 后面无法修改
def eat(self):
print('eat')
if __name__ == '__main__':
s1 = Student('zzy', 20)
s2 = Student('zjy', 20)
print(s1 is s2) #True
print(s2.name,s2.age) # zzy 20
面向对象的三大特性 封装 继承 和 多态
封装
函数是对语句的封装 类是对函数和变量的封装
继承
类和类之间可以手动的建立父子关系 父类的属性和方法 子类可以使用
python 支持多继承
class Animal:
def __init__(self,name,age):
self.name=name
self.age=age
def sleep(self):
print(self.name,'sleep')
class Dog(Animal): # 括号中就是继承的父类
# def __init__(self, name, age):
# self.name = name
# self.age = age
#
# def sleep(self):
# print(self.name, 'sleep')
def ww(self):
print(self.name,'waowao')
class Student(Animal):
# def __init__(self, name, age):
# self.name = name
# self.age = age
#
# def sleep(self):
# print(self.name, 'sleep')
def study(self):
print(self.name, 'study')
if __name__ == '__main__':
d1 = Dog('旺财',5)
print(d1.name) # 在父类中声明的属性和方法 子类可以直接使用 注意 在类中没有重写 __ init __方法的话 会自动的去自己的父类去找 找到使用父类的方法 没找到去object类的__init__方法
print(d1.age)
d1.sleep()
d1.ww()
继承顺序 和 深度优先
使用 __ mro __ 属性查看调用顺序
class Animal:
def __init__(self,name,age):
self.name=name
self.age=age
def sleep(self):
print(self.name,'sleep')
class People:
def __init__(self,height):
self.height=height
def run(self):
print('run')
class Student(Animal,People):
def study(self):
print(self.name, 'study')
if __name__ == '__main__':
s1=Student('zzy',2) # 如果 有相同的方法 那么继承的是前面的那个类的 方法 先到先得 深度优先 如 __inti__ 方法 使用的是Animal 的方法
print(Student.__mro__) # (<class '__main__.Student'>, <class '__main__.Animal'>, <class '__main__.People'>, <class # #'object'>) 调用的顺序
s1.sleep()
s1.run()
s1.study()
私有属性 和 私有方法的不能被继承
class Animal:
def __init__(self,name,age,money):
self.name=name
self.age=age
self.__money = money
def sleep(self):
print(self.name,'sleep')
def __hh(self):
print('不能调用')
class Student(Animal):
def study(self):
print(self.name, 'study')
def __hq(self):
print('hql')
if __name__ == '__main__':
s1=Student('zzy',2,1000)
print(s1.name) # 可以
print(s1.age) # 可以
s1.study() #可以
s1._Student__hq() # 自己类中定义的私有方法可以调用
# print(s1._Animal__money) 1000 # 继承的私有方法和属性都是无法调用 的 私有属性不继承 但是 可以通过 父类直接调用
# s1._Animal__hh() 输出 不能调用
子类重写父类方法
super 关键字
class Animal:
def __init__(self,name,age):
self.name=name
self.age=age
def sleep(self):
print('Animal sleep')
class Student(Animal):
def __init__(self,name,age,height):
super(Student, self).__init__(name,age) # super 当继承的方法不再满足子类的需求时 可以使用super 调用父类的方法
self.height = height
def __str__(self):
return 'name:{} age:{} height:{}'.format(self.name,self.age,self.height)
def study(self):
print(self.name, 'study')
def sleep(self):
print('Student sleep')
if __name__ == '__main__':
s1=Student('zzy',20,180) # 如果 有相同的方法 那么继承的是前面的那个类的 方法 先到先得 深度优先
s1.sleep() # Student sleep 调用自己的方法
print(s1) # name:zzy age:20 height:180
多态
多态是基于继承 通过子类重写父类的方法
达到不同的子类对象调用相同的父类方法 得到不同的结果
作业 提高代码的灵活度
class Dog(object):
def work(self):
print("狗在工作")
class OneDog(Dog):
def work(self):
print('OneDog在工作')
class TwoDog(Dog):
def work(self):
print('TwoDog 在工作')
class People(object):
def __init__(self,name,dog):
self.name = name
self.dog = dog
def people_dog(self):
self.dog.work()
if __name__ == '__main__':
one_dog = OneDog()
two_dog = TwoDog()
p = People('zzy',one_dog)
p.dog.work() # 输入不同的狗 会执行不同的狗的办法 增加的代码的灵活性
p2 = People('zzy',two_dog)
p2.dog.work()
有关对象的相关方法
- is 身份运算符 是用来比较两个对象 是否是同一个对象 比较的是地址
- isinstance 用来判断一个对象是否是由指定的类 (或者父类)实列化出来的 isinstanc(p1,Student)
- issubclass 用来判断一个类是否是另一个类的子类