include, extend, class_eval 用法

本文通过多个案例详细解析了Ruby中模块包含(include)和扩展(extend)的区别与使用方法,包括如何定义实例方法与类方法,以及运行时动态添加方法。

引用 :http://www.neeraj.name/blog/articles/503

 

 

Ruby is fun. However it took me a while to understand various semantics like include, extend, module_eval, class_eval. It all gets confusing in the beginning. Here are series of cases illustrating the simple concept of having a person with an instance method name and and a class method count.

# Case 1
# Simple case of a class having an instance method and a class method
class Person
  def self.count
    21
  end

  def name
    "Neeraj"
  end
end

puts Person.count
puts Person.new.name
# Case 2
# A class includes a module to have an instance method
module PersonName
  def name
    "Neeraj"
  end
end

class Person
  def self.count
    21
  end
  include PersonName
end

puts Person.count
puts Person.new.name
# Case 3
# A module with self.method doesn't become a class method as 
# it might seem on the surface
module PersonModule
  def name
    "Neeraj"
  end
  def self.count
    21
  end
end

class Person
  include PersonModule
end

puts Person.new.name
# Following operation does not work. Exception message is undefined 
# method `count' for Person:Class (NoMethodError)
puts Person.count 
# Case 4
# Including a module and thus creating a class method is a bit tricky. 
# Simpler solutions are  presented in next versions.
module PersonModule
  def self.included(base_class)
    base_class.extend(ClassMethods)
  end

  def name
      "Neeraj"
  end

   module ClassMethods
    def count
      21
    end
  end
end

class Person
  include PersonModule
end

puts Person.new.name
puts Person.count 
# Case 5
# Extending a module creats the class method. 
# Contrast it with the include module_name (presented later)
module PersonModule
  def count
    21
  end
end

class Person
  extend PersonModule  
  def name
      "Neeraj"
  end
end

puts Person.new.name
puts Person.count 
# Case 6
# Mix and match. Use both include and extend to get instance and class methods.
module PersonModuleCount
  def count
    21
  end
end

module PersonModuleName
  def name
    "Neeraj"
  end
end

class Person  
  extend PersonModuleCount
  include PersonModuleName
end

puts Person.new.name
puts Person.count 
# Case 7
# Accessing the anonymous class to create a class method

module PersonModuleCount
  def count
    21
  end
end

module PersonModuleName
  def name
    "Neeraj"
  end
end

class Person  
  class << self
    include PersonModuleCount
  end
  include PersonModuleName
end

puts Person.new.name
puts Person.count 
# Case 8
# Another way of creating a class method class << person

module PersonModuleCount
  def count
    21
  end
end

module PersonModuleName
  def name
    "Neeraj"
  end
end

class Person  
  include PersonModuleName
end
class << Person  
    include PersonModuleCount
end

puts Person.new.name
puts Person.count 
# Case 9
# Usage of class_eval

class Person
end

Person.class_eval do 
  def name
    "Neeraj"
  end
  def self.count
    21
  end  
end

puts Person.new.name
puts Person.count 
# Case 10
# Usage of class_eval in different flavor.

class Person
end

Person.class_eval <<-EOF
  def name
    "Neeraj"
  end

  def self.count
    21
  end  
EOF

puts Person.new.name
puts Person.count 
# Case 11
# Metaprogramming. Creating methods by defining them on run time.

class_name = "Person"
klass = Object.const_set(class_name,Class.new)
klass.class_eval do
  class << self
    define_method(:count) do 
      21
    end
  end

  define_method(:name) do 
    "Neeraj"    
  end
end

puts Person.new.name
puts Person.count 
# Case 12
# Usage of send to include modules. Plugins use this pattern often.

module PersonModuleCount
  def count
    21
  end
end

module PersonModuleName
  def name
    "Neeraj"
  end
end

class Person  
  class << self
    include PersonModuleCount    
  end
  send(:include, include PersonModuleName)
end

puts Person.new.name
puts Person.count 
# Case 13
# Imagine this case. A class includes a module. An instance of this class is
created.
# Then a new method is added to the module. Will the object instance willl have
# this method  which was added to the module after the object was created.
module PersonName
  def name
    "Neeraj"
  end
end

class Person
  def self.count
    21
  end
  include PersonName
end

person = Person.new

module PersonName
  def name2
    "Neeraj"
  end
end

puts person.name2

# it works. It works because when the metho name2 is executed and this method is
not
# found in the class then control looks for the included module. It means the
# methods inside module are not embedded in the object when it was created.
Rather
# it was just a soft reference.

# Let's take this case to next level. Let's add a new include to the class after
the
# object is created. This will tell us if all the list of includes are scanned
during
# run time or the list of includes are embedded inside the object when it was
# created

module PersonLate
  def late_name
    "I was added later"
  end
end

class Person
  include PersonLate
end

puts person.late_name

# it works. It menas ruby actually scans for the includes during the run time
and
# creating an object is well, put it simply, just an object.

# include is a method.
import tensorflow as tf import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import classification_report, confusion_matrix import seaborn as sns from time import time from matplotlib import rcParams rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体 rcParams['axes.unicode_minus'] = False # 避免负号显示问题 # 数据集加载函数 def data_load(data_dir, test_data_dir, img_height, img_width, batch_size): train_ds = tf.keras.preprocessing.image_dataset_from_directory( data_dir, label_mode='categorical', seed=123, image_size=(img_height, img_width), batch_size=batch_size) val_ds = tf.keras.preprocessing.image_dataset_from_directory( test_data_dir, label_mode='categorical', seed=123, image_size=(img_height, img_width), batch_size=batch_size) class_names = train_ds.class_names return train_ds, val_ds, class_names # 构建MobileNet模型 def model_load(IMG_SHAPE=(224, 224, 3), class_num=15): base_model = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE, include_top=False, weights='imagenet') base_model.trainable = False model = tf.keras.models.Sequential([ tf.keras.layers.experimental.preprocessing.Rescaling(1. / 127.5, offset=-1, input_shape=IMG_SHAPE), base_model, tf.keras.layers.GlobalAveragePooling2D(), tf.keras.layers.Dense(class_num, activation='softmax') ]) model.summary() model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) return model # 绘制训练过程中的损失和准确率 def show_loss_acc(history): acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] plt.figure(figsize=(8, 8)) plt.subplot(2, 1, 1) plt.plot(acc, label='Training Accuracy') plt.plot(val_acc, label='Validation Accuracy') plt.legend(loc='lower right') plt.ylabel('Accuracy') plt.ylim([min(plt.ylim()), 1]) plt.title('Training and Validation Accuracy') plt.subplot(2, 1, 2) plt.plot(loss, label='Training Loss') plt.plot(val_loss, label='Validation Loss') plt.legend(loc='upper right') plt.ylabel('Cross Entropy') plt.title('Training and Validation Loss') plt.xlabel('epoch') plt.savefig('results/results_mobilenet.png', dpi=100) # 评估模型函数 def evaluate_model(model, val_ds, class_names): y_true = [] y_pred = [] for images, labels in val_ds: predictions = model.predict(images) y_pred.extend(np.argmax(predictions, axis=1)) y_true.extend(np.argmax(labels, axis=1)) cm = confusion_matrix(y_true, y_pred) print("Confusion Matrix:") print(cm) print("Classification Report:") print(classification_report(y_true, y_pred, target_names=class_names, digits=4)) plt.figure(figsize=(10, 8)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names) plt.xlabel('Predicted') plt.ylabel('True') plt.title('Confusion Matrix') plt.show() # 自定义回调函数,用于动态打印评价指标 class PrintEvalCallback(tf.keras.callbacks.Callback): def on_epoch_end(self, epoch, logs=None): print(f"Epoch {epoch + 1}: " f"loss={logs['loss']:.4f}, accuracy={logs['accuracy']:.4f}, " f"val_loss={logs['val_loss']:.4f}, val_accuracy={logs['val_accuracy']:.4f}") # 主训练函数 def train(epochs): begin_time = time() train_ds, val_ds, class_names = data_load( "D:/1/WeChat Files/wxid_c6n47k03okeu22/FileStorage/File/2024-05/vegetables_tf2.3-master/data/train", "D:/1/WeChat Files/wxid_c6n47k03okeu22/FileStorage/File/2024-05/vegetables_tf2.3-master/data/valid", 224, 224, 16 ) print("Class Names:", class_names) model = model_load(class_num=len(class_names)) # 使用自定义回调函数 eval_callback = PrintEvalCallback() history = model.fit(train_ds, validation_data=val_ds, epochs=epochs, callbacks=[eval_callback]) model.save("models/mobilenet_fv.h5") end_time = time() print('Training time:', end_time - begin_time, "seconds") show_loss_acc(history) evaluate_model(model, val_ds, class_names) if __name__ == '__main__': train(epochs=10)import tensorflow as tf from PyQt5.QtGui import QIcon, QFont, QPixmap from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTabWidget, QFileDialog, QMessageBox import sys import cv2 from PIL import Image import numpy as np import shutil class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowIcon(QIcon('images/logo.png')) # 确保路径正确 self.setWindowTitle('蔬菜识别系统') self.model = tf.keras.models.load_model("models/mobilenet_fv.h5") self.to_predict_name = "images/tim9.jpeg" self.class_names = ['豆', '苦瓜', '葫芦瓜', '茄子', '西兰花', '胡萝卜', '包菜', '辣椒', '西红柿', '花菜', '土豆', '黄瓜','番木瓜', '南瓜', '白萝卜', ] self.resize(900, 700) self.initUI() def initUI(self): main_widget = QWidget() main_layout = QHBoxLayout() font = QFont('楷体', 15) left_widget = QWidget() left_layout = QVBoxLayout() img_title = QLabel("样本") img_title.setFont(font) img_title.setAlignment(Qt.AlignCenter) self.img_label = QLabel() # 读取并检查图像 img_init = cv2.imread(self.to_predict_name) if img_init is None: print(f"Error: 无法加载图像文件 '{self.to_predict_name}'。请检查文件路径和文件名。") sys.exit(1) h, w, c = img_init.shape scale = 400 / h img_show = cv2.resize(img_init, (0, 0), fx=scale, fy=scale) cv2.imwrite("images/show.png", img_show) img_init = cv2.resize(img_init, (224, 224)) cv2.imwrite('images/target.png', img_init) self.img_label.setPixmap(QPixmap("images/show.png")) left_layout.addWidget(img_title) left_layout.addWidget(self.img_label, 1, Qt.AlignCenter) left_widget.setLayout(left_layout) right_widget = QWidget() right_layout = QVBoxLayout() btn_change = QPushButton("上传图片") btn_change.clicked.connect(self.change_img) btn_change.setFont(font) btn_predict = QPushButton("开始识别") btn_predict.setFont(font) btn_predict.clicked.connect(self.predict_img) label_result = QLabel('蔬菜名称') self.result = QLabel("等待识别") label_result.setFont(QFont('楷体', 16)) self.result.setFont(QFont('楷体', 24)) right_layout.addStretch() right_layout.addWidget(label_result, 0, Qt.AlignCenter) right_layout.addStretch() right_layout.addWidget(self.result, 0, Qt.AlignCenter) right_layout.addStretch() right_layout.addStretch() right_layout.addWidget(btn_change) right_layout.addWidget(btn_predict) right_layout.addStretch() right_widget.setLayout(right_layout) main_layout.addWidget(left_widget) main_layout.addWidget(right_widget) main_widget.setLayout(main_layout) about_widget = QWidget() about_layout = QVBoxLayout() about_title = QLabel('欢迎使用蔬菜识别系统') about_title.setFont(QFont('楷体', 18)) about_title.setAlignment(Qt.AlignCenter) about_img = QLabel() about_img.setPixmap(QPixmap('images/bj.jpg')) about_img.setAlignment(Qt.AlignCenter) label_super = QLabel("作者:杨益") label_super.setFont(QFont('楷体', 12)) label_super.setAlignment(Qt.AlignRight) about_layout.addWidget(about_title) about_layout.addStretch() about_layout.addWidget(about_img) about_layout.addStretch() about_layout.addWidget(label_super) about_widget.setLayout(about_layout) self.tab_widget = QTabWidget() self.tab_widget.addTab(main_widget, '主页') self.tab_widget.addTab(about_widget, '关于') self.tab_widget.setTabIcon(0, QIcon('images/主页面.png')) self.tab_widget.setTabIcon(1, QIcon('images/关于.png')) self.setCentralWidget(self.tab_widget) def change_img(self): openfile_name, _ = QFileDialog.getOpenFileName(self, '选择文件', '', 'Image files(*.jpg *.png *jpeg)') if openfile_name: target_image_name = "images/tmp_up." + openfile_name.split(".")[-1] shutil.copy(openfile_name, target_image_name) self.to_predict_name = target_image_name img_init = cv2.imread(self.to_predict_name) if img_init is None: print(f"Error: 无法加载图像文件 '{self.to_predict_name}'。请检查文件路径和文件名。") return h, w, c = img_init.shape scale = 400 / h img_show = cv2.resize(img_init, (0, 0), fx=scale, fy=scale) cv2.imwrite("images/show.png", img_show) img_init = cv2.resize(img_init, (224, 224)) cv2.imwrite('images/target.png', img_init) self.img_label.setPixmap(QPixmap("images/show.png")) self.result.setText("等待识别") def predict_img(self): img = Image.open('images/target.png') img = np.asarray(img) outputs = self.model.predict(img.reshape(1, 224, 224, 3)) result_index = int(np.argmax(outputs)) result = self.class_names[result_index] self.result.setText(result) def closeEvent(self, event): reply = QMessageBox.question(self, '退出', "是否要退出程序?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: event.accept() else: event.ignore() if __name__ == "__main__": app = QApplication(sys.argv) x = MainWindow() x.show() sys.exit(app.exec_())这个代码是否正确
06-02
本系统旨在构建一套面向高等院校的综合性教务管理平台,涵盖学生、教师及教务处三个核心角色的业务需求。系统设计着重于实现教学流程的规范化与数据处理的自动化,以提升日常教学管理工作的效率与准确性。 在面向学生的功能模块中,系统提供了课程选修服务,学生可依据培养方案选择相应课程,并生成个人专属的课表。成绩查询功能支持学生查阅个人各科目成绩,同时系统可自动计算并展示该课程的全班最高分、平均分、最低分以及学生在班级内的成绩排名。 教师端功能主要围绕课程与成绩管理展开。教师可发起课程设置申请,提交包括课程编码、课程名称、学分学时、课程概述在内的新课程信息,亦可对已开设课程的信息进行更新或撤销。在课程管理方面,教师具备录入所授课程期末考试成绩的权限,并可导出选修该课程的学生名单。 教务处作为管理中枢,拥有课程审批与教学统筹两大核心职能。课程设置审批模块负责处理教师提交的课程申请,管理员可根据教学计划与资源情况进行审核批复。教学安排模块则负责全局管控,包括管理所有学生的选课最终结果、生成包含学号、姓名、课程及成绩的正式成绩单,并能基于选课与成绩数据,统计各门课程的实际选课人数、最高分、最低分、平均分以及成绩合格的学生数量。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值