2021-08-13 面向对象的编程(2)封装、继承、多态-Day09

面向对象的编程(2)-Day09

方法的动态性

-python是动态语言,可以动态的为类添加新的方法
-动态的修改类的已有的方法

#测试方法的动态性
class Person:
	def work(self):
		print("努力上班!")
def play_game(self):
	print("{0}玩游戏".format(self))
def work2(s):
	print("好好工作,努力上班!")

Person.play = play_game
Person.work = work2
p = Person()
p.play()
p.work()

上述代码显示,Person新增了play_game的方法,并且新增的方法work2替换掉了原有的work方法。

私有属性和私有方法–实现封装
  • 约定:两个下划线__开头的属性是私有的private,其余的是公共public
  • 类的内部可以访问私有属性和方法
  • 类的外部不能直接访问私有属性和方法
  • 类的外部需要通过"_类名__私有属性(方法)名称" 来访问私有属性
class Employee:
    __company = "百战程序员" #私有类属性. 通过 dir 可以查到_Employee__company

    def __init__(self,name,age):
        self.name = name
        self.__age = age #私有实例属性

    def say_company(self):
        print("我的公司是:",Employee.__company) #类内部可以直接访问私有属性
        print(self.name,"的年龄是:",self.__age)
        self.__work()
    def __work(self): #私有实例方法 通过 dir 可以查到_Employee__work
        print("工作!好好工作,好好赚钱,娶个媳妇!")

p1 = Employee("高淇",32)
print(p1.name)
print(dir(p1))
p1.say_company()
print(p1._Employee__age) #通过这种方式可以直接访问到私有属性 。通过 dir 可以查到属性:_Employee__age
print(p1.__age) #直接访问私有属性,报错
#p1.__sleep() #直接访问私有方法,报错

结果:

Traceback (most recent call last):
  File "C:/Users/housong/PycharmProjects/pythonProject/main.py", line 20, in <module>
    print(p1.__age) #直接访问私有属性,报错
AttributeError: 'Employee' object has no attribute '__age'
高淇
['_Employee__age', '_Employee__company', '_Employee__work', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'say_company']
我的公司是: 百战程序员
高淇 的年龄是: 32
工作!好好工作,好好赚钱,娶个媳妇!
32
@property 装饰器

@property可以把一个方法的调用方式变成"属性调用"

#简单测试@property
class Employee:
    @property
    def salary(self):
    	return 30000;

emp1 = Employee()
print(emp1.salary) #打印 30000
print(type(emp1.salary)) #打印<class 'int'>
emp1.salary() #报错:TypeError: 'int' object is notcallable
#emp1.salary =1000 #@property 修饰的属性,如果没有加 setter 方法,则为只读属性。此处修改报错:AttributeError: can't set attribute

结果:

Traceback (most recent call last):
  File "C:/Users/housong/PycharmProjects/pythonProject/main.py", line 10, in <module>
    emp1.salary() #报错:TypeError: 'int' object is notcallable
TypeError: 'int' object is not callable
30000
<class 'int'>

@property 主要用于帮助我们处理属性的读操作、写操作。如果直接读写会不安全,需要通过getter和setter的方法。

class Employee:
	'''雇员类,包含姓名和薪水属性'''
    def __init__(self,name,salary):
        self.name = name
        self.__salary = salary

    @property
    def salary(self):
        print("月薪{0},年薪{1}".format(self.__salary,(12*self.__salary)))
        return self.__salary;

    @salary.setter
    def salary(self,salary):
        if(0<salary<100000):
            self.salary = salary
        else:
            print("薪水录入有误!限值在0-100000之间")

staff1 = Employee("hoesen",200)
print(staff1.salary)
staff1.salary = -200

结果:

月薪200,年薪2400
200
薪水录入有误!限值在0-100000之间
属性和方法命名总结

方法和属性都遵循下面的规则:

  • _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访
    问这些成员
  • xxx:系统定义的特殊成员
  • __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外
    部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)
面向对象三大特征
  • 封装
    • 隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只
      对外暴露“相关调用方法”
    • 通过“私有属性、私有方法”的方式,实现“封装”。
  • 继承
    继承可以让子类具有父类的特性,提高了代码的重用性
  • 多态
    多态是指同一个方法调用由于对象不同会产生不同的行为
继承
  • 继承的语法格式
    Python 支持多重继承,一个子类可以继承多个父类。
class 子类类名(父类 1[,父类 2...]):
	类体
  • 如果在类定义中没有指定父类,则默认父类是 object 类
  • object 是所有类的父
    类,里面定义了一些所有类共有的默认实现,比如:new()
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show_age(self):
        print(self.name,"的年龄是",self.age,"\n")

class Student(Person):
    def __init__(self,name,age,score):
        self.score = score
        Person.__init__(self, name, age) #子类的构造函数中一般需要调用父类的构造函数(根据需要,非必须),子类不会自动调用父类的__init__()

s11 = Student("小明",16,99)
print(s11.name,'今年',s11.age,'岁。','期末考试',s11.score,'分。(年龄调用的是属性.age)')
print('下面这个年龄调用的是类中的方法:show_age()')
s11.show_age()
print('s11实例(或者Student类)的所有属性:',dir(s11))

运行结果:

小明 今年 16 岁。 期末考试 99 分。(年龄调用的是属性.age)
下面这个年龄调用的是类中的方法:show_age()
小明 的年龄是 16 

s11实例(或者Student类)的所有属性: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'score', 'show_age']
类成员的继承和重写
  • 成员继承:子类继承了父类除构造方法之外的所有成员
  • 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”
    下面代码仅在上面代码上新增子类的方法,覆盖掉父类的
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def show_age(self):
        print(self.name,"的年龄是",self.age,"\n")

class Student(Person):
    def __init__(self,name,age,score):
        self.score = score
        Person.__init__(self, name, age) #子类的构造函数中一般需要调用父类的构造函数(根据需要,非必须),子类不会自动调用父类的__init__()

    def show_age(self):
        print(self.name,"的年龄年龄年龄是",self.age,'岁!(这里是,子类重写了show_age()方法)')

s11 = Student("小明",16,99)
print(s11.name,'今年',s11.age,'岁。','期末考试',s11.score,'分。(年龄调用的是属性.age)')
print('下面这个年龄调用的是类中的方法:show_age()')
s11.show_age()
print('s11实例(或者Student类)的所有属性:',dir(s11))

运行结果:

小明 今年 16 岁。 期末考试 99 分。(年龄调用的是属性.age)
下面这个年龄调用的是类中的方法:show_age()
小明 的年龄年龄年龄是 16 岁!(这里是,子类重写了show_age()方法)
s11实例(或者Student类)的所有属性: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'score', 'show_age']
类的继承层次查看:mro()或者_mro_
class A:pass
class B(A):pass
class C(B):pass
print('A的继承层次:',A.mro())
print('B的继承层次:',B.mro())
print('C的继承层次:',C.mro())

运行结果:

A的继承层次: [<class '__main__.A'>, <class 'object'>]
B的继承层次: [<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
C的继承层次: [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
重写父类的__str__()方法
class A:pass
print(dir(A))
print(A.__str__)
class B(A):
    def __str__(self):
        return "子类B重写了父类的__str__(),以此留念~"
b = B()
print(b)

运行结果:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
<slot wrapper '__str__' of 'object' objects>
子类B重写了父类的__str__(),以此留念~
super() 获取父类的定义
class A:
    def say(self):
        print("A: ",self)
        print("say AAA")
class B(A):
    def say(self):
        #A.say(self) 调用父类的 say 方法
        super().say() #通过 super()调用父类的方法
        print("say BBB")
b = B()
b.say()

运行结果:

A:  <__main__.B object at 0x00000298FFDD76A0>
say AAA
say BBB
多态
  • 多态是指同一个方法调用由于对象不同会产生不同的行为
  • 多态是方法的多态,属性不存在多态一说
  • 多态的存在有2个必要条件:继承、方法重写
class Animal:
    def shout(self):
        print("动物叫了一声")
class Dog(Animal):
    def shout(self):
        print("小狗,汪汪汪")
class Cat(Animal):
    def shout(self):
        print("小猫,喵喵喵")
def animalShout(a):
    if isinstance(a,Animal):
        a.shout() #传入的对象不同,shout 方法对应的实际行为也不同。

animalShout(Dog())
animalShout(Cat())

运行结果:

小狗,汪汪汪
小猫,喵喵喵
特殊方法和运算符重载
  • python运算符实际上是通过调用对象的特殊方法来实现的
    a + b
    a.add(b)
常见的特殊方法:

方法 说明 例子
init 构造方法 对象创建:p = Person()
del 析构方法 对象回收
repr,str 打印,转换 print(a)
call 函数调用 a()
getattr 点号运算 a.xxx
setattr 属性赋值 a.xxx = value
getitem 索引运算 a[key]
setitem 索引赋值 a[key]=value
len 长度 len(a)

运算符对应的特殊方法:

运算符 特殊方法 说明
运算符+ add 加法
运算符- sub 减法
<,<=,== lt,leeq 比较运算符

,>=,!= gt,ge,ne 比较运算符
|,^,& or,xor,and 或、异或、与
<<,>> lshift,rshift 左移、右移
*,/,%,// mul,truediv,mod,
floordiv 乘、浮点除、模运算(取余)、整数除
** pow 指数运算

  • 重写上面的特殊方法,即可实现了“运算符的重载”
特殊属性

python对象包含了许多双下划线开始和结束的属性,是特殊属性,有着特殊用法。

常见的特殊属性:

特殊方法 含义
obj.dict 对象的属性字典
obj.class 对象所属的类
class.bases 类的基类元组(多继承)
class.base 类的基类
class.mro 类层次结构
class.subclasses() 子类列表

#测试特殊属性
class A:
    pass
class B:
    pass
class C(B,A):
    def __init__(self,nn):
        self.nn = nn
    def cc(self):
        print("cc")

c = C(3)
print(dir(c))
print(c.__dict__)
print(c.__class__)
print('C.__bases__:',C.__bases__)
print('C.mro():',C.mro())
print('A.__subclasses__():',A.__subclasses__())
print('B.__subclasses__():',B.__subclasses__())

运行结果:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cc', 'nn']
{'nn': 3}
<class '__main__.C'>
C.__bases__: (<class '__main__.B'>, <class '__main__.A'>)
C.mro(): [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
A.__subclasses__(): [<class '__main__.C'>]
B.__subclasses__(): [<class '__main__.C'>]
对象的浅拷贝和深拷贝
  • 浅拷贝copy.copy():新建一个新的对象,指向源对象的子对象。子对象不会被copy(换汤不换药)
  • 深拷贝copy.deepcopy():新建一个新的对象,并且把源对象的子对象也copy下来,新建了新的子对象(另起山头)
import copy

class Moon:
    def __init__(self,state):
        self.state = state
class Cpu:
    def cpu(self):
        print('在哪里?',self,'\n')

s = Cpu()
m1 = Moon(s)
m2=copy.copy(m1)
m3=copy.deepcopy(m1)

print('id(m1)?',id(m1))
print('m2浅拷贝了m1,那么id(m2)?',id(m2))
print('m3深拷贝了m1,那么id(m3)?',id(m3),'\n')

print("m1.state.cpu:")
m1.state.cpu()
print("浅拷贝的子对象:m2.state.cpu:")
m2.state.cpu()
print("深拷贝的子对象:m3.state.cpu:")
m3.state.cpu()
id(m1)2518656778640
m2浅拷贝了m1,那么id(m2)2518687264928
m3深拷贝了m1,那么id(m3)2518687265456 

m1.state.cpu:
在哪里? <__main__.Cpu object at 0x0000024A6BA486D0> 

浅拷贝的子对象:m2.state.cpu:
在哪里? <__main__.Cpu object at 0x0000024A6BA486D0> 

深拷贝的子对象:m3.state.cpu:
在哪里? <__main__.Cpu object at 0x0000024A6E7BC760> 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值