[英]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.