7_类、面向对象的三特征

目录

类的创建

构造函数 __init__()

实例对象和类对象

调用过程

静态方法

__del__(析构函数)和垃圾回收机制

__call__ 方法和可调用对象

Python中方法没有重载

方法的动态性

面向对象的三特征(封装、继承、多态)

私有属性和私有方法(封装)

@property 装饰器

继承

方法的重写

查看类的层次

object 根类

特殊属性

重写特殊方法

多重继承

方法解析顺序

super() 

多态

组合(获得其他类中方法的另一种方式)


 

类也是一个对象,内部包括了方法(函数)和属性(变量)

类的创建

# 定义一个类
class Student:   # 类的首字母一般大写,多个单词使用驼峰结构,如 GoodStudent
    def __init__(self, name, score):        # 注意这里是 init 、 双下划线!!!
        self.name = name
        self.score = score

    def print_student(self):
        print("{0}的分数是: {1}".format(self.name, self.score))

s1 = Student("Lu", 75)
s1.print_student()

print(dir(Student))      # 查看对象的属性和方法
print(s1.__dict__)       # 查看对象的字典
print(isinstance(s1, Student))   # 判断 s1 是不是 Student 类型

--------------------------------------------------
Lu的分数是: 75
['__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__', 'print_student']
{'name': 'Lu', 'score': 75}
True
--------------------------------------------------

构造函数 __init__()

1. 函数名称固定,必须是 __init__

2. 第一个参数必须是 self

3. 用来初始化实例对象,即初始化对象的各属性(如上方的 name 和 score),没有返回值

4. 通过 类名(参数列表) 调用构造函数

虽然说没有返回值,实际上已经把将创建好的对象返回给变量(如上方的 Lu,75,返回给了 s1)

5. 包括了两个过程

(1)__new__() 创建一个新的对象(忽略,编程时无需定义)

(2)__init__() 初始化对象的各属性

实例对象和类对象

class Student:  
    company = 'XX'                # 类属性,从属于类对象 Student
    count = 0                     # 类属性                                 

    def __init__(self, name, score):
        self.name = name          # 实例属性,从属于实例对象 self
        self.score = score        # 实例属性
        Student.count += 1
    
    def print_student(self):      # 实例方法
        pass                      # 表示一个空语句

    @classmethod                  # 声明定义类方法
    def pp(cls):                  # 括号里面要加 cls
        pass

s1 = Student("Lu", 75)
s1.print_student()

# 从属于那个对象,就可以被对象内部共享

调用过程

堆的左边实例对象,堆的右边类对象。

1. 实例对象中不包括类方法

2. 类对象中的 print_student 是实例方法,类对象中只是保存了代码,以便调用

静态方法

用于在类里面定义和类完全无关的方法,可以通过类名去访问

@staticmethod       # 装饰器声明
def ppp(a, b):      # a b 为形参 
    pass

静态方法和类方法不能调用实例参数实例方法!!!否则会报错

把类对象比作一个模具,我们只能设计花纹,不能使用模具造出来的产品,可能产品还没造出来

__del__(析构函数)和垃圾回收机制

class Person:

    def __del__(self):                   # 重建析构函数(Python自带,这里只是为了测试)
        print("销毁对象:{0}".format(self))

p1 = Person()
p2 = Person()
del p2                    # 可以通过 del 调用析构函数
print("程序结束")

---------------------------------
销毁对象:<__main__.Person object at 0x004E9F50>
程序结束
销毁对象:<__main__.Person object at 0x004E9CF0>
---------------------------------

Python中的垃圾回收机制:当引用计数为0,即对象没有被引用,垃圾回收器自动调用析构函数进行垃圾回收

__call__ 方法和可调用对象

定义 __call__ 方法的对象,称为可调用对象,即对象可以像函数一样被调用

class Test:

    def __call__(self, salary):
        yearsalary = salary * 12
        daysalary = salary // 30
        return dict(yearsalary=yearsalary, monthsalary=salary, daysalary=daysalary)

a = Test()      
print(a(24000))     # 将对象像函数一样调用

-------------------------------------
{'yearsalary': 288000, 'monthsalary': 24000, 'daysalary': 800}
-------------------------------------

Python中方法没有重载

即不要定义重名的方法(其他一些语言可以),如果重名,前面的会被后面的覆盖

方法的动态性

为类添加新方法,修改方法

但是,对于最原始的模具不会变!!!

# 万物皆对象
class Life:

    def work(self):
        print("day day up")

def study():
    print("study day day up!")
def work2():
    print("work day day up!")

p = Life()
p.work()          # 下面的修改全是针对 p 这个对象

p.study = study   # 增加了 study 方法
p.study()            

p.work = work2    # 修改 work 方法为 work2 方法
p.work()

p2 = Life()       # 注意,这里的类是不变的!!!
p2.work()

--------------------------------
day day up
study day day up!
work day day up!
day day up
--------------------------------
  • 面向对象的三特征(封装、继承、多态)

私有属性和私有方法(封装)

通常约定,双下划线开头的属性(方法)是私有的

在私有属性所属类的内部可以直接访问,类的外部不能直接访问,可以通过 _类名__私有属性名 (前面是单下划线)

class Student:

    def __init__(self, name, age):
        self.name = name
        self.__age = age            # 私有属性
     
    def __work(self):
        print("aaaaa!")             # 私有方法
        print(self.__age)           # 在类的内部可以直接调用,相当于自己人用自己家东西
        
s1 = Student("Lu", 25)
print( s1._Student__age )           # 私有属性的访问
s1._Student__work()                 # 私有方法的调用

@property 装饰器

将方法变成属性

# 原始办法
class Student:

    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<50000:
            self.__salary = salary
        else:
            print("Your input is wrong!")

s1 = Student("Lu", 3000)
print(s1.get_salary())        # 这里还是用的方法
s1.set_salary(4000)
print(s1.get_salary())
# 使用 property 修饰器
class Student:

    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<50000:
            self.__salary = salary
        else:
            print("Your input is wrong!")

s1 = Student("Lu", 3000)
print(s1.salary)        # 变成属性
s1.salary = 4000
print(s1.salary)

继承

子类(派生类)继承父类(基类)的特征,实现代码复用,更好地实现拓展

Python 中可以继承多个直接父类

没有指定父类,默认 object 类(所有类的父类)

class Person:

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

    def print_age(self):
        print(self.__age)

class Student(Person):         # 继承,括号中是父类

    def __init__(self, name, age, score):
        Person.__init__(self, name, age)      # 继承父类的用法
        self.score = score

s = Student("Lu", 25, 75)
s.print_age()
print(dir(s))               # 显示 s 的所有属性
print(s._Person__age)       # print(s.age) 报错,子类可以继承私有属性,但是不能直接查看

-----------------------------------------
25
['_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', 'print_age', 'score']
25
-----------------------------------------

方法的重写

class Person:

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

    def print_age(self):                # 对该方法重写
        print(self.age)

class Student(Person):

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

    def print_age(self):                # 重写
        '''重写父类中的代码'''
        print("My age is", self.age)

s = Student("Lu", 25, 75)
s.print_age()

-------------------------
My age is 25
-------------------------

查看类的层次

class A:
    pass

class B(A):
    pass

class C(B):
    pass

print(C.mro())   # 查看类的层次

------------------------------------
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
------------------------------------

object 根类

使用 dir() 查看所有的属性!!!

方法也是属性!!!

特殊属性

class A:
    pass

class B:
    pass

class C(B, A):
    def __init__(self, name):
        self.name = name

c = C("Lu")
print(dir(c))
print(c.__dict__)    # 对象的属性字典
print(c.__class__)   # 对象所属的类
print(C.__bases__)   # 类的基类元组
print(C.__base__)    # 类的基类
print(C.mro())    # 类的层次结构
print(A.__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__', 'name']
{'name': 'Lu'}
<class '__main__.C'>
(<class '__main__.B'>, <class '__main__.A'>)
<class '__main__.B'>
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
[<class '__main__.C'>]
-------------------------------------------------------

重写特殊方法

 只是为了了解本质,一般不需要重写。

每个运算符都对应一个特殊方法,如 + 本质上是 __add__(),运算符也可以重载

class Person:

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

    def __str__(self):                       # 改写
        return "My name is {0}".format(self.name)

p = Person("Lu")
print(p)

------------------------------------------
My name is Lu
------------------------------------------

多重继承

一般不建议使用

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.aa()
c.bb()
c.cc()

方法解析顺序

class A:
    def aa(self):
        print("aa")

class B:
    def aa(self):
        print("bb")

class C(A, B):     # 按这里括号内的顺序
    pass

class D(B, A):     # 按这里括号内的顺序
    pass

c = C()
d = D()
c.aa()
d.aa()

------------------------------
aa
bb
------------------------------

当父类中出现相同的方法

直观上:按照括号中的顺序解析

实际上:解析顺序是 mro() 顺序,从左往右

super() 

获得父类的定义,但不是父类的对象(可以理解为获得父类的代码) 

class A:

    def say(self):
        print(self)

class B(A):
    
    def say(self):       # 注意以下三个语句的区别        
        A().say()        # 调用            
        A.say(self)      # 继承                     
        super().say()    # super实现的继承
        print(self)

b = B()
b.say()

--------------------------------
<__main__.A object at 0x0249F6B0>        # 调用,对象是 A 
<__main__.B object at 0x02499CF0>
<__main__.B object at 0x02499CF0>
<__main__.B object at 0x02499CF0>
--------------------------------

多态

同一个方法调用,由于对象不同,产生的行为不同(如张三的休息是睡觉,李四的休息是打游戏)

1. 多态是方法的多态,属性没有多态

2. 多态存在的两个必要条件:继承,方法的重写

class Man:
    def eat(self):
        print("吃饭")

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

class American(Man):
    def eat(self):
        print("美国人用叉子吃饭")

def maneat(m):
    if isinstance(m, Man):
        m.eat()
    else:
        print("不能吃饭")

maneat(Chinese())
maneat(American())

组合(获得其他类中方法的另一种方式)

区别不同的结构,使用组合与继承

继承:动物,猫是一个动物

组合:屏幕,手机有一个屏幕

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

class CPU:
    def say(self):
        print("980")

class SCREEN:
    def say1(self):
        print("daxingxing")

a = Mobilephone(CPU(), SCREEN())
a.cpu.say()
a.screen.say1()

#################################################
980
daxingxing
#################################################

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值