python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式

文章目录

  • python 面向对象高级特性
    • 一、类与实例
      • 1.类属性和实例属性
    • 二、类方法和静态方法
        • 类方法能够通过实例对象和类对象去访问。
        • 静态方法能够通过实例对象和类对象去访问。
      • 1. @classmethod: 类方法
      • 2. @staticmethod:静态方法
      • 3.类方法和静态方法的应用
    • 三、@property类属性
      • 1.property属性的定义和调用要注意一下几点:
      • 2.类属性应用
        • 1)应用场景一: 某个属性只能访问不能修改时使用。
          • 2)应用场景二:某一个属性不能直接返回, 需要计算的, 可以通过property属性实现
      • 3.property属性
        • 1)property通过函数的方式实现类属性
        • 2)property通过desc的方式实现类属性
    • 四、 单例模式(敲重点)
      • 1.为什么要实现单利模式
      • 2.怎样实现单利模式
        • (1)装饰器实现单例模式
        • (2)new方法实现单例模式
        • (2)new方法实现单例模式改进版
    • 五、面向对象汇总

python 面向对象高级特性

一、类与实例

1.类属性和实例属性

1). 类属性不管有多少个对象, 都只存储一份。
实例属性存储的个数取决于实例的个数.
2). 作用域不同:
类属性: 通过类名/对象名来访问
实例属性: 只能通过对象名来访问。

import random
class Turtle(object):
    # power是类属性。
    power = 100
    def __init__(self):
        # x,y:实例属性.
        self.x = random.randint(0, 10)
        self.y = random.randint(0, 10)
# 1). 类属性不管有多少个对象, 都只存储一份。 实例属性存储的个数取决于实例的个数.
# 2). 作用域不同:
#		类属性: 通过类名/对象名来访问
#		实例属性: 只能通过对象名来访问。
print(Turtle.power)
turtle1 = Turtle()
print(turtle1.power, turtle1.x, turtle1.y)

二、类方法和静态方法

1). @classmethod: 类方法
2). @staticmethod:静态方法

类方法能够通过实例对象和类对象去访问。

静态方法能够通过实例对象和类对象去访问。

1. @classmethod: 类方法

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

2. @staticmethod:静态方法

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


1). @classmethod: 类方法
2). @staticmethod:静态方法
"""

import random
class Turtle(object):
    def __init__(self):
        # x,y:实例属性.
        self.x = random.randint(0, 10)
        self.y = random.randint(0, 10)
        self.power = 100

    # 默认情况下, Python解释器会自动将对象传递给类里面定义的方法。
    def eat(self):
        print("self: ", self)
        self.power += 20
    @classmethod
    def cls_example(cls):
        print("cls: ", cls)

    @staticmethod
    def static_example():
        print("静态方法.......")
turtle = Turtle()
turtle.eat()
turtle.cls_example()
turtle.static_example()
# 类方法能够通过实例对象和类对象去访问。
Turtle.cls_example()
# 静态方法能够通过实例对象和类对象去访问。
Turtle.static_example()


3.类方法和静态方法的应用


import time

"""
# 系统自带date类的使用
from datetime import date

dateObj = date(2019, 10, 10)
print(dateObj)
print(date.today())
"""

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

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

    @classmethod
    def today(cls):
        """
        返回当前的日期对象
        cls: 类名称Date
        :return: Date实例化的对象名称
        """
        # 获取当前的时间, 返回的是命名元组的格式
        # time.struct_time(tm_year=2019, tm_mon=12, tm_mday=29, tm_hour=16, tm_min=49, tm_sec=32, tm_wday=6, tm_yday=363, tm_isdst=0)
        now = time.localtime()
        return cls(now.tm_year, now.tm_mon, now.tm_mday)

    def is_leap(self):
        """
        判断是否为闰年?
        一个闰年就是能被4整除但是不能被100整除 或者 year能被400整除.
        :return:
        """
        return (self.year % 4 == 0 and self.year % 100 != 0) or (self.year % 400 == 0)


if __name__ == '__main__':
    # 获取当前日期, today是当前日期对象。
    today = Date.today()
    # 打印日期对象, 返回字符串'2019-12-29', 因为有__str__魔术方法。
    print(today)
    # 判断是否为闰年?
    print("今年是否为闰年? ", today.is_leap())


    # dateObj = Date(2019, 10, 10)
    # print(dateObj)


三、@property类属性

功能: 将类方法转换成类属性

1.property属性的定义和调用要注意一下几点:

  1. 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数
  2. 调用时,无需括号

2.类属性应用

1)应用场景一: 某个属性只能访问不能修改时使用。


from datetime import date


class Date(object):
    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

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


if __name__ == '__main__':
    dateObj = Date(2019, 12, 12)
    print(dateObj.day)   # 调用时,无需括号

2)应用场景二:某一个属性不能直接返回, 需要计算的, 可以通过property属性实现

分页显示是一种非常常见的浏览和显示大量数据的方法,属于web编程中最常处理的事件之一。

类属性应用需求: 对于京东商城中显示电脑主机的列表页面,每次请求不可能把数据库
中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求
数据时就要显示的指定获取从第start条到第end条的所有数据 这个分页的功能包括:
• 根据用户请求的当前页和总数据条数计算出 start 和 end
• 根据start 和 end 去数据库中请求数据
• 是否有上一页has_prev、下一页has_next
• 上一页prev、下一页next
• 总页数pages, 数据总条数total、当前页信息items

"""
# 应用场景二: 某一个属性不能直接返回, 需要计算的, 可以通过property属性实现
goods = ["电脑" + str(i) for i in range(100)]
"""


class Pagintor(object):
    """实现商品分页的类"""
    def __init__(self, objects_list, page=1, per_page=5):
        """
        :param objects_list: 商品列表
        :param page: 当前需要显示的页码信息
        :param per_page: 每页显示的数据个数
        """
        self.objects_list = objects_list
        self.page = page
        self.per_page = per_page

    @property
    def start(self):
        return (self.page - 1) * self.per_page

    @property
    def end(self):
        return self.page * self.per_page

    @property
    def total(self):
        """
        数据总条数total
        :return:
        """
        return len(self.objects_list)

    @property
    def pages(self):
        """
        总页数pages
        if 总商品数量%每页显示数量==0:  刚好当前页显示满
        else: 好友多与的部分, 在计算的结果上面加1
        self.total = 5  pages=1
        self.total = 6  pages=2
        :return:
        """
        result = self.total // self.per_page
        if self.total % self.per_page == 0:
            return result
        else:
            return result + 1

    @property
    def has_next(self):
        return True if 0 < self.page + 1 <= self.pages else False

    @property
    def next(self):
        next_page = self.page - 1
        next_start = (next_page - 1) * self.per_page
        next_end = self.page * self.per_page
        return self.objects_list[next_start:next_end]

    @property
    def has_prev(self):
        return True if 0 < self.page - 1 <= self.pages else False

    @property
    def prev(self):
        prev_page = self.page - 1
        prev_start = (prev_page - 1) * self.per_page
        prev_end = self.page * self.per_page
        return self.objects_list[prev_start:prev_end]

    @property
    def items(self):
        """
        当前页信息items
        :return:
        """
        return self.objects_list[self.start:self.end]


if __name__ == '__main__':
    # 应用场景二: 某一个属性不能直接返回, 需要计算的, 可以通过property属性实现
    goods = ["电脑" + str(i) for i in range(5)]
    # 需求: 显示第三页时, 开始的索引是? 结束的索引为多少?
    pagintor = Pagintor(goods, page=1, per_page=6)
    print("第1页的商品信息为: ", goods[pagintor.start:pagintor.end])
    print("是否有上一页?", pagintor.has_prev)
    print("总页数?", pagintor.pages)

3.property属性

property属性的有两种方式: •
装饰器 即:在方法上应用装饰器 •
类属性 即:在类中定义值为property对象的类属性

注意: •
经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法 •
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方 法名.setter、@方法名.deleter修饰的方法

1)property通过函数的方式实现类属性

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


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

    @property
    def is_age_vaild(self):
        return  0 < self.__age <= 150
    def get_age(self):
        if self.is_age_vaild:
            return self.__age
        else:
            raise Exception("年龄不合法")

    def set_age(self, age):
        if self.is_age_vaild:
            self.__age = age
        else:
            raise Exception("年龄不合法")

    def del_age(self):
        print("年龄属性删除......")
    # 类属性 即:在类中定义值为property对象的类属性
    age = property(fget=get_age, fset=set_age, fdel=del_age)


if __name__ == '__main__':
    p1 = Person("张三", 30)
    print(p1.age)
    p1.age = 31
    print(p1.age)
    del p1.age

python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式_第1张图片

2)property通过desc的方式实现类属性

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

    @property
    def score(self):
        return  self.__score
    @score.setter
    def score(self, score):
        self.__score = score

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

    @property           # 获取age属性时执行的内容
    def age(self):
        if self.is_age_vaild:
            return self.__age
        else:
            raise Exception("年龄不合法")
    @age.setter         # 设置age属性时执行的内容
    def age(self, age):
        if self.is_age_vaild:
            self.__age = age
        else:
            raise Exception("年龄不合法")
    @age.deleter        # 删除age属性时执行的内容
    def age(self):
        print("年龄属性删除......")

if __name__ == '__main__':
    p1 = Person("张三", 30, 100)
    print(p1.age)       # 获取年龄(), 执行@property def age(self):
    p1.age = 31         # 设置年龄, age=31
    print(p1.age)
    del p1.age          # 删除年龄属性

四、 单例模式(敲重点)

简单说就是:一个类只能构建一个对象

1.为什么要实现单利模式

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有要实现一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要

2.怎样实现单利模式

(1)装饰器实现单例模式

思路:
当实例化对象时, 判断该类是否实例化过对象。
- 如果是, 返回之前实例化的对象。
- 如果不是, 实例化第一个对象, 并将实例化后的对象存储起来(缓存).


from functools import wraps
def singleton(cls):
    """
    实现单例模式的装饰器
    思路: 当实例化对象时, 判断该类是否实例化过对象。
    - 如果是, 返回之前实例化的对象。
    - 如果不是, 实例化第一个对象, 并将实例化后的对象存储起来(缓存)。
    """
    instances = {}  # {'Person': obj}

    @wraps(cls)
    def wrapper(*args, **kwargs):
        name = cls.__name__
        if instances.get(name):
            # 直接返回缓存中的对象
            return instances.get(name)
        else:
            # 第一次实例化对象
            obj = cls(*args, **kwargs)
            # 类名作为key值, 对象作为value值, 存储到instances字典中.
            instances[name] = obj
            return obj

    return wrapper

@singleton
class Person(object):
    pass

if __name__ == '__main__':
    p1 = Person()
    p2 = Person()
    # 面试题目: ==和is有什么区别?
    print("单例模式是否成功?", p1 is p2)

python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式_第2张图片

(2)new方法实现单例模式


class Person(object):
    # 1). 设置类属性, 存储已经创建好的对象。
    _instance = None
    def __new__(cls, *args, **kwargs):
        print("new方法在实例化对象之前执行.....返回对象本身")
        # 2). 判断是否已经实例化对象?
        if cls._instance:
            return  cls._instance
        else:
            self = object.__new__(cls)
            cls._instance = self
            # 返回父类object的new方法创建的对象.....
            return self

    def __init__(self):
        print("构造方法实例化对象之后执行......")

if __name__ == '__main__':
    p1 = Person()
    p2 = Person()
    print(p1, p2)

python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式_第3张图片

(2)new方法实现单例模式改进版


from datetime import  date

class Person(object):
    def __new__(cls, *args, **kwargs):
        print("判断当前类是否拥有instance属性?", hasattr(cls, 'instance'))
        if not hasattr(cls, 'instance'):
            cls.instance = super(Person, cls).__new__(cls)
        return  cls.instance

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

p1 = Person("张三")
p2 = Person("张xxx")
print("单例模式是否成功? ", p1 is p2)

python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式_第4张图片

五、面向对象汇总

python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式_第5张图片

你可能感兴趣的:(python 面向对象高级特性----类与实例 & 类属性与实例属性 & 类方法与静态方法 & @property属性 & 单利模式)