python入门知识(八):装饰器+面对对象的三个特征+组合+设计模式

    科技2022-07-31  111

    文章目录

    一、方法的重载二、方法的动态性三、私有属性四、@property装饰器(一)使用装饰器调用方法(二)使用get和set修改属性(三)使用@property和set修改属性 五、面向对象的三大特征说明(封装、继承和多态)(一)继承1. 成员继承2.方法的重写3.object根类4.重写__str__()方法5.多重继承6.mro()7.super()获得父类定义 (二)同一方法调用多态 六、特殊方法和运算符重载七、特殊属性八、对象的浅拷贝和深拷贝九、组合十、设计模式(一)工厂模式的实现(二)单例模式的实现

    一、方法的重载

    python中没有方法的重载。在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可。方法签名包含3个部分:方法名、参数数量、参数类型。而在python中,如果定义了多个同名方法,那么只有最后一个有效,即方法可以重载。

    #python中没一个方法的重载。定义多个同名方法,只有最后一个有效 class person: def say_hi(self): print("hello") def say_hi(self,name): print("{0},hello".format(name)) p1=person() p1.say_hi() #不带参数,将会报错

    二、方法的动态性

    python是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类已有的方法。具体例子如下:

    class Person: def work(self): print("努力!") def play_game(s): print("{0}在玩游戏".format(s)) Person.play=play_game #为类添加新方法 p=Person() p.work() p.play()

    三、私有属性

    私有属性和私有方法,能够实现对象的封装,让外人不可随意查看。 就像电脑一样,只需要会用,不需要知道内部的工作原理。 注:方法本质上也是属性,只不过是通过()执行而已。要点: ①两个下划线开头的属性是私有属性:__私有属性名;其他的命名方法为公共属性; ②类内部可以直接访问私有属性(方法):类名.__私有属性名 ③类外部不能直接访问私有属性(方法),但可以通过“对象名._类名__私有属性(方法)名”访问私有属性(方法) class Employee: __company='百战' #类的私有属性 def __init__(self,name,age): self.name=name self.__age=age #实例的私有属性 def __work(self): #私有方法 print("{0} ,please work hard!".format(self.__age)) #在类内部,可以随意调用私有属性 print(Employee.__company) #类的私有属性的调用方法 e=Employee("何旯",18) print(e._Employee__age) #私有属性的调用方法 e._Employee__work() #私有方法的调用方法 print(e._Employee__company) #打印类的私有属性 print(dir(e)) #打印类可以调用的所有属性和方法

    四、@property装饰器

    (一)使用装饰器调用方法

    含义:@property可以将一个方法的调用方式变成“属性调用”使用方法:在方法的前一行,写上@property优点:调用方法时,不需要在后面加()了,像调用属性一样:对象名.方法名 class Empolyee: def salary(self): return 10000 #传统调用方式 emp1=Employee() #创建对象 print(emp1.salary()) #将会打印10000 #@property调用 class Empolyee: @property def salary(self): return 10000 emp1=Employee() #创建对象 print(emp1.salary) #像调用属性一样,调用方法,但emp1.salary无法更改

    (二)使用get和set修改属性

    #使用get和set方法修改属性 class Employee: def __init__(self,name,salary): self.__name=name #私有属性 self.__salary=salary def get_salary(self): return self.__salary def set_salary(self,salary): if 10000<salary<50000: self.__salary=salary #修改私有属性 else: print("输入错误!") emp1=Employee('高',30000) print(emp1.get_salary()) #打印30000 emp1.set_salary(-20000) print(emp1.get_salary()) #打印"录入错误!" emp1.set_salary(40000) print(emp1.get_salary()) #打印40000

    (三)使用@property和set修改属性

    #使用@property和set方法修改属性 class Employee: def __init__(self,name,salary): self.__name=name self.__salary=salary @property def salary(self): #对原来的get方法进行了简化 return self.__salary def set_salary(self,salary): if 10000<salary<50000: self.__salary=salary else: print("输入错误!") emp1=Employee('高',30000) print(emp1.salary) #使用装饰器后,调用方法时不需要加括号 emp1.set_salary(-20000) print(emp1.salary) #打印"录入错误!" emp1.set_salary(40000) print(emp1.salary) #打印40000 #可以看到使用@property装饰器,可以将get方法简化,可以直接将方法当作属性使用

    五、面向对象的三大特征说明(封装、继承和多态)

    python是面向对象语言。面向对象语言都有三大特性:封装(隐藏)、继承和多态。 封装(隐藏) 含义:隐藏对象的属性和实现细节,只对外暴露“相关调用方法”。实现方式:私有属性、私有方法 继承 继承可以让子类具有父类的特性,提高了代码的重用性原有父类设计不变的情况下,子类可以增加新的功能,或者改进已有算法 多态 含义:由于对象不同,同一个方法的调用会产生不同的行为例子:中国人用筷子吃饭,美国人用刀叉吃饭等

    (一)继承

    已有的类:父类 新的类:子类(派生类)

    1. 成员继承

    语法格式:class 子类类名(父类1[,父类2,…]):类体如果没有指定父类,则默认父类为object类。object类中定义了一些所有类共有的默认实现,比如__new__()定义子类时,必须在其构造函数中调用父类的构造函数。 #定义父类 class Person: def __init__(self,name,age): self.name=name self.__age=age def say_age(self): print("不知道") #定义子类 class Student(Person): def __init__(self,name,age,score): Person.__init__(self,name,age) #继承。这里不调用也不出错,但是如果不显式地调用父类初始化方法,解释器本身也不会去调用,就无法使用name,age Student.score =score #Student->Person->object stu1=Student("高",18,80) print(stu1.name) #将会打印出“高” print(stu1.age) #不会打印,因为age是私有属性 print(stu1.__Person__age) #通过print(dir(stu1)),可以看到打印age的方法。此处将会打印出18 stu1.say_age() #将会打印出不知道

    2.方法的重写

    #定义父类 class Person: def __init__(self,name,age): self.name=name self.__age=age def say_age(self): print("我的年龄为:",self.__age) def say_introduce(self): print("我的名字为:",self.name) #定义子类 class Student(Person): def __init__(self,name,age,score): Person.__init__(self,name,age) Student.score =score stu1=Student("高",18,80) stu1.say_age() #子类继承了父类的方法 stu1.say_introduce() #重写父类的方法 class Student(Person): def __init__(self,name,age,score): Person.__init__(self,name,age) Student.score =score def say_introduce(self): #由于python有方法的重载特性,直接在子类中定义一个重名方法,python将会调用子类的方法 print("报告老师,我的名字是:{0}".format(self.name)) stu1.say_introduce() #这时程序将会调用子类的方法

    3.object根类

    object根类:object根类是所有类的父类。学习object类的结构,对深入学习python有好处。使用dir()可以查看类的属性

    4.重写__str__()方法

    object有一个__str__()方法,用于返回对于“对象的描述”str()方法需要搭配printstr()方法可以重写 class Student: def __init__(self,name): self.name=name p=Student("gao") print(p) #这里会打印出关于对象p的地址 #测试重写object的__str__()方法 class Student: def __init__(self,name): self.name=name def __str__(self): return "名字是{0}".format(self.name) p=Student("gao") print(p) #使用str()方法改写后,这里会打印出“名字是gao”

    5.多重继承

    python支持多重继承,一个子类可以有多个父类,但是这样会被“类的整体层次”搞得异常复杂,应尽量避免使用。

    class A: def aa(self): print("aa") class B: def bb(self): print("bb") class C(A,B): def cc(self): print("cc") c=C() c.cc() #将会打印出cc c.aa() #将会打印出aa c.bb() #将会打印出bb

    6.mro()

    mro():通过类的方法mro()或者类的属性__mro__可以输出类的继承结构,或者说层次结构。

    例子如下:

    class A:pass class B(A):pass class C(B):pass print(C.miro())

    输出结果为:

    由于python支持多重继承,所以父类中如果有相同名字的方法,在子类没有指定父类名时,会按照“从左到右”的顺序搜索。 class A: def aa(self): print("aa") def say(self): print("say AAA!") class B: def bb(self): print("bb") def say(self): print("say BBB!") class C(A,B): def cc(self): print("cc") c=C() print(C.mro()) #打印类的层次结构 c.say() #A在B前,先调用A,再调用B

    7.super()获得父类定义

    在子类中,如果想要获得父类的方法时,需要通过super()来实现

    #测试super() class A: def say(self): print("A:",self) class B(A): def say(self): A.say(self) print("B:",self) B().say() #将会输出A:<__main__.B object at 0x021A6610>和B:<__main__.B object at 0x021A6610> #-------------或者是使用以下方式获得父类的方法----------- class B(A): def say(self): super().say() #使用super()替代父类,以获取父类方法 print("B:",self) B().say() #输出的效果如上

    (二)同一方法调用多态

    多态是指同一方法调用,由于对象不同可能产生不同行为。注: 1.多态是方法的多态,属性没有多态 2.多态的存在有两个必要条件:继承、方法重写 class Man: def eat(self): print("饿了,快吃饭") class Chinese(Man): def eat(self): print("筷子") class English(Man): def eat(self): print("叉子") class Indian(Man): def eat(self): print("右手") def manEat(m): if isinstance(m,Man): #多态。如果传进来的是Man的子类,则根据对象的不同调用不同的方法! m.eat() else: print("不能吃饭") manEat(Chinese()) manEat(English())

    六、特殊方法和运算符重载

    python的运算符实际上是通过调用对象的特殊方法实现的。比如:

    a=20 b=30 c=a+b d=a.__add_(b) #加号+的实质是调用了__add__()方法 print('c=',c) print('d=',d) #两者的运算结果相同

    每个运算符实际上都对应了相应的方法,统计如下: 这解释了为什么字符串也可以进行±*等等操作

    常见的特殊方法统计如下:

    运算符重载(实质是方法的重载) class Person: def __init__(self,name): self.name=name def __add__(self,other): if isinstance(other,Person): #判断other是不是Person类型 return "{0}--{1}".format(self.name,other.name) else: return "不是同类对象,不能相加" def __mul__(self,other): if isintance(other,int): #判断other是不是int类型 return self.name*other else: return "传入的数据不是整数类型,不能相乘" p1=Person("GA") p2=Person("ca") f=p1+p2 print(f) print(f*3)

    七、特殊属性

    obj.dict:获得类的属性字典 class c: def __init__(self,age): self.age=age g=c(20) print(g.__dict__) #将会输出{'age':20} obj.class:获得对象属于的类 class a: def say(self): print("不错") class c(a): def __init__(self,age): self.age=age g=c(20) print(g.__class__) #将会输出类为c的地址 obj.bases:当有多个父类时,将对象的父类的地址放在元组中 class a: def say(self): print("不错") class b: def say(self): print("很好") class c(a,b): def __init__(self,age): self.age=age g=c(20) print(g.__bases__) #将会输出a,b的地址组成的元组 obj.base:当只有单个父类时,输出对象的父类的地址obj.mro:类层次结构obj.subclass():子类列表 class a: def say(self): print("不错") class c(a): def __init__(self,age): self.age=age g=c(20) print(a.__subclass__()) #已知父类,输出子类。此处将会输出c的地址

    八、对象的浅拷贝和深拷贝

    变量赋值:形成两个变量(可以理解为标签),实质指向同一个对象(那么两个变量的地址仍然不变)浅拷贝:只拷贝了源对象,没有拷贝儿子和孙子,拷贝对象和源对象仍然指向同一个儿子和孙子。因此源对象和拷贝对象的地址不同,但是子对象的地址相同深拷贝:不仅拷贝了源对象,还拷贝了儿子和孙子。因此,源对象和拷贝对象的地址不同,其子对象的地址也不同

    九、组合

    继承:是“is a”的关系,如狗是动物组合:是“has a”的关系,如手机拥有cpu #继承 class A: def say_a1(self): print("a1") class B(a): pass b=B() b.say_a1 #类B继承了类A的方法 #组合 class C: def __init__(self,a): self.a=a class D: def say_d1(self,a): print("我是{0}".format(a)) c=C(D()) #将类D对类C进行组合 c.D.say_d1() #可以通过对象c调用对象D的方法

    十、设计模式

    (一)工厂模式的实现

    含义:设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候的固定做法。比较流行的是GOF(Goup Of Four)模式。工厂模式:能够实现创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制 例子如下: #测试工厂模式 class CarFactory: def create_car(self,brand): if brand =="奔驰": return Benz() elif brand=="宝马": return BNW() elif brand=="比亚迪": return BYD() else: return "未知品牌,无法创建" class Benz: pass class BNW: pass class BYD: pass factory=CarFactory() c1=factory.create_car("奔驰") c2=factory.create_car("比亚迪")

    (二)单例模式的实现

    核心作用:确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。优点:当一个对象的对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留于内存中,从而极大地降低开销。 class MySingleton: #单例对象需要重写new和init方法 __obj=None #类属性 __init__flag=True def __new__(cls,*args,**kwargs): if cls.__obj==NONE: #当类属性还没有建立时,创建一个类对象 cls.__obj=object.__new__(cls) return cls.__obj def __init__(self,name): if MySingleton.__init__flag==True: print("init...") self.name=name MySingleton.__init__flag==False a=MySingleton("aa") b=MySingleton("bb") #只会输出一次init... print(a) print(b) #a和b的地址都是一样的 #测试工厂模式的单例模式 class CarFactory: __new__=None __init__flag=True def __new__(cls,*args,**kwargs): if cls.__obj==NONE: #当类属性还没有建立时,创建一个类对象 cls.__obj=object.__new__(cls) return cls.__obj def __init__(self): if CarFactory.__init__flag==True: print("init CarFactory...") CarFactory.__init__flag==False def create_car(self,brand): if brand =="奔驰": return Benz() elif brand=="宝马": return BNW() elif brand=="比亚迪": return BYD() else: return "未知品牌,无法创建" class Benz: pass class BNW: pass class BYD: pass factory1=CarFactory() c1=factory1.create_car("奔驰") c2=factory1.create_car("比亚迪") factory2=CarFactory() print(factory1) print(factory2) #factory1和factory2的地址是一样的。
    Processed: 0.014, SQL: 8