繁体   English   中英

Lua:类方法跳过第一个参数

[英]Lua: Class method skips first argument

我试图在Lua中实现一个应该实例化的类。 但是,在函数BatchLoader.init的输入参数发生偏移的地方出现错误。 我是否想像在python中那样将self关键字作为参数输入到任何成员函数中,或者类定义还有其他问题吗?

整个类代码看起来像这样(我去除了不重要的东西):

function BatchLoader:new()
    setmetatable({}, BatchLoader)
    self.epoch_done = false
    return self
end

function BatchLoader:init(X, y, sids, batch_size, argshuffle)    
    print("In batchloader")
    print(X:size())    -- Prints size(62000, 1) [which is 'y']
    print(y:size())    -- Prints size(62000, 1) [which is 'sids']
    print(sids)        -- Prints '10'           [which is 'batch_size']
end

但是,当我创建此类,然后调用函数BatchLoader.init ,似乎y被解释为X,y被解释为sids,依此类推。 这样, batch_size的输入将被解释为sids通过该sids ,每个参数都将从实际参数“移开”。

在进入BatchLoader.init之前,以下代码就是我所说的。 此处的所有内容均按预期进行打印。

local BatchLoader = require "../datahandler/BatchLoader.lua"
local trainLoader = BatchLoader:new()
print(X_data[{{1, 62000}, {}, {}}]:size()) -- Prints size(62000, 8, 16)
print(y_data[{{1, 62000}, {}}]:size())     -- Prints size(62000, 1)
print(sid_data[{{1, 62000}, {}}]:size())   -- Prints size(62000, 1)

local X_train, y_train, sid_train = trainLoader.init(
    X_data[{{1, a}, {}, {}}],
    y_data[{{1, a}, {}}],
    sid_data[{{1, a}, {}}],
    10, true)

我的问题是:那里的类声明有什么问题吗? 这是我在Lua中的第一个OOP代码,因此感谢您的任何想法或帮助! :)

在Lua中,此语法为:

o:f(x, y)

为此是语法糖:

o.f(self, x, y)

定义和调用均是如此。 在这里,您可以使用冒号语法定义init并使用点语法来调用它,因此它将无法正常工作,因为第一个参数将变为self ,而其他参数将相距一个。 一种解决方案是这样调用init

local X_train, y_train, sid_train = trainLoader:init(
    X_data[{{1, a}, {}, {}}],
    y_data[{{1, a}, {}}],
    sid_data[{{1, a}, {}}],
    10, true)

这解决了这个问题,但是请注意,在您的示例中,构造函数也被完全破坏了 因为您使用冒号语法定义了它,所以它将始终返回BatchLoader表本身而不是新实例。 由于它是一个类方法,因此您应该编写它并使用点语法对其进行调用:

function BatchLoader.new()
    local self = setmetatable({}, BatchLoader)
    self.epoch_done = false
    return self
end

或者简单地:

function BatchLoader.new()
    return setmetatable({epoch_done = false}, BatchLoader)
end

然后,您也可以使用点语法来调用它:

local trainLoader = BatchLoader.new()

要了解这些内容,如果您还没有完成,我强烈建议您购买最新版本的Lua编程副本,并阅读有关面向对象编程的部分。

方法语法(使用foo:bar而不是foo.bar )会自动引入一个self参数。

在函数定义中, function Foo:bar( ... )等效于function Foo.bar( self, ... ) 在函数调用时, foo:bar( ... )大致等效于foo.bar( foo, ... ) (后者对foo两次评估)。

因此,让我们剖析您的代码:

function BatchLoader:new()
    setmetatable({}, BatchLoader) -- creates a table & throws it away
    self.epoch_done = false       -- self is the hidden first argument
    return self
end

local trainLoader = BatchLoader:new()  -- i.e. BatchLoader.new( BatchLoader )

这意味着您正在有效地跑步

function BatchLoader:new()
    setmetatable({}, BatchLoader)
    BatchLoader.epoch_done = false
    return BatchLoader
end

这当然不是您想要的。 做您可能想要的几种方法是

-- fixed creation scheme
function BatchLoader.new( )
   local self = { epoch_done = false }
   return setmetatable( self, BatchLoader )
end

-- acceptable uses:
local trainLoader = BatchLoader.new( )
local trainLoader = BatchLoader:new( ) -- ignores passed self

要么

-- permit passing base object
function BatchLoader:new( )  -- equivalently: BatchLoader.new( self )
   self = self or { }  -- use passed table or create new
   self.epoch_done = false
   return setmetatable( self, BatchLoader )
end

-- acceptable uses:
local trainLoader = BatchLoader.new( )  -- creates from scratch
local trainLoader = BatchLoader.new { n = 23 } -- re-uses this table
-- WRONG uses:
local trainLoader = BatchLoader:new( )  -- reuses BatchLoader class as object

或许多其他选项。

您同样为另一个调用混合了方法符号:

function BatchLoader:init(X, y, sids, batch_size, argshuffle)

很好,相当于

function BatchLoader.init(self, X, y, sids, batch_size, argshuffle)

然后您错误地称其为

local X_train, y_train, sid_train = 
  trainLoader.init( X, y, ... )

(看看为什么一切都改变了?)

使用trainLoader:init( X, y, ... )trainLoader作为self传递。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM