为什么 tkinter 几何管理器方法返回 None 而不是返回调用它们的小部件?

问题描述 投票:0回答:2

编辑:我已通过 cpython 的 GitHub 问题跟踪器将其作为功能改进提案提交。请参阅问题 100891


注意:我认识到这个问题可能接近于“基于意见”——如果有更好的讨论场所,请告诉我,我会将其删除。我很欣赏你的坦诚!

对于 tkinter 新手来说,执行以下操作似乎是一个极其常见的陷阱:

my_button = tkinter.Button(text='Hello').pack()

只会遇到错误,因为

my_button
在链接到几何管理器方法后计算为
None
,即
pack
place
grid

因此,典型的做法是单独声明小部件并将其添加到几何管理器中,例如:

my_button = tkinter.Button(text='Hello')
my_button.pack()

快速查看几何管理器类的源代码表明,返回调用它们的小部件将是一个极其微不足道的更改。可以将同一行添加到每个几何管理器各自的

_configure
方法中:
return self
(我在下面已经这样做了)

打包

class Pack:
    """Geometry manager Pack.
    Base class to use the methods pack_* in every widget."""

    def pack_configure(self, cnf={}, **kw):
        """Pack a widget in the parent widget. Use as options:
        after=widget - pack it after you have packed widget
        anchor=NSEW (or subset) - position widget according to
                                  given direction
        before=widget - pack it before you will pack widget
        expand=bool - expand widget if parent size grows
        fill=NONE or X or Y or BOTH - fill widget if widget grows
        in=master - use master to contain this widget
        in_=master - see 'in' option description
        ipadx=amount - add internal padding in x direction
        ipady=amount - add internal padding in y direction
        padx=amount - add padding in x direction
        pady=amount - add padding in y direction
        side=TOP or BOTTOM or LEFT or RIGHT -  where to add this widget.
        """
        self.tk.call(
              ('pack', 'configure', self._w)
              + self._options(cnf, kw))

        return self  # return the widget passed to this method

    pack = configure = config = pack_configure

地点

class Place:
    """Geometry manager Place.
    Base class to use the methods place_* in every widget."""

    def place_configure(self, cnf={}, **kw):
        """Place a widget in the parent widget. Use as options:
        in=master - master relative to which the widget is placed
        in_=master - see 'in' option description
        x=amount - locate anchor of this widget at position x of master
        y=amount - locate anchor of this widget at position y of master
        relx=amount - locate anchor of this widget between 0.0 and 1.0
                      relative to width of master (1.0 is right edge)
        rely=amount - locate anchor of this widget between 0.0 and 1.0
                      relative to height of master (1.0 is bottom edge)
        anchor=NSEW (or subset) - position anchor according to given direction
        width=amount - width of this widget in pixel
        height=amount - height of this widget in pixel
        relwidth=amount - width of this widget between 0.0 and 1.0
                          relative to width of master (1.0 is the same width
                          as the master)
        relheight=amount - height of this widget between 0.0 and 1.0
                           relative to height of master (1.0 is the same
                           height as the master)
        bordermode="inside" or "outside" - whether to take border width of
                                           master widget into account
        """
        self.tk.call(
              ('place', 'configure', self._w)
              + self._options(cnf, kw))

        return self  # return the widget passed to this method

    place = configure = config = place_configure

网格

class Grid:
    """Geometry manager Grid.
    Base class to use the methods grid_* in every widget."""
    # Thanks to Masazumi Yoshikawa ([email protected])

    def grid_configure(self, cnf={}, **kw):
        """Position a widget in the parent widget in a grid. Use as options:
        column=number - use cell identified with given column (starting with 0)
        columnspan=number - this widget will span several columns
        in=master - use master to contain this widget
        in_=master - see 'in' option description
        ipadx=amount - add internal padding in x direction
        ipady=amount - add internal padding in y direction
        padx=amount - add padding in x direction
        pady=amount - add padding in y direction
        row=number - use cell identified with given row (starting with 0)
        rowspan=number - this widget will span several rows
        sticky=NSEW - if cell is larger on which sides will this
                      widget stick to the cell boundary
        """
        self.tk.call(
              ('grid', 'configure', self._w)
              + self._options(cnf, kw))

        return self  # return the widget passed to this method

    grid = configure = config = grid_configure

我的问题的关键是:任何人都可以解释 tkinter 这个“功能”背后的设计原理吗?最终,这样的更改值得拉取请求/PEP 吗?这会导致 tkinter 发生不当的重大更改吗?

这不一定是一个问题,因为它是在看到这么多关于此行为的问题后进行深入研究的结果。

python tkinter
2个回答
2
投票

谁能解释一下 tkinter 这个“功能”背后的设计原理吗?

我猜这是因为 tk 库中的底层方法不返回任何内容。在 tcl/tk 中,不可能在单个语句中创建和管理小部件,因此

pack
place
grid
没有理由返回任何内容。另外,在 tcl/tk 世界中,您可以调用
grid
pack
并传入多个小部件,因此返回单个小部件是没有意义的。

恕我直言,这绝对是 tkinter 需要改进的地方。

最终,这样的更改值得拉取请求/PEP 吗?

我个人是这么认为的。

这会导致 tkinter 发生不当的重大更改吗?

我认为这只会导致过度破坏依赖于返回函数的代码

None
。我怀疑有人故意这样做,尽管可能有一些编码不当的程序无意中依赖于这些方法返回的事实
None


0
投票

返回新对象的方法通常会被链接起来:

'aBc'.lower().center(10)
变成
'   abc    '
。从
.lower()
返回的未命名临时值将被丢弃。在Python中,运算符表达式可以隐式链接对象方法:如果a,b,c属于同一类,则
a * b + c
相当于
a.__mul__(b).__add__(c)
。或者,根据顺序和优先级,这些方法可能会被嵌套。

Python 避免变异方法链接,因为别名对象可能会导致错误。例如,之后

a = [1, 4, 2, 5, 0]
b = a.sort()

人们会期望 a 和 b 是单独的列表,分别具有原始顺序和排序顺序。在某些语言中,这是事实。这个问题的现实显然是 Guido 在最终确定 Python 之前的经验的一部分。

对于几何方法来说,这似乎不是什么问题。我很想支持这个提议。另一方面, pack 改变了小部件的放置信息,并且 `b = a.pack(...) 要么毫无意义,要么是一个错误。是否有任何/足够的理由使这些方法变得特殊?

© www.soinside.com 2019 - 2024. All rights reserved.