python(3) - 面向对象:封装、继承、多态

本文深入解析Python面向对象编程,涵盖类与实例、封装、继承、多态等核心概念,详解高级特性和特殊形式表达,助您掌握Python OOP精髓。

python 基础知识

继上一篇:python基础知识(二)

面向对象

class 语法,定义一个对象,包含属性,操作方法;然后进行实例化,方法调用。

# 类与实例, class
class User(object):
	# 类属性
    __Name__  = "User"
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def getName(self):
        print(self.name)

    def getAge(self):
        print("you won't get the age")

Ming = User("ming",32)
Ming.getName()
Ming.getAge()
print(Ming.age)
print(Ming.__Name__)

说明

  • 定义一个类,User()参数为需要继承的类名,默认继承object
  • __init__类中特定方法:类实例化时必选参数必须保持一致(self除外)
  • self表示实例对象,实例化后方法调用或者属性调用;
  • 类中定义的所有方法第一个参数都是self,之后的参数都是需要传递的
  • 方法中没有方法体时,pass表示不进行任何处理.
封装

为了隐藏某些细节,但提供了操作方法。

# 封装
class User():
    def __init__(self,name,age):
        self.__name = name
        self.__age = age

    def getName(self):
        print(self.__name)

    def getAge(self):
        print("you won't get the age")

Ming = User("ming",32)
Ming.getName()
Ming.getAge()
#print(Ming.__name)
Ming.__name = "ming_copy"
Ming.getName()
print(Ming.__name)

说明:

  • __用来表示属性为私有属性,不可通过Ming.__name访问到。
  • 但作为示例对象的变量,Ming.__name = "ming_copy"是可以访问的。它不同于内部实例的属性,是实例化后额外追加上去的。
  • 对于变量命名,对于非私有属性不要使用__
  • 对于这种__name__ 实例化后是可以则直接访问的。属于特殊变量。
继承、多态
  • 继承即子类继承父类、超类。
  • 多态即继承这种表现形式的特点:
    • 子类拥有父类所有可见的属性、方法。
    • 子类可重写父类现有的方法,也可以自定义自己的方法。
    • 继承关系构成一棵树,最顶层是object,
# 继承、多态
class People():
    def eat(self):
        print("eat meat")
class User(People):
    def walk(self):
        print("walking...")

class Young(People):
    def study(self):
        print("studying...")

class Child():
    def cry(self):
        print("crying...")

    def eat(self):
        print("eat milk")

p_1 = User()
p_2 = Young()
p_3 = Child()

p_3.eat()
p_2.eat()
p_1.walk()

说明:

  • 多态优点:可扩充、灵活、可替换、解耦。
对象属性操作
# 对象属性的操作
print(type(None))

import types

print(type(User.eat)==types.FunctionType)
print(type(abs))

# True
print(isinstance(p_1,People)) 
print(isinstance(p_1,User))
	
print(dir(p_1))
# 获取一个实例对象的方法,并调用
getattr(p_1,"eat")()
print(hasattr(p_1,"name"))
# 设置一个实例对象的额外的参数
setattr(p_1,"name","peope_one")
print(hasattr(p_1,"name"))

说明:

  • type()用来判断基本数据的数据类型。int/str/float/bool/NoneType

  • 使用types模块中的变量定义函数类型。

    • 自定义函数类型FunctionType
    • 系统内置函数类型BuiltinFunctionType
    • 匿名函数类型LamdbaType
    • 生成器函数类型GeneratorType
  • isinstance()来判断实例是否为某个类的实例对象。
    第二个参数接收一个元祖类型的参数,用于检测被检测对象是否为其中的一个类型

  • dir()列出数据对象的所有属性;返回一个包含字符串的list

  • getattr()/setattr()/hasattr()用来获取属性、设置属性、判断是否存在。

高级特性

类实例化后可以添加额外属性、方法,只能作用域当前实例;给类动态添加属性、方法,就会作用域所有实例上。

使用__slots__
# 高级特性 、类操作说明
class People():
    __slots__ = ('name','age')
    def eat(self):
        print("eat meat")
class User(People):
	# 然后再加上 __slots__属性,
	# __slots__ = ()
    def walk(self):
        print("walking...")

p = People()
p.name = "people"
# 报错:has no attribute 'address'
# p.address = "address"
print(dir(p))
# 实例化子类,可以添加属性
p_1 = User()
# 再加上 __slots__ 属性,就报错了
p_1.address = "001"
print(dir(p_1))

说明:

  • __slots__定义实例的属性,只允许添加定义的属性。添加其他属性就报错。
  • __slots__只作用于当前类实例,如果子类继承则不会起作用;但是如果子类中也定义了 __slots__,那他子类允许添加的属性自身和父类的并集。
使用@property

给属性的setter/getter进行注解;将方法调用转换为属性调用。

# @property 定义并转换为动态添加的属性提供方法,并进行属性处理
class People():
    __slots__ = ('age')
    def eat(self):
        print("eat meat")

    @property
    def name(self):
        return self._name
    
    @name.setter
    def name(self,val):
        if val=="admin":
            raise ValueError("you can't use the name")
        self._name = val

people = People()
# 报错, you can't use the name
# people.name = "admin"

说明:

  • @property转为getter方法,获取属性;@***.setter(属性名,实例中为name)转为为setter方法,提供设置属性。
  • 可以用来定义只读/只写属性。
多继承

多继承即类有多个父类,并拥有所有父类可见属性、方法。

# 多重继承
class Boy(User,Young):
    pass

# Boy 拥有了 study  walk  两个技能
print(dir(Boy))

说明:

  • 多继承的特点有点像是对象混入(mix),组合式继承。
特殊形式表达

诸如__slots__这种,在python内部会特殊处理;还有以下常用:

  • __len__()在类中定义方法,可以对类使用len()函数;

    class Boy(User,Young):
        def __len__(self):
            return 100
    # 100
    print(len(Boy()))
    
  • __str__()在类中定义后,表示打印或输出实例时的内容;直接调用实例时的输出定义为__repr__()

    class Boy(User,Young):
    	def __str__(self):
        	return "the object inherit <User>.<Young>"
        
        #__repr__ = __str__
    # __str__ 打印时的输出
    print(Boy())
    

    .py文件中直接调用实例不会有任何输出,只有在命令行中能看见__repr__() 的效果;

  • __iter__()用于返回一个迭代对象,然后在实现__next()__方法,迭代对象调用next()方法获取数据。

    class Boy():
        def __iter__(self):
            return self
    
        def __next__(self):
        	# 随机生成一个数字,代表年龄
            age = random.randint(0,100)
            # 年龄大于90 ,抛出错误,迭代终止
            if age>90:
                raise StopIteration()
            return age
    
    b_age = Boy()
    # 遍历输出
    for val in b_age:
        print(val)
    
  • __getitem__()可以使对象类似list一样取数据

    class Boy():
        def __getitem__(self,index):
            return index*2
    # output 8 
    print(Boy()[4])
    
  • __call__可以使一个类再被实例化后,实例仍可像函数一样执行;callable()可以判断对象是否可以被调用

    # print(Boy()())
    print(callable(Boy()))
    class Boy():
        def __call__(self):
            print("olololololo")
    Boy()()
    
枚举

类似java的枚举,enum ,用来列出可能出现的常量值,供调用。

from enum import Enum
Names = Enum("names",("靓仔","校长","鸽吻"))

print(Names(2)) 
for name,member in Names.__members__.items():
    print(name,member,member.value)
# 可以自定value值
from enum import Enum,unique
# unique 校验数据中是否有重复值,会报错
@unique
class Address(Enum):
    程序员 = 0
    公务员 = 1
    教师 = 2

print(Address(0),Address(2))

说明:

  • 下标访问是从1 开始
  • @unique校验重复值,有就报错;
使用元类
  • type() 可以创建一个新的类;

    • 参数一:定义类的名称;
    • 参数二:元组类型表示继承的父类,
    • 参数三:绑定方法,将定义好的方法fn绑定到类
    # type() 创建一个新类
    def getAge(self):
        return random.randint(20,50)
    
    User_Age =type("User_Age",(object,),dict(getAge = getAge))
    
    print(User_Age().getAge())
    

    说明:

    • 函数定义的第一个参数必须是self
    • 指定继承的父类只有一个时,注意书写方式(**,)
  • metaclass可以创建类,也可以改变一个类的行为;

源代码地址,有注释说明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heroboyluck

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值