19,面向对象收尾

1,两个装饰器函数

@classmethod

被装饰的方法会成为一个静态方法
    1,什么时候用
        在修改类当中的某个变量,又不想实例化他,在实例化之前就去操作的情况下。
    2,怎么定义?
        1,装饰器怎么加?
        2,参数怎么改?
    3,怎么用?
        1,用谁来调用?
class Goods:
    __discount = 0.8
    def __init__(self):
        self.__price = 5
        self.price = self.__price * self.__discount

    def change_discount(self, new_discount):
        Goods.__discount = new_discount
Goods.change_discount(0.6)
apple = Goods()
print(apple.price)
# x修改折扣,将8折改成折
apple.change_discount(0.6)        # 类方法可以通过对象名调用
apple2 = Goods()
print(apple2.price)
# 上述的方法在逻辑上有一些问题
使用classmethod
定义一个方法,默认传self,但是这个self没被使用
@classmethod 把一个对象绑定的方法修改成一个类方法
优势:
    1,在方法中仍然可以引用类中的静态变量
    2,可以不用实例化对象,就直接用类名在外部调用方法
什么时候用@classmethod;
    1,用不到对象,并且要用到类名的时候
    2,定义了一个方法,默认传self,但是这个self没被使用
    3,并且你在这个方法里用到了当前的类名,或者你准备使用这个类的内存空间中的名字的时候
class Goods:
    __discount = 0.8

    def __init__(self):
        self.__price = 5
        self.price = self.__price * self.__discount

    @classmethod
    def change_discount(cls, new_discount): # 此时cls是指向Goods
        cls.__discount = new_discount       # 这里不管类名是什么cls都是代表类名


Goods.change_discount(0.6)      # 可以通过类名调用类方法
apple = Goods()
print(apple.price)


# 实例化***
import time
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        struct_t = time.localtime()
        print(struct_t.tm_year)
        print(struct_t.tm_mon)
        print(struct_t.tm_mday)
        return date
date = Date()       # 此时调用Date还需要传参
date.today()



# import time
class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod
    def today(cls):
        struct_t = time.localtime()
        date = cls(struct_t.tm_year, struct_t.tm_mon, struct_t.tm_mday)
        return date
date = Date.today()
print(date.year)
print(date.month)
print(date.day)

@staticmethod

1,什么时候用?
    帮助我们把普通的函数挪到类中啦直接使用,制造静态方法用的
2,怎么定义?
3,怎么用?
    用谁来调
@staticmethod*  被装饰的方法会成为一个静态方法
class User:
    pass

    @staticmethod
    def login(a, b):    # 本身是一个普通函数,被挪到类的内部执行那么直接给这个函数添加@staticmethod装饰器就可以了,但是调用时还是要通过类名调用。
        print('登录的逻辑', a, b)
        # 在函数的内部既不会用到self变量,也不会用到cls类

obj = User()
obj.login(1, 2)     # 既可以用类名定义
User.login(3, 4)        # 也可以用对象调用
class A:
    countr = '中国'
    def fuc(self):
        print(self.__dict__)
    @classmethod
    def clas_func(cls):
        print(cls)
    @staticmethod
    def stat_func():
        print('普通函数')
    @property
    def name(self):
        print('property方法')
'''
能定义到类中的内容:
静态变量:country = '中国'
# 所有的对象共享的变量
绑定方法:含有self的方法 由对象调用
# 是个自带self参数的函数
    class A:
        countr = '中国'
        def fuc(self);
            print(self.__dict__)
类方法:加上@classmethod的装饰器用cls作为参数的方法
# 自带cls的参数 由对象/类调用
    @classmethod
    def clas_func(cls);
        print(cls)
静态方法:@staticmethod 将类中的方法,变成一个普通的函数,不需要传参
# 啥都不带的普通函数 有对象/类调用
    @staticmethod
    def stat_func():
        print('普通函数')
property属性:是个伪装成属性的方法 由对象调用 但是不加括号
'''

2,一些内置的魔术方法

一些内置的魔术方法:
    __new__:构造方法,实例化对象的时候使用,用来开辟空间的
        单例模式(默写)
    __call__:只要类中有__call__方法   就可以用对象() 调用
    __len__:len(对象) 需要实现这个类中的__len__方法 只要类中有__len__方法,就可以直接使用len()函数
    __str__:帮助我们在打印\展示对象的时候更直观的显示对象内容 %s字符串拼接  str()类型强制转换 print()
    __repr__:repr是str的备胎,同时还和%r和repr的时候就只会显示这个方法的返回值
item系列
    __gettitem__
__hash__
enter/exit
del

1,__call__

# 1,__call__
# callable(对象)
# 对象能不能运行就是callable判断的事儿(就是看这个类里面有没有__call__方法)
class A:
    def __call__(self, *args, **kwargs):
        print('-------')

obj = A()
print(callable(obj))
obj()       # 对象加括号就是调用这个类下面的__call__方法
# Flask框架的源码使用__call__

2,__len__

class Cls:
    def __init__(self, name):
        self.name = name
        self.student = []
    def __len__(self):
        return len(self.student)

py22 = Cls('py22')
py22.student.append('alex')
py22.student.append('taibai')
py22.student.append('wusir')
print(len(py22))        # 3


# 例子,(理解__len__)
class Pow:
    def __init__(self, n):
        self.n = n
    def __pow2__(self):
        return self.n ** 2

def pow2(obj):
    return obj.__pow2__()

obj = Pow(10)
print(pow2(obj))

3,__new__:单例模式***

class A:
    def __new__(cls, *args, **kwargs):      # 构造方法
        o = super().__new__(cls)
        print('执行new', o)
        return o
    def __init__(self):
        print('执行init', self)

A()
实例化的时候
    先创建一块对象空间,有一个指针能指向类---> __new__
    再调用init
    __new__没有返回值就不会调用__init__
设计模式 -- 单例模式
一个类从头到尾 只会创建一次self空间
class Baby:
    __instance = None

    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super().__new__(cls)
        return cls.__instance

    def __init__(self, cloth, pants):
        self.cloth = cloth
        self.pants = pants


b1 = Baby('红毛衣', '绿皮裤')
b2 = Baby('白衬衫', '黑豹纹')
b3 = Baby('西装', '牛仔裤')
print(b1.cloth)
print(b2.cloth)
print(b3.cloth)

4,__str__

class Course:
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period
    def __str__(self):      # 作用就是查看的时候是一个直观地值,而不是内存地址
        return ','.join([self.name, str(self.price), self.period])

python = Course('python', 21800, '6months')
linux = Course('linux', 19800, '5months')
mysql = Course('mysql', 12800, '4months')
go = Course('go', 15800, '4months')
lst = [python, linux, mysql, go]

for course in lst:
    print(course)

for index, i in enumerate(lst, 1):
    num = int(input('请输入您要选择的课程>>>'))
    course = lst[num-1]
    print(f'恭喜您选课成功,您选的课程是{course.name},价格{course.price}元')
    print(index, i.name)




使用场景
    1,在打印一个对象的时候 调用__str__方法
    2,在%拼接一个对象的时候 调用__str__方法
    3,在str一个对象的时候 调用__str__方法


class clas:
    def __init__(self):
        self.student = []

    def append(self, name):
        self.student.append(name)

    def __str__(self):      #如果不使用__str__(),打印出来的全是内存地址
        return str(self.student)

# 场景一
py22 = clas()
print(py22)
py22.append('大壮')       # ['大壮']
print(py22)
# 场景二
py21 = clas()
py21.append('大壮')
print('我们py21班 %s'%py21)        # 我们py21班 ['大壮']
# 场景三
py21 = clas()
py21.append('大壮')
print(str(py21))        # ['大壮']


 5,__repr__: 和__str__作用相同

1,当我们打印一个对象 用%s进行字符串拼接 或者str(对象)总是调用这个对象的__str__方法
    如果找不到__str__,就调用__repr__方法。
2,__repr__不仅仅是__str__的替代品,还有自己的功能
    用%r进行字符穿拼接 或者用repr(对象)的时候总是会调用这个对象的__repr__方法
class clas:
    def __init__(self):
        self.student = []

    def append(self, name):
        self.student.append(name)

    def __repr__(self):
        return str(self.student)

    def __str__(self):
        return 'aaaa'


py22 = clas()
print(py22)
py22.append('大壮')
print(py22)  # ['大壮']
print('我们py22班 %s' % py22)  # 我们py22班 aaaa
print('我们py22班 %r' % py22)  # 我们py22班 ['大壮']

4,__eq__:判断相等

==这个符号刚好会调用alex对象对应的类的__eq__方法,ale会被当做self参数传入方法,alex222会被当做other参数传入方法
alex == alex222 的结果就是__eq__方法的返回值
# __gt__: 大于
# __lt__: 小于
class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __eq__(self, other):
        print('开始执行我了')
        print(self)
        print(other)
        print('执行完了')
        return 'aaaaaaaaaaa'

alex = Person('alex', 84)
alex222 = Person('alex', 84)
print('-' * 20)
print(alex == alex222)

3,学生系统项目

功能描述

'''
学生选课:核心功能只有选课

角色:学生,管理员

功能:
    1,登录:管理员和学生都可以登录,且登录之后可以自动区分身份
    2,选课:学生可以自由的为自己选择课程
    3,创建用户:选课系统是面向本校的学生,因此所有的用户都应该由管理员完成
    4,查看选课情况:每个学生可以查看自己的选课情况,而管理员应该可以查看所有学生的信息

工作流程:
1,学生:
    1,登录:用户输入用户名和密码
    2,判断身份:在登录的时候应该可以直接判断出用户的身份是学生还是管理员
    3,学生用户:对于学生来说,登录之后有三个功能
        a) 查看所有课程
        b) 选择课程
        c) 查看所选的课程
        d) 退出程序
2,管理员用户:管理员用户除了可以做一些查看功能之外,还有很多创建工作
    1,创建课程
    2,创建学生账号
    3,查看所有课程
    4,查看所有学生
    5,查看所有学生的选课情况
    6,退出程序
3,属性,方法
    1,课程:
        属性:课程名,价格,周期,老师
    2,学生:
        属性:姓名,所选课程
        方法:查看可选的课程,选择课程,查看所选课程,退出程序
    3,管理员:
        属性:姓名
        方法:创建课程,创建学生账号,查看所有学生,查看所有学生的选课情况,退出程序
'''

新建一个userinfo文件存储用户名、用户密码和身份

文件的路径需要自己修改

alex|000|Manager
yutao|123456|Student
import pickle

USERINFO = r'D:\python 代码文件\python全栈学习\01-python基础\18-面向对象收尾\学生系统项目\代码\userinfo'
STUINFO = r'D:\python 代码文件\python全栈学习\01-python基础\18-面向对象收尾\学生系统项目\代码\stuinfo'


class Course:  # 课程类
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period


'''
创建学生
    让用户输入用户名 密码
    实例化一个对象
    把用户名 密码写到userinfo
    把学生对象信息写到stuinfo文件里,将用户名密码和用户信息分开
'''


class Student:
    opt_lst = [('查看课程', 'show_courses'), ('选择课程', 'choose_course'),
               ('查看已选课程', 'show_selected'), ('退出', 'exit')]

    def __init__(self, name):
        self.name = name
        self.courses = []  # 每一个学生一进行注册就有一个空的课程列表

    def show_courses(self):
        pass

    def choose_course(self):
        pass

    def show_selected(self):
        pass

    def __exit__(self):
        pass


class Manager(object):
    opt_lst = [('创建课程', 'create_course'), ('创建学生', 'create_student'),
               ('查看课程', 'show_courses'), ('查看学生', 'show_students'),
               ('查看学生和已选课程', 'show_stu_course'), ('退出', 'exit')]

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

    def create_course(self):
        pass

    def create_student(self):
        user = input('请输入创建的用户名:')
        pwd = '123456'
        stu = Student(user)
        with open(USERINFO, mode='a', encoding='utf-8') as f:
            f.write(f'{user}|123456|Student\n')

        with open(STUINFO, mode='ab') as f:
            pickle.dump(stu, f)  # pickle之后数据是二进制的数据
        print(f'{stu.name}创建成功---操作员{self.name}')

    def show_courses(self):
        pass

    def show_students(self):
        pass

    def show_stu_course(self):
        pass

    def __exit__(self):
        pass
    #
    # @classmethod
    # def init(cls,ret):
    #     obj = cls(ret[0])
    #     return obj


# 用户 输入用户名 密码判断用户是否合法和身份是啥?
def login():
    '''

    :return: 登录成功:返回用户名 身份
             登录失败
    '''
    username = input('username:')
    password = input('passwors:')
    with open(USERINFO, 'r', encoding='utf-8') as f:
        for line in f:
            user, pwd, ident = line.strip().split('|')
            if user == username and password == pwd:
                return user, ident
        else:
            return False

ret = login()
if ret:
    print(f'登录成功!{ret[0]},欢迎使用选课系统')
    if ret[1] == 'Manager':
        m = Manager(ret[0])
        for index, opt in enumerate(Manager.opt_lst, 1):
            print(index, opt[0])
        num = int(input('您要选择的操作:').strip())
        if hasattr(m, Manager.opt_lst[num - 1][1]):
            getattr(m, Manager.opt_lst[num - 1][1])()
    elif ret[1] == 'Student':
        with open(STUINFO, 'rb') as f:
            while True:
                try:
                    obj = pickle.load(f)
                    if obj.name == ret[0]:
                        stu = obj
                        break
                except EOFError:
                    print('没有这个学生')
        s = Student(ret[0])
        for index, opt in enumerate(Student.opt_lst, 1):
            print(index, opt[0])
        num = int(input('您要选择的操作:').strip())
        if hasattr(s, Student.opt_lst[num - 1][1]):
            getattr(s, Student.opt_lst[num - 1][1])()

else:
    print('登录失败!')

优化版:

import pickle
import sys

USERINFO = r'D:\python 代码文件\python全栈学习\01-python基础\18-面向对象收尾\学生系统项目\代码\userinfo'
STUINFO = r'D:\python 代码文件\python全栈学习\01-python基础\18-面向对象收尾\学生系统项目\代码\stuinfo'


class Course:  # 课程类
    def __init__(self, name, price, period):
        self.name = name
        self.price = price
        self.period = period


'''
创建学生
    让用户输入用户名 密码
    实例化一个对象
    把用户名 密码写到userinfo
    把学生对象信息写到stuinfo文件里,将用户名密码和用户信息分开
'''


class Student:
    opt_lst = [('查看课程', 'show_courses'), ('选择课程', 'choose_course'),
               ('查看已选课程', 'show_selected'), ('退出', 'exit')]

    def __init__(self, name):
        self.name = name
        self.courses = []  # 每一个学生一进行注册就有一个空的课程列表

    def show_courses(self):
        pass

    def choose_course(self):
        pass

    def show_selected(self):
        pass

    def __exit__(self):
        pass

    @staticmethod
    def init(ret):
        with open(STUINFO, 'rb') as f:
            while True:
                try:
                    obj = pickle.load(f)
                    if obj.name == ret[0]:
                        return obj
                except EOFError: print('没有这个学生')


class Manager(object):
    opt_lst = [('创建课程', 'create_course'), ('创建学生', 'create_student'),
               ('查看课程', 'show_courses'), ('查看学生', 'show_students'),
               ('查看学生和已选课程', 'show_stu_course'), ('退出', 'exit')]

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

    def create_course(self):
        pass

    def create_student(self):
        user = input('请输入创建的用户名:')
        pwd = '123456'
        stu = Student(user)
        with open(USERINFO, mode='a', encoding='utf-8') as f:
            f.write(f'{user}|123456|Student\n')

        with open(STUINFO, mode='ab') as f:
            pickle.dump(stu, f)  # pickle之后数据是二进制的数据
        print(f'{stu.name}创建成功---操作员{self.name}')

    def show_courses(self):
        pass

    def show_students(self):
        pass

    def show_stu_course(self):
        pass

    def __exit__(self):
        pass

    @classmethod
    def init(cls,ret):
        obj = cls(ret[0])
        return obj


# 用户 输入用户名 密码判断用户是否合法和身份是啥?
def login():
    '''

    :return: 登录成功:返回用户名 身份
             登录失败
    '''
    username = input('username:')
    password = input('passwors:')
    with open(USERINFO, 'r', encoding='utf-8') as f:
        for line in f:
            user, pwd, ident = line.strip().split('|')
            if user == username and password == pwd:
                return user, ident
        else:
            return False


# ----------------------------------------------------------------------------------------------------------------------
# 优化后的代码::
ret = login()
if ret:
    print(f'登录成功!{ret[0]},欢迎使用选课系统')
    cls = getattr(sys.modules[__name__], ret[0])
    obj = cls.init(ret)
    for index, opt in enumerate(cls.opt_lst, 1):
        print(index, opt[0])
    num = int(input('您要选择的操作:').strip())
    if hasattr(obj, Student.opt_lst[num - 1][1]):
        getattr(obj, Student.opt_lst[num - 1][1])()

# ----------------------------------------------------------------------------------------------------------------------

# ret = login()
# if ret:
#     print(f'登录成功!{ret[0]},欢迎使用选课系统')
#     if ret[1] == 'Manager':
#         m = Manager(ret[0])
#         for index, opt in enumerate(Manager.opt_lst, 1):
#             print(index, opt[0])
#         num = int(input('您要选择的操作:').strip())
#         if hasattr(m, Manager.opt_lst[num - 1][1]):
#             getattr(m, Manager.opt_lst[num - 1][1])()
#     elif ret[1] == 'Student':
#         with open(STUINFO, 'rb') as f:
#             while True:
#                 try:
#                     obj = pickle.load(f)
#                     if obj.name == ret[0]:
#                         stu = obj
#                         break
#                 except EOFError:
#                     print('没有这个学生')
#         s = Student(ret[0])
#         for index, opt in enumerate(Student.opt_lst, 1):
#             print(index, opt[0])
#         num = int(input('您要选择的操作:').strip())
#         if hasattr(s, Student.opt_lst[num - 1][1]):
#             getattr(s, Student.opt_lst[num - 1][1])()

else:
    print('登录失败!')

4,练习题目

1,阅读代码,写结果

class Foo(object):
    def __init__(self, name):
        self.name = name

v1 = [Foo for i in range(10)]
v2 = [Foo(5) for i in range(10)]
v3 = [Foo(i) for i in range(10)]


print(v1)
print(v2)
print(v3)

2,阅读代码,写结果

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __eq__(self, other):
        print('开始执行我了')
        print(self)
        print(other)
        print('执行完了')
        return 'aaaaaaaaaaa'

alex = Person('alex', 84)
alex222 = Person('alex', 84)
print('-' * 20)
print(alex == alex222)
print('*' * 20)
print(alex is alex222)

3,阅读代码,写结果

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __eq__(self, other):        # 两个对象作比较的时候自动调用这个方法
        if self.age == other.age and self.name == other.name:
            return 'True'
        else:
            return 'False'
    def __gt__(self, other):
        print('执行gt啦')
    def __lt__(self, other):
        print('执行lt啦')

alex = Person('alex', 83)
alex222 = Person('alex', 84)
print(alex == alex222)

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值