我正在尝试在Lua中实现一个应该被实例化的类。但是,我收到一个错误,其中函数BatchLoader.init
的输入参数被移位。我是否缺少将self
关键字作为参数输入到任何成员函数(如python),或者类定义是否还有其他错误?
整个类代码看起来像这样(我删除了不重要的东西):
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
,每个参数都与实际参数“移开”。
以下代码是我在进入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代码,所以任何想法或帮助都表示赞赏! :)
答案 0 :(得分:4)
在Lua中,这种语法:
data AppM a = AppM {unwrapAppM :: ReaderT Env (LoggingT IO) a}
instance Functor AppM where
fmap fn appm = AppM $ fmap fn (unwrapAppM appm)
instance Applicative AppM where
pure a = AppM $ pure a
是这个的语法糖:
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
要了解这些内容,如果您尚未完成,我强烈建议您购买最新版本的Lua编程副本,并阅读面向对象编程一节。
答案 1 :(得分:3)
方法语法(使用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
传递。