美文网首页
(3) python 面向对象编程

(3) python 面向对象编程

作者: 小黄不头秃 | 来源:发表于2022-10-18 00:16 被阅读0次

(一)面向对象编程

在面向对象中最重要的三个部分分别是:封装、继承、多态

可参考我前面的笔记:https://www.jianshu.com/p/92790574f3d2

在学习这些之前,我们先明白两个概念:类、对象

  • 类(class):描述具有相同属性和方法的对象的集合。例如:人类。
  • 对象(object):通过对类进行实例化,分配内存空间,能能够被用户使用。例如:张三。
# 类
class Person():
    name="人类有个名字"
    age="人类有年龄"
    sex="人类有性别"

# 对象
p1 = Person()
p1.name = "我叫张三"
p1.age = 18
p1.sex = "man"
print(type(p1)) # <class '__main__.Person'>
(1)封装(encapsulation)

将一个类的所有属性和方法放到一起,或者说将数据和功能汇聚到一起。
封装能够保证类内部数据结构的完整性,只允许用户使用公开的数据,不允许使用私有数据,避免了外部对内部数据的影响,从而提高了程序的可维护性。

首先我们来看看,对象生命周期和函数执行的顺序:

self:代表当前对象,可以在类的内部直接访问任何类的变量和方法,类里面的所有函数都以self作为第一个参数。(self不是关键字,只是形参的名字)

class Person():
    """人类"""
    # 这个方法一般不使用
    def __new__(cls,*args, **kwargs):
        print("new")
        return super().__new__(cls)

    # 一个人诞生了,需要给它起个名字,初始化年龄等
    def __init__(self,name,age) -> None:
        print("初始化函数") # 实例化对象的时候会自动调用
        self.name = name
        self.age = age
        self.print_name()

    def print_name(self):
        print("我是:",self.name)
    
    def __del__(self):
        print("析构函数")# 释放对象的时候会自动调用

p1 = Person("张三", 18)
# new
# 初始化函数
# 我是: 张三
# 析构函数

类变量和实例变量

  • 类变量:类变量是每一个类都有的变量,新创建的每一个实例的类变量都是一样的,地址也都一样。类变量可以是可变变量和不可变变量。我们可以以通过实例和类访问到类变量,如果类变量是可变变量,只要在一个实例中改变类变量,其他实例访问的时候也会改变。不推荐使用实例访问类变量。
  • 实例变量:是每一个实例私有的,每个实例的变量的地址都不同,每个实例之间不会相互影响。并且无法通过类名访问。

私有变量:私有成员变量,外部不能访问。以__开头
私有方法:私有成员方法,外部不能访问。以__开头

理论上私有变量是不允许外部访问的,但是python给我们开了个后门,我们可以使用实例名._类名__变量名来访问

class Person():
    # 类变量
    sex = "man"
    list1 = [1,2,3]
    __a = 1 # 私有成员变量

    # 初始化函数
    def __init__(self, name) -> None:
        self.name = name 

    # 私有成员方法
    def __get_a(self):
        __a = 3 # 内部可以访问,外部不能访问

# 两个都叫张三的人
p1 = Person("张三")
p2 = Person("张三")

# 类变量, 不可变变量
print(Person.sex == p1.sex == p2.sex, id(Person.sex), id(p1.sex), id(p2.sex)) # True 1371018000456 1371018000456 1371018000456
p1.sex = "woman"
print(Person.sex == p1.sex == p2.sex, id(Person.sex), id(p1.sex), id(p2.sex)) # False 1371018000456 1371047207352 1371018000456

# 类变量, 可变变量
print(Person.list1 == p1.list1 == p2.list1, id(Person.list1), id(p1.list1), id(p2.list1)) # True 1371046436744 1371046436744 1371046436744
Person.list1.append(4)
print(Person.list1 == p1.list1 == p2.list1, id(Person.list1), id(p1.list1), id(p2.list1)) # True 1371046436744 1371046436744 1371046436744

# 实例变量
print(id(p1.name), id(p2.name)) # 1371047341288 1371047984448
print(Person.name) # AttributeError: type object 'Person' has no attribute 'name'

# 私有成员变量&方法
print(p1.__a) # AttributeError: 'Person' object has no attribute '__a'
print(p1.__get_a()) # AttributeError: 'Person' object has no attribute '__get_a'
print(p1._Person__a) # 1

类方法属于类但不属于实例的方法,需要在方法前面使用@classmethod标记。
静态方法寄居在类中,独立存在,不能调用对象方法和类方法(类名.方法名除外),需要在方法前面使用@staticmethod标记。
property 装饰器让一个方法被当成属性来调用,不能传入参数,,需要在方法前面使用@property标记

python还有很多的魔术方法:

class A():
    def __init__(self) -> None:
        pass

    @classmethod
    def a(self):
        print("类方法")

    @staticmethod
    def b(): # 无需传入self
        print("静态方法")
    
    @property
    def c(self):
        print("c")

    def __str__(self) -> str:
        return "hello, this is the object of A"

    def d(self):
        print("d")

a1 = A()
A.a() # 类方法
A.b() # 静态方法
A.c # c
A.d(self=1)# 可以使用类名调用实例方法但是需要手动传入self参数
a1.a() # 类方法
a1.b() # 静态方法
a1.c # c
a1.c() # c TypeError: 'NoneType' object is not callable
print(a1) # hello, this is the object of A
(2)继承

子类通过继承父类从而获取父类的属性和方法。

如果父类和子类有相同名称的方法或者属性,会被后者覆盖。可以通过super调用父类的重名函数。

一个类也可以继承于多个父类。

class Person(): # 父类
    title="人类"
    __a = "a"

    def print_title(self):
        print(Person.title)

class Teacher(Person): # 子类
    name = "老师"

class Student(Person): # 子类
    name = "学生"
    def print_title(self):
        print(Student.name)

    def private_a(self):
        print(Person._Person__a) # 不推荐使用

t1 = Teacher()
s1 = Student()
t1.print_title() # 人类 继承父类方法
s1.print_title() # 学生 覆盖父类方法
super(Student, s1).print_title() # 人类
# 访问父类私有属性
s1.private_a()
s1._Person__a # 'a' 不推荐使用
(3)多态

多态就是子类重写父类的方法,上面已经说过了。也就是子类和父类方法重名,子类方法覆盖父类方法。

class A():
    def test(self):
        print("a")

class B(A):
    def test(self):
        print("b")

b = B()
b.test() # b

相关文章

网友评论

      本文标题:(3) python 面向对象编程

      本文链接:https://www.haomeiwen.com/subject/qnveartx.html