面向对象—02面向对象高级特性

本文详细介绍了Python面向对象的高级特性,包括类属性与实例属性的区别,类方法与静态方法的使用,property属性的定义及应用场景,元类type的概念与动态创建类,抽象基类的接口设计,自省机制及其常见函数,以及如何通过slots限制对象属性。通过对这些特性的理解,可以更好地掌握Python的面向对象编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、类属性与实例属性

1、类属性

(1)类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有。
(2)占用内存:类属性在内存中只存在 一个副本。
(3)作用域:可以通过类名或者对象名来访问

2、实例属性

(1) 即对象属性,它不被所有类对象的实例对象所共有。
(2)占用内存:在内存中的副本个数取决于对象个数,有几个对象,就有几个实例属性。
(3)作用域:只能通过对象名来访问

二、类方法与静态方法

1、类方法

类方法是类对象所拥有的方法,
需要用修饰器一般以@classmethod来标识其为类方法
1). 对于类方法,第一个参数必须是类名cls(形参)
2). 能够通过实例对象和类去访问

import time

class Date(object):
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

    def __str__(self):
       return '%s-%s-%s' %(self.year, self.month, self.day)

    @classmethod   
    def today(cls):
        """
        类方法 @classmethod ,传入类名 Date
        :return: 返回 类Date实例化出的对象
        """
        now = time.localtime()
        return cls(now.tm_year, now.tm_mon, now.tm_mday)  # Date() 实例化对象

if __name__ == '__main__':
    today = Date.today()   # 通过类名直接访问 , today()方法返回当前日期对象
    print(today)  # 有魔术方法__str__可以友好展示,不然打印出的是一个日期对象 :<__main__.Date object at 0x000001A8CD4B95F8>

2、静态方法

静态方法需要用修饰器一般以@staticmethod来标识其为静态方法,
1). 静态方法不需要传任何参数
2). 能够通过实例对象和类去访问。

三、property类属性

1、定义

一种用起来像是使用的实例属性一样的特殊属性,可以对应于类的某个方法
使用:
定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
调用时,无需括号

2、应用场景

(1)某个属性只能访问不能修改,将类方法转换成类属性

class Date(object):
    def __init__(self, year, month, day):
        self.__year = year      # 定义为私有属性
        self.__month = month
        self.__day = day

    @property      # 将该私有属性用@property定义为一个函数,返回,则可以进行查看
    def year(self):
        return self.__year
    @property
    def month(self):
        return self.__month
    @property
    def day(self):
        return self.__day

if __name__ == '__main__':
    dateobj = Date(2020, 1, 1)
    print(dateobj.year, dateobj.month, dateobj.day)  # 2020 1 1 则可以查看到私有属性
    # 虽然year, month, day 都是方法,但是这里调用不用加(), 将类方法转换成了类属性

(2)某一个属性不能直接返回, 需要计算, 可以通过property属性实现

"""
分页显示是一种非常常见的浏览和显示大量数据的方法,属于web编程中最常处理的事件之一
类属性应用需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库
中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求
数据时就要显示的指定获取从第start条到第end条的所有数据 这个分页的功能包括:
• 根据用户请求的当前页和总数据条数计算出 start 和 end
• 根据start 和 end 去数据库中请求数据
"""

class Pagintor(object):
    def __init__(self,page = 1, per_page = 5):
        """
        :param page: 当前展示的页码
        :param per_page: 每页显示的数据个数
        """
        self.page = page
        self.per_page = per_page

    @property
    def start(self):
        return (self.page - 1) * self.per_page  # 根据用户请求的展示页码和显示的数据个数计算出satrt

    @property
    def end(self):
        return self.page * self.per_page      # 根据用户请求的展示页码和显示的数据个数计算出end

goods = ['电脑'+str(i) for i in range(100)]   # 列表生成式

if __name__ == '__main__':
    pagintor = Pagintor(page = 2, per_page= 5)
    inform = goods[pagintor.start: pagintor.end]   # 切片
    print('第%s页的商品信息为:%s' %(pagintor.page, inform))  #第2页的商品信息为:['电脑5', '电脑6', '电脑7', '电脑8', '电脑9']

3、property实现类属性的方式

类属性:在类中定义值为property对象的类属性

(1)通过函数实现

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.__age = age    # 定义私有属性

    @property
    def vaildAge(self):
        return 0 < self.__age <= 150  # age 为property对象

    # 设置property对象(age)的属性

    def get_age(self):           #获取age
        if self.vaildAge:
            return self.__age
        else:
            raise  Exception('年龄不合法')   # 抛出异常

    def set_age(self, age):     #修改设置age
        if self.vaildAge:
            self.__age = age
        else:
            raise Exception('年龄不合法')

    def del_age(self):         #删除age
        if self.vaildAge:
            print('年龄属性删除')
        else:
            raise Exception('年龄不合法')

    # 通过函数的方式实现property类属性
    age = property(fget=get_age, fset=set_age, fdel=del_age)

if __name__ == '__main__':
    person = Person('张三', 18)
    print(person.age)
    person.age = 20
    print(person.age)
    del person.age

2、通过装饰器实现

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

    @property
    def vaildAge(self):
        return 0 < self.__age <= 150

    @property
    def age(self):               # age 为property对象
        if self.vaildAge:
            return self.__age
        else:
            raise Exception('年龄不合法')

    # 通过装饰器实现类属性

    @age.getter                 #获取age
    def age(self):
        if self.vaildAge:
            return self.__age
        else:
            raise Exception('年龄不合法')

    @age.setter                # 修改设置age
    def age(self, age):
        if self.vaildAge:
            self.__age = age
        else:
            raise Exception('年龄不合法')

    @age.deleter              # 删除age
    def age(self):
        if self.vaildAge:
            print('年龄属性删除')
        else:
            raise Exception('年龄不合法')

if __name__ == '__main__':
    person = Person('张三', 18)
    print(person.age)
    person.age = 20
    print(person.age)
    del person.age

四、元类type

1、定义

元类是类的类,是类的模板
元类的实例为类,正如类的实例为对象
元类就是创建类的类。函数type就是是元类。
Python中一切皆对象。包括整数、字符串、函数以及类都是对象,且都是从type类创建而来。
动态生成类,不能控制类是如何生成的。python3 的metaclass可动态创建类。
很多Web框架都会使用metaclass 来创建类。掌握元类对理解源代码至关重要。eg: ORM框架类
在这里插入图片描述
在这里插入图片描述
通过 __ class __ 的魔术方法 可以查看到,这些类的类是元类type。

类的本质是对象, 于是可以对类做如下的操作:
(1)可以将它赋值给一个变量
(2)可以拷⻉它
(3)可以为它增加属性
(4)可以将它作为函数参数进行传递

2、动态创建类

(1)通过分支语句动态创建类

因为类也是对象,运行时在函数中使用class关键字动态的创建类。 当使用class关键字时,Python解释器自动创建这个对象。当然Python提供手动处理的方法

def create_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return  Foo
    else:
        class Bar(object):
            pass
        return  Bar

cls = create_class(name='foo1')
print(cls.__name__)

(2)通过type动态创建类
语法格式:
type(类名, 父类名称的元组, 属性信息的字典)

def hello(self):
    print('hello')

# 通过type创建类
Person = type('Person', (object, ), {'country' : 'China', 'hello': hello})

p = Person()
print(p.country)
p.hello()

3、自定义元类metaclass

应用场景:Django(ORM)、元类实现单例模式等
元类本身而言,实现的功能是: 1. 拦截类的创建 2. 修改类 3. 返回修改之后的类

class Example(type):   # 自定义元类
    pass

class Person(object, metaclass=Example):  #指定元类为自定义出的Example
    pass

五、抽象基类

1、定义

抽象基类有两个特点:
(1)规定继承类必须具有抽象基类指定的方法
(2)抽象基类无法实例化
基于上述两个特点,抽象基类主要用于接口设计
实现抽象基类需要使用内置的abc模块

import abc
class Human(metaclass=abc.ABCMeta):
    """定义一个抽象基类"""
    @abc.abstractmethod    # 抽象基类中的指定方法,继承的子类中需要重写
    def introduce(self):
        print('introduce...')

    @property              #继承的子类中需要重写
    def country(self):
        pass

    @classmethod           #继承的子类中需要重写
    def gender(cls):
        pass

    @staticmethod          #继承的子类中需要重写
    def hello():
        pass

    def sayhello(self):     # 继承的子类中不用重写
        print('hello...')



class Person(Human):
    def __init__(self, name , country, gender):
        self.name = name
        self.__country = country
        self.gender = gender

    def introduce(self):  # 继承时,要重写抽象基类中的指定方法
        print('123...')

    @property
    def country(self):
        return self.__country

    @classmethod
    def gender(cls):
        return 'female'

    @staticmethod
    def hello():
        pass

if __name__ == '__main__':
    #h = Human()     # 抽象基类不能实例化
    p = Person('张三', 'China', 'female')
    p.introduce()
    print(p.country)
    p.sayhello()

六、自省机制

1、定义

(1)在日常生活中,自省(introspection)是一种自我检查行为。
(2)在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及 它能做什么。自省向程序员提供了极大的灵活性和控制力。
(3)例如Python, Ruby, object-C, C++都有自省的能力,这里面的C++的自省的能力最弱, 只能够知道是什么类型,而像Python可以知道是什么类型,还有什么属性。

2、Python中比较常见的自省机制(函数用法):

dir() #查看有什么方法,属性
type() #查看类型
hasattr() #查看是否有某个属性,属性写为字符串
setattr() #修改设置属性
getattr() #获取某个属性
delattr() #删除某个属性
isinstance() #判断是不是某个类型
通过这些函数,我们能够 在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

七、slots限制对象属性

1、动态语言与静态语言的不同

动态语言:可以在运行的过程中,修改代码
静态语言:编译时已经确定好代码,运行过程中不能修改

2、__ slots __

Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

import time


class Date(object):
    __slots__ = '__year', '__month', '__day'  # 限制对象不能添加其他属性信息 , 只能有这三个属性信息

    def __init__(self, year, month, day):
        self.__year = year
        self.__month = month
        self.__day = day

    @property
    def year(self):
        return self.__year

    @property
    def month(self):
        return self.__month

    @property
    def day(self):
        return self.__day

    @classmethod
    def today(cls):
        time_t = time.localtime()
        # cls是当前类  Date()  是实例化对象,
        return cls(time_t.tm_year, time_t.tm_mon, time_t.tm_mday)

    def __str__(self):
        return '%s-%s-%s' % (self.__year, self.__month, self.__day)


d = Date(2020, 1, 1)
print("对象类型:", type(d))  # <class '__main__.Date'> 返回的是类名,他是由这个类创建出来的 就像以前type('s'),返回的是str,是他的类
print("判断是否有year这个属性:", hasattr(d, 'year'))
print("判断是否有time这个属性:", hasattr(d, 'time'))
# setattr(d,'day','9')                     报错, 他是私有属性,用了@property只能查看不能修改
print('day属性为:', getattr(d, 'day'))
# setattr(d,'time','1:1:1')                报错, slots 限制了不能添加其他属性
# print('time属性为:', getattr(d,'time'))
print(Date.today())

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值