方法的动态性+私有属性/私有方法+@property装饰器+继承+多态+运算符重载+特殊属性+对象的深拷贝/浅拷贝+工厂模式+单例模式+工厂和单例的混合

目录

一、方法的动态性

二、私有属性和私有方法(实现方法)

(一)私有属性

(二)私有方法

三、@property装饰器

四、面向对象的三大特征介绍

1、封装(隐藏)

2、继承

3、多态

五、运算符重载

六、特殊属性

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

八、组合

九、工厂模式

十、单例模式

目录

一、方法的动态性

二、私有属性和私有方法(实现方法)

(一)私有属性

(二)私有方法

三、@property装饰器

四、面向对象的三大特征介绍

1、封装(隐藏)

2、继承

3、多态

五、运算符重载

六、特殊属性

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

八、组合

九、工厂模式

十、单例模式

十一、单例模式和工厂模式的组合


 


一、方法的动态性

在其他语言,可以定义多个重名的方法,只要保证方法签名——形参列表,唯一即可。但在python里面,方法的参数没有声明类型,参数的数量也可以由可变参数控制

所以,不要使用重名的方法,定义了多个同名函数之后,只有最后一个函数可以被识别调用。

方法的动态性:python是动态语言,我们可以动态得为类添加新方法,或者动态修改类已有的方法

class Person:

    def work(self):
        print("努力上班")


def play_game(a):
    print("{0}谁在玩游戏".format(a))


Person.play = play_game  #把方法直接赋为类Person里的类方法


def work2(s):
    print("好好工作,努力上班!")

P = Person()
P.work()
P.play()    #P.play()从本质上来说等同于Person.play_game(P)所以,只需要把函数赋给Person即可。

Person.work = work2  #更新了原来的类方法work,变成了work2()
P.work()
#好好工作,努力上班!

二、私有属性和私有方法(实现方法)

(一)私有属性

1、通常我们约定,两个下划线开头的属性是私有的,其他为公共属性;

2、类内部可以直接访问私有属性(方法);

3、类外部不能直接访问私有属性(方法);

4、类外部可以通过“__类名__私有属性(方法)名”访问私有属性(方法)

#公共属性
class Employee:

    def __init__(self, name, age):
        self.name = name
        self.age = age

e = Employee("高宇星", 18)
print(e.name)
print(e.age)
#高宇星
#18


#私有属性
class Employee:

    def __init__(self, name, age):
        self.name = name
        self.__age = age

e = Employee("高宇星", 18)
print(e.name)
print(e.age)
#AttributeError: 'Employee' object has no attribute 'age'

当属性变为私有时,不能直接访问,否则会报错


正确的操作方式如下:
#通过__命名私有属性,私有属性不能直接被外部访问,如果想要访问,必须通过_方法名__私有属性
class Employee:

    def __init__(self, name, age):
        self.name = name
        self.__age = age

e = Employee("高宇星", 18)
print(e.name)

print(e._Employee__age)
#18

print(dir(e))
#['_Employee__age', '__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']

(二)私有方法

在类内部调用自己的属性或方法,直接用self.__属性。

#测试私有方法
class Employee:

    __Company = "华为"

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

    def __work(self):   #定义一个私有的方法
        print("好好学习,天天向上呀")
        print("年龄:{0}".format(self.__age)) #在类的内部自己调用自己的方法,是完全可以的
        print(Employee.__Company)



e = Employee("高宇星", 18)
print(e.name)

print(e._Employee__age)
#18

e._Employee__work()

三、@property装饰器

#测试@property的用法

class Employee:

    @property  #装饰器
    def  salary(self):
        print("salary run ···")
        return 10000

emp1 = Employee()
#emp1.salary()
#salary run ···

print(emp1.salary)  #直接把方法当做属性来调用
#emp1.salary = 20000   #AttributeError: can't set attribute 会报错,不能给salary设置属性

当我们的属性可以直接被外部调用的时候,很容易出现录入错误数据并输出错误数据的现象

这个时候,为了解决这个问题,我们可以先将属性私有化

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 1000 < salary < 500000:
            self.__salary = salary
        else:
            print("工资输入有误,薪水在1000到50000这个范围")


emp1 = Employee("高宇星", 30000)
print(emp1.get_salary())
#30000
emp1.set_salary(-290000)
print(emp1.get_salary())
#工资输入有误,薪水在1000到50000这个范围

emp1.set_salary(20000)
print(emp1.get_salary())
#20000

同时,也可以利用装饰器

1、将一个方法的调用方式变成“属性调用”;

2、一般用来给我们的属性设置get和set方法;

class Employee:

    def __init__(self, name, salary):
        self.name = name
        self.__salary = salary

    @property
    def salary(self):
        return self.__salary

    @salary.setter
    def salary(self, salary):
        if 1000 < salary < 500000:
            self.__salary = salary
        else:
            print("工资输入有误,薪水在1000到50000这个范围")


emp1 = Employee("高宇星", 30000)
print(emp1.salary)
#30000

emp1.salary = -2000
print(emp1.salary)
#工资输入有误,薪水在1000到50000这个范围

emp1.salary = 2000
print(emp1.salary)
#2000

四、面向对象的三大特征介绍

1、封装(隐藏)

隐藏对象的属性和实现细节,只对外提供必要的方法。通过“私有属性和私有方法”等方式来实现封装,没有严格的语法级别的“访问控制”,更多的是靠程序员的自觉实现

2、继承

(1)让子类继承父类的特性,提高了代码的重用性,是一种增量进化,是代码复用的重要手段

(2)一个子类可以继承多个父类

(3)语法格式:

class 子类(父类):

      类体

如果没有指定父类,默认父类是object类

object类是python里的一个类,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)  
#必须显示调用父类的初始化方法,不然解释器不会去调用,子类直接引用了父类的属性
        self.score = score

#Student继承了Person,Person继承了object类

print(Student.mro())
#[<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]

s = Student("高宇星", 18, 100)
s.say_age()
#年龄:我也不清楚多大年纪
#说明父类里的东西,子类里也可以使用

print(s.name)  #直接调用了父类的代码
#高宇星

print(s._Person__age)  #子类不能直接调用父类的私有属性
#18

print(dir(s))
#['_Person__age', '__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_age', 'score']

(4)类成员的继承和重写

成员继承:子类继承了父类除构造方法之外的所有成员

方法重写:子类可以重新定义父类的方法, 这样就覆盖父类的方法,也称为“重写”

#测试方法的重写
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("我的名字是{0}".format(self.name))

class Student(Person):

    def __init__(self, name, age, score):
        Person.__init__(self, name, age)  #必须显示调用父类的初始化方法,不然解释器不会去调用,子类直接引用了父类的属性
        self.score = score


    def say_introduce(self):
        '''重写了父类的方法'''
        print("报告老师,我的名字是:{0}".format(self.name))

s = Student("高宇星", 18, 100)
s.say_age()
s.say_introduce()
'''
我的年龄: 18
我的名字是高宇星
'''
s = Student("高宇星", 18, 100)
s.say_age()
s.say_introduce()
#我的年龄: 18
#报告老师,我的名字是:高宇星

(5)object根类__dir__()

object.dir()可以查看对象的所有属性

通过类的方法mro()或者类的属性_mor_可以输出这个类的继承层次结构

object类是所有类的父类,所有的类都有object类的属性和方法

#测试方法的重写
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("我的名字是{0}".format(self.name))

class Student(Person):

    def __init__(self, name, age, score):
        Person.__init__(self, name, age)  #必须显示调用父类的初始化方法,不然解释器不会去调用,子类直接引用了父类的属性
        self.score = score


    def say_introduce(self):
        '''重写了父类的方法'''
        print("报告老师,我的名字是:{0}".format(self.name))

s = Student("高宇星", 18, 100)
s.say_age()
s.say_introduce()
'''
我的年龄: 18
我的名字是高宇星
'''
s = Student("高宇星", 18, 100)
s.say_age()
s.say_introduce()
#我的年龄: 18
#报告老师,我的名字是:高宇星


obj = object
print(dir(object))
#['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

print(dir(s))
#['_Person__age', '__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_age', 'say_introduce', 'score']

(6)重写__str__()方法

object有一个__str__()方法,用于的返回一个对于“对象的描述”,对应于内置函数str()经常用于print()方法,帮助我们查看到对象的信息

#测试object里面的__str__()方法

class Person:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "名字是:{0}".format(self.name)


p = Person("高宇星")
print(p)
#<__main__.Person object at 0x000001C7AE9A20D0>,重写__str__()函数之前,str默认的信息
#名字是:高宇星

(7)多重继承

一个子类可以有多个直接父类

好处:可以使我们类具备多个“父类”的特点

坏处:类的整体层次异常复杂,尽量避免使用

#多继承
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()
c.aa()
c.bb()
'''
cc
aa
bb
'''

(8)mro()函数

python支持多继承,如果多个父类有相同名字的方法,在没有指定父类的时候,解释器将“从左到右”按顺序搜索

mro():方法解析顺序。我们可以通过mro()方法来获得“类的层次结构”,方法解析顺序也是按照这个累的层次结构寻找的

#mro()方法的测试
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())  #打印类的层次,这个mro函数是C大类的函数
c.say()  #在mro层次结构里从左到右得找
'''

[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
say AAA!

Process finished with exit code 0

'''

(9)通过super()获得父类定义,而不是父类对象

#测试super(),代表父类的定义,而不是父类对象
class A:

    def say(self):
        print("A:", self)

class B(A):

    def say(self):    
        #A.say(self)    #在B里面想调用A的say方法,通过super()也可以完成,可以达到同样的效果       super().say()  #super()函数之后的函数方法里面不需要带self
        super().say()
        print("B:", self)

B().say()
'''
A: <__main__.B object at 0x000001584C7D4160>
B: <__main__.B object at 0x000001584C7D4160>
说明从B里面调用A的say方法成功了
'''

#整个过程相当于是父类方法的重写

3、多态

同一个 方法调用由于对象不同会产生不同的行为。

(1)多态是方法的多态,而不是属性的;

(2)多态存在两个必要条件,继承和方法重写

#多态,一个方法调用,根据不同的对象调用不同的方法!

class Man:
    def eating(self):
        print("饿了,吃饭了")

class Chinese(Man):
    def eating(self):
        print("中国人用筷子吃饭")

class English(Man):
    def eating(self):
        print("英国人用叉子吃饭饭")

class Indian(Man):
    def eating(self):
        print("印度人用右手吃饭")


def manEating(a):  #全局函数,不属于任何一个模块
    if isinstance(a, Man):
        a.eating()  #传进来的都是人,只要是man的子类都可以,根据传的对象类型不同,调用的方法也不一样
    else:
        print("不能吃饭!哼哼")


manEating(Chinese())
#中国人用筷子吃饭

manEating(English())
#英国人用叉子吃饭饭

五、运算符重载

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:
            print("不是同类对象不能同类相加")

    def __mul__(self, other):
        if isinstance(other, int):
            return self.name * other
        else:
            print("不是同类对象不能同类相乘")


p1 = Person("litterStar")
p2 = Person("高宇星")

x = p1.__add__(p2)
print(x)
#litterStar——高宇星

x = p1 + p2
print(x)
#litterStar——高宇星

print(p1.__mul__(3))
#litterStarlitterStarlitterStar

print(p1 * 3)
#litterStarlitterStarlitterStar

六、特殊属性

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")

    def __init__(self, nn):
        self.nn = nn


c = C(3)


print(dir(c))
#['__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__', 'aa', 'bb', 'cc', 'say']

print(c.__dict__) #__dict__可以看到类的所有属性值,以字典的形式表达
#{'nn': 3}

print(c.__class__)
#<class '__main__.C'>

print(C.__bases__)   #要指向大写的类对象,找类对象的基类,以元祖的形式返回
#(<class '__main__.A'>, <class '__main__.B'>)

print(C.mro())
#[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]

print(A.__subclasses__())
#[<class '__main__.C'>]

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

import copy
#测试对象的浅拷贝和深拷贝

class MobliePhone:
    def __init__(self, cpu, screen):
        self.cpu = cpu
        self.screen = screen


class CPU:
    def calculate(self):
        print("计算")
        print("cpu对象:", self)

class Screen:
    def show(self):
        print("显示一幅美丽的画面")
        print("screen对象", self)

#测试变量赋值
c1 = CPU()
c2 = c1
print(c1)
print(c2)
'''
<__main__.MobliePhone object at 0x000001D18754A400>
<__main__.MobliePhone object at 0x000001D18754A400>
'''

#浅复制
s1 = Screen()
m1 = MobliePhone(c1, s1)
m2 = copy.copy(m1)  #需要导入copy模块

print(m1)
print(m2)
'''
<__main__.MobliePhone object at 0x000001CB031F85E0>
<__main__.MobliePhone object at 0x000001CB0330B040>
m1 和 m2 是完全不同的两个对象
'''

print(m1, m1.cpu, m1.screen)
print(m2, m2.cpu, m2.screen)
'''
<__main__.MobliePhone object at 0x00000191930885E0> <__main__.CPU object at 0x0000019193088640> <__main__.Screen object at 0x0000019193088100>
<__main__.MobliePhone object at 0x000001919319B040> <__main__.CPU object at 0x0000019193088640> <__main__.Screen object at 0x0000019193088100>
m1和m2虽然是两个对象,地址不同,但是使用的cpu和screen都是相同的
'''

#测试深复制
m3 = copy.deepcopy(m1)
print(m1, m1.cpu, m1.screen)
print(m3, m3.cpu, m3.screen)
'''
<__main__.MobliePhone object at 0x00000299F80B85E0> <__main__.CPU object at 0x00000299F80B8640> <__main__.Screen object at 0x00000299F80B8100>
<__main__.MobliePhone object at 0x00000299F8614F40> <__main__.CPU object at 0x00000299F8749C10> <__main__.Screen object at 0x00000299F8749C40>
cpu和screen都发生了变化,说明他们把子对象的子对象都进行了复制
'''

八、组合

Is—a关系,我们可以用继承,狗是动物

Has—a关系,我们可以使用组合,手机有cpu

它们都可以有代码调用的功能

#使用继承实现代码的复用
class A1:
    def say_a1(self):
        print("a1,a1,a1")

class B1(A1):
    pass

b1 = B1()
b1.say_a1()
#a1,a1,a1

#同样的方法,使用组合来实现代码的复用
class A2:
    def say_a2(self):
        print("a2, a2, a2")


class B2:
    def __init__(self, a):  #当B2里面直接使用A2的属性,把A2的属性传入B2的参数
        self.a = a

a2 = A2()
b2 = B2(a2)
b2.a.say_a2()
#测试has—a 的关系,使用组合
class MobliePhone:
    def __init__(self, cpu, screen):
        self.cpu = cpu
        self.screen = screen


class CPU:
    def calculate(self):
        print("计算")
        print("cpu对象:", self)

class Screen:
    def show(self):
        print("显示一幅美丽的画面")
        print("screen对象", self)


m = MobliePhone(CPU(), Screen())
m.cpu.caculate()
m.screen.show()

九、工厂模式

class CarFactory:
    def create_car(self, broad):
        if broad == "奔驰":
            return Benz()
        elif broad == "宝马":
            return BMW()
        elif broad == "比亚迪":
            return BYD()
        else:
            print("未知品牌,无法创建")


class Benz:
    pass

class BMW:
    pass

class BYD:
    pass

factory = CarFactory()  #先建立工厂
c1 = factory.create_car("奔驰")  #造车,让我的工厂造车
c2 = factory.create_car("比亚迪")

print(c1)
print(c2)
'''
<__main__.Benz object at 0x000001941106B490>
<__main__.BYD object at 0x000001941106B220>
只是有这个未知保留了,已经预留了车位,准备检车,但是由于各个车型还没有传入制造方法,所以只能看到其对象id
'''

十、单例模式

class MySingleton:

    __obj = None   #创建了一个类,类的属性为空 __obj用来描述对象的属性
    __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:  #这里不可赋布尔值
            print("init···")
            self.name = name
            MySingleton.__init_flag = False #初始的时候为True,改变其初始值为Flase,意味着初始化方法不会被调用两次



a = MySingleton("aa")
print(a)

b = MySingleton("bb")
print(b)

c = MySingleton("cc")
print(c)

d = MySingleton("dd")
print(d)


init···
<__main__.MySingleton object at 0x0000025376F7B220>
<__main__.MySingleton object at 0x0000025376F7B220>
<__main__.MySingleton object at 0x0000025376F7B220>
<__main__.MySingleton object at 0x0000025376F7B220>
实现了单例模式,切init方法只调用了一次

十一、单例模式和工厂模式的组合

#把工厂模式和单例模式的结合使用
a = "new start"
b = a.center(20, "*")
print(b)

class CarFactory:

    __obj = None   #创建了一个类,类的属性为空 __obj用来描述对象的属性
    __init_flag = True


    def create_car(self, broad):
        if broad == "奔驰":
            return Benz()
        elif broad == "宝马":
            return BMW()
        elif broad == "比亚迪":
            return BYD()
        else:
            print("未知品牌,无法创建")

    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:   #如果类对象属性为空
            cls.__obj = object.__new__(cls)    #那就建立一个类属

        return cls.__obj

    def __init__(self):
        '''为了使初始化方法制备调用一次'''
        if CarFactory.__init_flag:  #这里不可赋布尔值
            print("init CarFactory···")
            CarFactory.__init_flag = False #初始的时候为True,改变其初始值为Flase,意味着初始化方法不会被调用两次


class Benz:
    pass

class BMW:
    pass

class BYD:
    pass

factory = CarFactory()  #先建立工厂
c1 = factory.create_car("奔驰")  #造车,让我的工厂造车
c2 = factory.create_car("比亚迪")

print(c1)
print(c2)

print("嘿嘿嘿")
factory2 = CarFactory()
print(factory)
print(factory2)
'''
嘿嘿嘿
<__main__.CarFactory object at 0x000001B672F4B220>
<__main__.CarFactory object at 0x000001B672F4B220>
这两个工厂的对象都是同一个,实现了单例模式
'''

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值