Godot: GDScript 中的私有变量或函数

创建于 2018-04-25  ·  47评论  ·  资料来源: godotengine/godot

问题描述:
如果某些变量和函数不能从其他脚本获得并且对于特定脚本是本地的,那么更好的代码结构可能很重要。 也许为此引入新的关键字? 或者我错过了什么,现在可能吗?

archived discussion feature proposal gdscript

最有用的评论

我知道这已经关闭并存档(不确定是否应该为此打开另一个问题),但是访问修饰符在任何编程语言中都是一个非常重要的功能。 如果我想为 Godot 创建一个新的 Node 插件,并且我的新节点具有不应在 Node 外部修改的内部状态变量,那么没有什么可以阻止这种情况发生。 我知道您可以使用前导下划线来模仿此功能,但它仍然不会阻止访问,这是访问修饰符的全部内容。 在我看来,这是一个非常重要的问题,因为无法控制其他人与您的对象交互的方式。

所有47条评论

最接近变量的是使用setget导致函数不执行任何操作或打印警告。 但是不,没有真正的私有变量或函数。

@YeldhamDev可悲的是, setget很有帮助,但如果您不想看到公共财产 - 没有办法做到这一点。 糟糕了,

这在 Python 中也是不可能的:即使是双前导下划线也不会阻止您访问和修改变量。 在 Python 中,您使用约定代替:一个前导下划线表示一个变量是私有的,ALL_CAPS 表示某个东西是一个常量……它们仍然可以从任何地方访问,但实际上这不是问题。

@NathanLovato也许在这种情况下 GDScript 应该与 Python 不同?

@Chaosus您应该提供参数来解释为什么需要私有变量。 否则,不太可能有人会着手解决这个问题。

私有变量在这里帮助封装数据并防止与其他类耦合——它防止其他类访问这些变量。 如果您一开始就没有访问它们,那么问题也解决了。

在这两种情况下 - 使用 private 关键字或使用约定编写 - 您必须了解何时以及如何将变量设为私有,何时以及如何访问它们。 你必须学会​​设计你的类,这样你以后就可以在不破坏它们的界面的情况下更改内部结构,反之亦然。 我认为这是您在代码架构方面最大的麻烦来源。

关于 Python,它适用于数百万 Python 开发人员。 有一种机制可以使变量“私有”,以防止直接访问,这很简单:写两个前导下划线而不是一个。 但我还没有看到有人使用它。 直到最近它才在 JS 中可用。 可能还有其他类似的语言。

我并不是说它不应该出现在 GDscript 中——我真的不介意其他人是否很好地使用了该功能。 我只是不相信它有那么有用。 例如,Godot 不能在自动完成中列出带有前导 _ 或两个的变量(尽管它确实使用_function_name作为虚函数的约定)?

我只是不想在 GDScript 中看到带有智能感知的内部方法,让它更像 C# 和其他静态类型语言

是的,我同意它很难实现并且需要新的关键字,为非常小的结果付出了太多的努力
带有“__”前缀的解决方案部分解决了问题,谢谢(我从未使用过 Python,所以它对我来说是新东西)。

我知道这已经关闭并存档(不确定是否应该为此打开另一个问题),但是访问修饰符在任何编程语言中都是一个非常重要的功能。 如果我想为 Godot 创建一个新的 Node 插件,并且我的新节点具有不应在 Node 外部修改的内部状态变量,那么没有什么可以阻止这种情况发生。 我知道您可以使用前导下划线来模仿此功能,但它仍然不会阻止访问,这是访问修饰符的全部内容。 在我看来,这是一个非常重要的问题,因为无法控制其他人与您的对象交互的方式。

是的,我同意@dylmeadows,这会很有用

我也绝对是私有函数和变量的专业人士。

  1. 是的,我们确实有一个在方法名称前使用 _ 的私有约定,但对于虚函数使用完全相同的约定。 因此,如果我看到一个下划线,它可能意味着“绝对不要触摸该功能!” 或“覆盖该功能!”。 老实说,这太危险了。

  2. 如果我是单独工作或在一个非常小的团队中进行一个小项目,它不会有太大的影响,因为我知道哪些功能是要使用的,哪些功能仅供内部使用。
    但是随着团队的不断壮大,这变得越来越困难。 人们使用他们不是一直自己编写的类工作,而我因为我是一个编写很多小的内部函数来使事情工作的人,我真的希望能够阻止人们调用这些函数,因为如果他们使用那些可能导致无意行为和错误的事情,一旦犯错就需要时间来修复这些事情。 尽管有一个共同的约定,但这些事情在更大的团队中发生,因为它们毕竟可以从外部调用。

  3. 最后但并非最不重要的; 自动完成。 我是一个经常使用它来学习班级可以做什么的人。
    我只是把那个'.' 最后,看看弹出什么功能。 如果某些东西听起来有用,我就会使用它。
    如果它不会被那些无论如何都不应该被调用的函数弄得乱七八糟,那会更干净。 此外 - 再一次 - 我仍然不知道这些 _name 函数是私有的还是虚拟的。

此外,私有变量甚至可以用于个人项目。 有时有时我无法在我正在开发的游戏上工作,所以我开始忘记我的一些功能是做什么的。 或者,我忘记了我应该和不应该使用哪些。

私有变量会很棒! 它将确保不能在节点之外访问变量或函数,当我回到项目时,我可以猜测如何使用变量,而不必再次完全阅读我的所有代码。

我也赞同 Byteron 和 dylmeadows 所说的。 他们只是把他们的帖子写得足够好,并且准确地说出了我的想法。 只是想加上我的两分钱。

我将重新打开,因为有几个用户感兴趣并想讨论这个问题。 它还没有计划好,但我们可以讨论一下,看看社区是否有浓厚的兴趣。

Python 并不是最理想的语言。
有人说戈多是非常面向对象的。 每个脚本也是一个对象。 面向对象编程的主要原则之一是提供封装。 如果我想从外面保留一些东西,这可能是最好的理由。

我个人从未遇到过绝对需要阻止人们编辑变量或访问函数的情况。 任何时候我想告诉人们不要乱搞东西,除非他们知道自己在做什么,我在它的名字前加上_ (或_internal_或类似的)。

我不会反对一个关键字(或类似的),它会简单地隐藏自动完成的变量/函数。 我只是认为不需要完全阻止访问。

一方面,最好是警告,而不是禁止。 但另一方面,私有字段和方法通常会被多次使用。 长变量名(例如_internal_variable )有点烦人。
在任何情况下,关键字private都不会强迫您使用它。

类的私有成员类似于常量。 同样,我们可以将变量名写在大写字母中,并同意我们不会更改其值。 但我们不这样做,对吗? 也就是说,私有变量是普通变量和常量的交叉。 为什么不为这种情况输入一个特殊的关键字?

是的,我们确实有一个在方法名称前使用 _ 的私有约定,但对于虚函数使用完全相同的约定。 因此,如果我看到一个下划线,它可能意味着“绝对不要触摸该功能!” 或“覆盖该功能!”。 老实说,这太危险了。

这是我在这里看到的最大问题。 代替private关键字,也许我们可以有一个virtual关键字? 当您编写“func”时,一些虚拟方法已经出现在自动完成中,因此明确区分您应该覆盖的虚拟函数和不应出现在自动完成中的私有函数的关键字可能就足够了。 virtual关键字的好处是您使用它的频率低于private ,因此它的写作量​​更少。

我很高兴看到私人班级成员也包括在内。 这在其他语言中存在是有原因的。 其他消费者/团队成员(甚至你自己)不需要知道每个类是如何工作的。 事实上,他们甚至可能不应该选择随意使用无论如何应该是内部的功能。

我知道前导下划线应该“表明”这是一个私有成员,但实际上没有人关心是否以某种方式修改它来完成工作。 如果您想将其中的一些用作插件,并且每个人都可以随意更改,则这尤其痛苦。 我想完全控制我创建的任何对象/脚本的状态。 拥有可以在有人愿意的时候改变其状态的任何方面的对象使得生成其他人可以使用的代码而不是刺激性。

除此之外,整理“可用”变量/函数的列表会很棒。

我可以向开发团队提出一项建议,然后请考虑所有这些吗? 更改自动完成列表顺序。 任何不以字母或数字开头的 var 或 func 出现在自动完成列表的 __Bottom__ 处。 然后您几乎必须键入 _ 才能看到该项目…另外,如果我们可以在名称中使用其他非数学或逻辑符号会更好吗? 还没有尝试过,但是 €Display 或 ¥Print 是可接受的函数名称吗? 等等。

此外,如果我们可以在名称中使用其他非数学或逻辑符号会更好吗? 还没有尝试过,但是 €Display 或 ¥Print 是可接受的函数名称吗? 等等。

请参阅https://github.com/godotengine/godot/issues/24785。

因此,在对此进行修补后,我得出的结论是,如果您定义了一个什么都不做的 setter,即使您尝试为不同脚本中的相同变量分配一个新值并尝试打印它,原始值也将是打印。 它不是真正私密的,但我想它已经足够接近了......

这意味着没有任何提示表明似乎是公共的并且您刚刚修改的变量没有更改?
很好地调试广泛使用此方法的代码。

除了空的 setter,您还可以打印错误。

我仍然只知道,一旦我启动了程序并实际点击了那行代码,我就做了一些我不应该做的事情。 在编写代码时它仍然看起来是公共的,并且仍然需要多行代码来设置单个私有变量。
private放在该变量前面要短得多,不需要任何额外的代码行,并且会阻止我在键入时错误地访问它们。

尽管 GDScript 是一种动态语言,但对我来说它感觉很像 C++。 当我从用 C++ 编写代码切换到 GDScript 时,我想念那些访问修饰符。 话虽如此,GDScript 确实缺少对 OOP 的全面支持。

我只浏览了这个问题,但如果函数和变量的名称以下划线为前缀,那么至少能够从自动完成中隐藏函数和变量会很好。 我想这个突出的问题是确定它是否是一个虚函数,因此不管它是否应该出现

问题是下划线也用于虚函数,当然在某些情况下你也希望虚函数是公共的。

也许只对其他节点/对象隐藏下划线前缀的函数,但在 self/base 上显示它们。

我的建议是对虚拟函数使用单下划线,对“私有”函数使用双前导下划线。 这样我们就可以在不影响虚函数的情况下将它们从自动完成中隐藏起来。

使用下划线隐藏变量是不好的,因为当您更改变量的访问权限 _attribute_ 时,您必须更改其 _name_。 实际上, variable_variable是不同的名称。
这也类似于 UNIX 文件名中的一个点:一个颇有争议的决定。

这是我的意见

  • 以“__”为前缀的私有函数
  • 带有“__”的函数不会出现在自动完成中
  • “private func x()”是“func __x()”的语法糖

以上破坏了任何包含以“__”为前缀的变量的代码。 但是,除此之外,我认为该系统将是理想的。

迄今为止,GDScript 的功能与 Python/JS 非常相似,并且这两种语言都没有私有变量和函数,这是有充分理由的——这完全与它们的设计理念背道而驰。 您拥有自由,而这种自由很重要,它使编码变得容易。 你牺牲了封装,但这是他们的哲学。 没有类型检查就已经破坏了真正的封装[除非您自己检查所有类型,否则您可能不会这样做]。 所以,除非他们实现严格的类型,否则私有变量感觉是错误的。 在 OOP 的梯度中,严格类型在私有变量之前。 有许多具有严格类型但没有私有变量的语言,但我不知道任何具有私有变量且没有严格类型的语言。 这又是一个很好的理由。 除此之外,JS 甚至可以让您访问整个继承树,并让您也可以更改这些方面。 您可以通过任何包含您的对象的代码来更改对象在运行时继承的类! 当然,这不会发生,但显示了设计理念。

所以,在我看来,真正的私有变量会极大地阻碍语言。 无论如何,我认为 Python 的系统做得很好,你有 __ 可以用来访问私有变量,但它清楚地表明你在搞乱内部的东西,但它并没有有意义地限制你。 任何想要真正的 OOP 设计哲学的人都不能使用“__”,或者在他们公司或项目的编码风格中使用它。 也许将其标记为错误的选项会很好。 我的意思是一般鸭子类型和私有变量并没有真正结合在一起。 至少你完全搞砸了命名空间,因为现在如果 "hi" 是私有的, obj.set("hi", 5) 不起作用? 但是如果“hi”不存在,它确实有效吗? 这没有多大意义......所以,无论你做什么,都强烈反对强制私有完全无法访问,这是我的投票。 对于私有变量以 Python 当前的方式存在是非常强烈的。 Tbh 我仍然不确定如何解决私有变量的鸭子类型问题,即使希望拥有真正且无法访问的私有变量。 我猜你只是阻止了 obj.set 并让它抛出错误。 现在 obj.set 似乎需要返回一个布尔值,这很奇怪。 is_private 电话? 每次使用 obj.set 之前都必须调用? 身份证

[天哪,我们真的可以进行实际的错误检测吗,我们正在谈论私有变量,但截至目前,如果您在 gdscript 中有错误,游戏将默默地忽略它(facepalm)。 也许我做错了,但如果我的代码做了一些非法的事情,gdscript 似乎只是从函数中返回 null,这使得追踪变得非常困难,JS 曾经那么糟糕,JS 是一门语言。 我知道让游戏崩溃可能太多了,但我一直不得不通过放置打印语句来对我的代码库进行二进制搜索,直到我找到两个连续的打印语句,前者打印而后者不打印,只是为了找出代码在哪里损坏。 在这个意义上,JS/Python 出奇地严格得多,尽管它们在其他方面是多么自由。]

我建议找到一个一致的项目组织来最小化问题。 您可以使用场景的根节点作为接口从外部控制场景,使用子脚本作为后端。

或者,您可以只使用方法、导出变量和信号,而不要从外部接触简单的变量。 这是一个简单的约定,GDScript 可以保持其简单性。

这在 Python 中也是不可能的:即使是双前导下划线也不会阻止您访问和修改变量。 在 Python 中,您使用约定代替:一个前导下划线表示一个变量是私有的,ALL_CAPS 表示某个东西是一个常量……它们仍然可以从任何地方访问,但实际上这不是问题。

我只想说,在 Python 中可以有 _private_ 属性。

报价(https://www.python.org/dev/peps/pep-0008/):

__double_leading_underscore:在命名类属性时,调用名称修改(在类 FooBar 中,__boo 变为 _FooBar__boo;见下文)。

__double_leading_and_trailing_underscore__:存在于用户控制的命名空间中的“神奇”对象或属性。 例如 __init__、__import__ 或 __file__。 永远不要发明这样的名字; 仅按照文档使用它们

如果您单击该链接并按 CTRL+F“私有”,您将得到

我们在这里不使用术语“私有”,因为在 Python 中没有真正私有的属性(通常没有不必要的工作量)。

双下划线或单下划线变量的作用就像普通变量一样,这只是一种引用约定,它们不应该被使用,并且在更新库时可能会改变,因为它们是内部的。 通常,由于像 GDScript 这样的 Pythonic 语言将对象视为只是字典,因此尝试强制私有变量并让它们使用命名空间会很尴尬。

如果您单击该链接并按 CTRL+F“私有”,您将得到

我们在这里不使用术语“私有”,因为在 Python 中没有真正私有的属性(通常没有不必要的工作量)。

双下划线或单下划线变量的作用就像普通变量一样,这只是一种引用约定,它们不应该被使用,并且在更新库时可能会改变,因为它们是内部的。 通常,由于像 GDScript 这样的 Pythonic 语言将对象视为只是字典,因此尝试强制私有变量并让它们使用命名空间会很尴尬。

我同意,他们不称其为 _private_ 属性。 但是,让我描述一下它是如何工作的:

# defining class Employee
class Employee:
    def __init__(self, name, salary):
        self.name = name
        self.__salary = salary
>>> emp = Employee("Bill", 10000)
>>> emp.__salary
# AttributeError: 'employee' object has no attribute '__salary'

所以它不被称为 _private_ 属性,但它的行为几乎与它相似。
在 GDScript 中拥有一个几乎私有的属性会很棒,因为它存在于 Python 中。

哦,是的,我非常同意你的看法。 Python 只是为您提供了使用 ._Employee__salary 的语法糖。 我个人不喜欢 python 的方式,我认为它可以在 Godot 中得到很大的改进,正如我在评论中提到的,

class Employee:
      var name # normal
      private var salary # Syntactic sugar for var _salary

这更干净,因为 _Employee__salary 是一种隐藏变量名的丑陋方式,并且拥有一个 private 关键字使它就像普通的 OOP 一样。 更好的是,这阻止了拥有公共变量salary 和私有变量_salary 的能力,这会很丑陋,并且应该像在Java 中一样出现语法错误。 这是因为两者都会被声明为“varsalary”和“private varsalary”,存在明显的冲突。 另一种思考方式是“为了使用成员 m 访问某个其他类 C 的私有变量,您必须像在 C._m 中一样使用下划线”。 然后,我们可以将以下划线开头的变量声明为错误,即使私有成为声明它的唯一方法,以便清楚正在做什么。

我认为 python 出现不太理想的情况的唯一原因是因为变量的顶部没有声明,您只需在任何函数体中组成类变量。 GDScript 似乎需要在类主体中进行声明,这使它很容易转入类似于 Java 的私有声明。

我不喜欢将关键字用作语法糖,除非它们可以节省大量输入。 在这里,输入private实际上会让你写更多的字符,这使它成为一个反捷径:slightly_smiling_face:

另外,方法呢? 几个虚方法以下划线开头,因此我们不能使用单个下划线将它们标记为私有。 不过,我们可以使用两个下划线,这会以更长的时间为代价来避免冲突。 我也喜欢在有意义的时候遵循 Python 约定的想法——“dunder”在该语言中已经流行了一段时间。

我不认为其意图是将其视为快捷方式,而是在类之外使用“_”来访问私有变量。 语法糖将是它的实现方式。 本质上与 python 的工作方式相同。 但就像是的,这是真的,在 python 的情况下,它的语法糖节省了大量的输入,但这只是因为它别名为愚蠢的长。 使用更短的别名会更好,所以使用更短的别名然后选择不使用语法糖,因为别名太短,归结为我们是否应该支持私有变量; 我们不必这样做,我们可以让用户在变量前加上下划线或选择他们自己的约定。 它仅适用于具有 Java 和 C++ 头脑的人,他们宁愿编写“private var myvariable”而不是将“_myvariable”作为约定的私有,这在来自 OOP 世界时感觉很奇怪,即使他们都完成了确切的一样。 双下划线会很好地匹配 Python 的语法,所以我也支持那个,特别是如果 _ 与其他东西冲突

我宁愿有一个关键字,它明确定义了可能被误解为仅样式约定之外的行为。 private得到我的投票。

引发讨论:“私有”成员的 Python 样式约定是在名称前添加下划线,这是 gdscript _已经_在常见事件方法(如_ready()_input用于不同目的的_physics_process ,仅举几例。 那些应该是私人的吗? 添加私有关键字将如何与这些方法交互? 其他关键字如protected也需要实现?

在任何情况下,我都是为了强制执行限制性指令 _by design_ 而不仅仅是让用户定义约定。 但鉴于实现的复杂性,我不太确定私有类成员是否会提供预期的改进。 我想,整个 API 也必须重新审视。 整个语言将有一个完全不同的范式。

是的,已经有人注意到了。 (见 Calinou 的回应)双下划线将是要走的路。 也和 Python 一样。

我的2c。 在 Python 中,没有什么可以阻止任何人访问以_开头的类成员,并且具有__一些内部知识。

一切都是为了表达意图。 哲学是我们都是成年人,我们可以决定是否真的需要访问所谓的私有变量或函数。 如果我们这样做,我们将独自应对后果。

@sanchopanca

  1. GDScript 不是 Python。
  2. 按照您的逻辑,也不需要常量(var CONSTANT = 1)。
  3. 不是每个人都喜欢使用__

我支持private关键字,它甚至不会破坏兼容性。
相反,通过使用_funcvar设为私有,会因为其他原因而改变一些使用它的情况(我只在函数的参数中使用_ )。

它让我想起了新的静态类型功能,而这个私有和虚拟功能也会以同样的方式运行。
它将提供更清晰的代码库、更好的错误检测、更好的自动完成以及代码的自动文档化。
如果有人阅读你的代码,他们会更好地理解它的作用。

我想知道为开发团队实施两个新关键字会有多困难。
它肯定比打字系统容易得多,并且会提供很多价值。
如果开发团队的某个人可以指导我该怎么做,老实说,我很乐意提供帮助!

只是为添加私有和受保护的关键字再投一票。
如果您曾经编写过其他开发人员将要使用的代码,那么您不能反对。
所有反对添加关键字的可以检查这个主题:
https://softwareengineering.stackexchange.com/questions/143736/why-do-we-need-private-variables

我们仍将使用 GDscript,但为什么不在此过程中改进它。

_, __, ___ 等等都是愚蠢的,就像在变量名上添加前缀来建议类型一样
intAge、strName、bIsAlive……所有这些都只显示缺少的语言功能。
因此,即使不将 GDScript 与 Python 或其他语言进行比较,开发人员也可以进行民意调查,看看大多数人想要还是不想要这两个关键字;)

如果功能实现,希望选择C++方式。 每个声明前面的“private”或“public”关键字使 C# 阅读起来很麻烦。

我个人不喜欢 C++ 方式,因为我们没有 C++ 类型语法,默认情况下一切都是公开的。 我认为能够在不添加另一行或将其移动到新行的情况下将变量设置为 private 比看不到 private 关键字更重要。

private var foo : String = "foobar"也更符合现有的exportonready关键字的用法。

关闭支持https://github.com/godotengine/godot-proposals/issues/641 ,因为现在在 Godot 提案存储库中跟踪功能提案。

此页面是否有帮助?
0 / 5 - 0 等级