【问题标题】:How to pass arguments when instantiating a class to a function in Python?将类实例化到Python中的函数时如何传递参数?
【发布时间】:2021-10-05 04:02:45
【问题描述】:

我已尝试仅描绘和记录每个类的必要内容,希望您能帮助我,我正在尝试实例化 Show_image 需要两个参数, 图像列表的两个索引,如果你能指导我,如果我想做的事情是可能的,我将不胜感激。谢谢。

此类调整图像大小

from tkinter importante *
from PIL import Image, ImageTk

class Array(Frame):
    def __init__(self, master, path, *args):
        Frame.__init__(self, master, *args)       self.image = Image.open(path)
        self.img_copy = self.image.copy()

        self.background_image = ImageTk.PhotoImage(self.image)

        self.background = Label(self, image=self.background_image)
        self.background.pack(fill='both', expand=True)
        self.background.bind('<Configure>', self._resize_image)

    def _resize_image(self, event):
        self.image = self.img_copy .resize ((self.master .winfo_width(), self.master .winfo_height()))

        self.background_image = ImageTk.PhotoImage(self.image)
        self.background.configure(image=self.background_image)

基类控件

class Interface(Frame):
    def __init__(self, master, *args):
        Frame.__init__(self, master, *args)
        self.path_lst = ['11.png','22.png','33.png','44.png']  # change/add paths 
        self._frame_1 = None
        self._open_1 = False
        self.button1 = Button(self, text='pack 1',
                      command= lambda:self.windows(Show_image))
        self.button1 .pack()
 
    def windows(self, var_1):
        if not self._open_1:
            self.top1 = Toplevel(self.master)
            self.top1 .geometry('200x200')
                                
        container = var_1(self.top1)

        if self._frame_1 is not None:  
            self._frame_1 .destroy()
        self._frame_1 = container
        self._frame_1 .pack()
        self._open_1 = True

        self.top1.protocol ('WM_DELETE_WINDOW', lambda: self.closed(1))
    
    def closed(self, number):
        if number == 1:
            self.top1. destroy()
            self._open_1 = False


这个类应该画两个实例,两个图像,但是我不知道怎么传 &lt;index_1&gt; &lt;index_2&gt; arguments in bound &lt;lambda&gt; 函数。

class Show_image(Frame):
    def __init__(self, index_1, index_2, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        self.img = Array(self, self.master.path_lst[index_1])
        self.img .grid(column=0, row=0)
        self.img2 = Array(self, self.master.path_lst[index_2])
        self.img2 .grid(column=0, row=1)

root = Tk()
frm = Interface(root)
frm .pack()
root.mainloop()

另外,如果您能告诉我图像的初始化路径是否正确。谢谢。

【问题讨论】:

  • 我不确定我是否在关注;你是这个意思吗? self.button1 = Button(self, text='pack 1', command= lambda:self.windows(Show_image(index_1, index_2, args, kwargs)))
  • @Schalton 感谢您的帮助,但我担心&lt;path_lst&gt; 列表有问题,因为&lt;Show_image&gt; 类无法识别它并且我正在抛出错误.抱歉,这是我的另一个错误,一旦我解决了它,我会测试&lt;lambda top&gt; 是否适合我。谢谢你给我的帮助,我很感激。

标签: python arguments


【解决方案1】:

如果我理解你将不得不使用嵌套的lambdas

command=lambda:self.windows(lambda:Show_image(index1, index2))

但我看到windows 运行带有参数top 的函数,所以它在lambda 中也需要它

command=lambda:self.windows( lambda top:Show_image(index1, index2, top))

编辑:

包含其他更改的完整工作代码。

我发送master 作为第一个值,path_lst 作为最后一个值,我不需要使用self.master.pack_lst

我更改了一些pack()grid() 并添加了grid_rowconfigure(),以便在窗口更改大小时正确调整图像大小。

我使用os.listdir() 创建path_lst。它使用sys.argv 从命令行(python script.py path_to_images)获取folder,或者使用os.getcwd() 获取Current Working Directory 作为folder

我将名字改为ShowImage 建议PEP8 - CamelCaseNames 上课。

我不确定它是否建议将noun 用于类(例如名词ImageViewer 而不是动词ShowImage)和verb 用于功能(例如动词show_window 而不是名词windows)但我跳过它。也许是书中的建议'Clean Code' by Robert C. Martin(也称为Uncle Bob

PEP 8 -- Style Guide for Python Code

import os   # os.path.join(), os.listdir()
import sys  # sys.argv
#from tkinter import *  # PEP8: `import *` is not preferred
import tkinter as tk 
from PIL import Image, ImageTk

# --- constants ---  # PEP8: `UPPER_CASE_NAMES

#FOLDER = '/home/furas/test'

# --- classes ---  # PEP8: `CamelCaseNames` 

class Array(tk.Frame):
    def __init__(self, master, path, *args):
        super().__init__(master, *args)   # in Python 3 you can use `super()` without `self`
        
        self.image = Image.open(path)
        self.img_copy = self.image.copy()

        self.background_image = ImageTk.PhotoImage(self.image)

        self.background = tk.Label(self, image=self.background_image)
        self.background.pack(fill='both', expand=True)
        self.background.bind('<Configure>', self._resize_image)

    def _resize_image(self, event):
        self.image = self.img_copy.resize((self.master.winfo_width(), self.master.winfo_height()//2))

        self.background_image = ImageTk.PhotoImage(self.image)
        self.background.configure(image=self.background_image)


class Interface(tk.Frame):
    def __init__(self, master, folder, *args):
        super().__init__(master, *args)
        
        self.folder = folder
        
        #self.path_lst = ['11.png','22.png','33.png','44.png']  # change/add paths
        self.path_lst = [os.path.join(self.folder, name) for name in os.listdir(self.folder) if name.lower().endswith(('.png', '.jpg', '.gif'))]  # change/add paths
        
        self._frame_1 = None
        self._open_1 = False
        
        index_1 = 0
        index_2 = 1
        
        self.button1 = tk.Button(self, text='pack 1',
                      command=lambda:self.windows(lambda top:ShowImage(top, index_1, index_2, self.path_lst)))
        self.button1.pack()
 
    def windows(self, var_1):
        if not self._open_1:
            self.top1 = tk.Toplevel(self.master)
            self.top1.geometry('200x200')
                                
        container = var_1(self.top1)

        if self._frame_1 is not None:  
            self._frame_1.destroy()
            
        self._frame_1 = container
        self._frame_1.pack(fill='both', expand=True)
        self._open_1 = True

        self.top1.protocol('WM_DELETE_WINDOW', lambda: self.closed(1))
    
    def closed(self, number):
        if number == 1:
            self.top1.destroy()
            self._open_1 = False


class ShowImage(tk.Frame):
    def __init__(self, master, index_1, index_2, path_lst, *args, **kwargs):
        super().__init__(master, *args, **kwargs)
        
        if len(path_lst) > index_1:
            self.img = Array(self, path_lst[index_1])
            self.img.grid(column=0, row=0, sticky='news')
        
        if len(path_lst) > index_2:
            self.img2 = Array(self, path_lst[index_2])
            self.img2.grid(column=0, row=1, sticky='news')

        # column 0 will use full width
        self.grid_columnconfigure(0, weight=1)
        # row 0 will use 1/2 height AND row 1 will use 1/2 height
        self.grid_rowconfigure(0, weight=1)     
        self.grid_rowconfigure(1, weight=1)

# --- functions ---  # PEP8: `lower_case_names`

# empty

# --- main ---

if len(sys.argv) > 1:
    folder = sys.argv[1]
else:
    folder = os.getcwd()

#folder = FOLDER

root = tk.Tk()
frm = Interface(root, folder)
frm.pack()
root.mainloop()

顺便说一句:

因为窗口必须显示两个图像,所以我将Array 中的高度除以 2 (self.master.winfo_height()//2) 以适应窗口中的两个行/图像。

【讨论】:

  • 感谢您的帮助,但我担心&lt;path_lst&gt; 列表有问题,因为&lt;Show_image&gt; 类无法识别它并且我抛出了一个错误。抱歉,这是我的另一个错误,一旦我解决了它,我会测试&lt;lambda top&gt; 是否适合我。感谢您给我的帮助,我很感激。
  • 很抱歉再次打扰您,确定您还有其他事情要做,但是如果我打算实例化 &lt;Show_image&gt; 类的 3 个对象,则此语法有效:command = lambda: self.windows (lambda top, top2, top3: Show_image (index1, index2, top, top2, top3))
  • 至于path_lst:您在InterfaceShow_image 中有path_lst,您使用self.master.path_lst,但Interface 不是Show_image 的主控 - 它需要发送self 作为参数Show_image(index_1, index_2, self, top),然后它将self, top 分配给*args,这会将*args 发送给Frame.__init__(...),它会将*args 的第一个值分配给self.master
  • 也许你应该做类似于Array 并将Show_image 定义为def __init__(self, master, index_1, index_2, *args, **kwargs):master as first argument and run it as Show_image(self, index_1, index_2, top)` 就像你在Array 和标准小部件 - 即。 self.button1 = Button(self, ....)
  • 顺便说一句:您还应该在 Show_init 的分隔变量中捕获 top,因为它会将其捕获为 *args 并将其发送到 Frame.__init__ 并且它不知道如何处理top.
猜你喜欢
  • 1970-01-01
  • 2023-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多