【问题标题】:As a Java programmer learning Python, what should I look out for? [closed]作为一名学习 Python 的 Java 程序员,我应该注意什么? [关闭]
【发布时间】:2011-01-21 07:33:20
【问题描述】:

我的大部分编程背景都在 Java 中,而且我仍然在使用 Java 进行大部分编程。但是,我开始为一些工作中的副项目学习 Python,我想尽可能独立于我的 Java 背景来学习它——即我不想只用 Python 编写 Java。我应该注意哪些事项?

一个简单的示例 - 在查看 Python 教程时,我发现函数(例如列表)的默认可变参数是持久化的(从调用到调用都会记住)。作为一名 Java 程序员,这对我来说是违反直觉的,而且我很难理解。 (如果您不理解该示例,请参阅 herehere。)

有人还向我提供了this 列表,我觉得这很有帮助,但很简短。任何人都有任何其他关于 Java 程序员可能倾向于滥用 Python 的例子......?还是 Java 程序员会错误地假设或难以理解的事情?

编辑:好的,简要概述我链接到的文章中提到的原因,以防止答案重复(如 Bill the Lizard 所建议)。 (如果我在措辞上有错误,请告诉我,我只是刚刚开始使用 Python,所以我可能无法完全理解所有概念。并且免责声明 - 这些将是 非常简短,所以如果你不明白它的内容,请查看链接。)

  • Java 中的静态方法不会转换为 Python 类方法
  • Java 中的 switch 语句转换为 Python 中的哈希表
  • 不要使用 XML
  • getter 和 setter 是邪恶的(嘿,我只是在引用 :))
  • 代码重复在 Java 中通常是一种必要的弊端(例如方法重载),但在 Python 中则不然

(如果您觉得这个问题很有趣,请查看链接。:) 非常好。)

【问题讨论】:

  • 好问题。您在上一段中链接到的文章是一个非常好的开始。您可能会考虑提取那里给出的要点的(非常简短的)摘要,这样人们就不会在答案中重复相同的列表。 (我几乎贴出了文章中的一个观点。)
  • @Bill the Lizard - 已更新,感谢您的建议。只是出于好奇-您要发布哪一点? :)
  • 另外,请将其设为社区 Wiki。没有“答案”,只有很多建议。
  • 我打算发布“Getter 和 setter 是邪恶的”。在这一点上,两种语言之间存在着昼夜差异。它们可能是发现正在使用 Python 编写 Java 的人的最简单方法。

标签: java python


【解决方案1】:

我能想到的最大的一个是不理解或没有充分利用鸭子打字。在 Java 中,您需要预先指定非常明确和详细的类型信息。在 Python 中,类型既是动态的,也是隐含的。哲学是你应该在比名义类型更高的层次上考虑你的程序。例如,在 Python 中,您不使用继承来模拟可替代性。默认情况下,可替代性是鸭子类型的结果。继承只是程序员重用实现的一种便利。

类似地,Pythonic 的成语是“请求原谅,不要请求许可”。显式类型被认为是邪恶的。不要预先检查参数是否某种类型。只需尝试对参数做任何你需要做的事情。如果它不符合正确的接口,它会抛出一个非常明显的异常,您将能够很快找到问题。如果有人传递了一个名义上意外但具有与您预期相同的接口的类型的参数,那么您就获得了免费的灵活性。

【讨论】:

  • 哇。我不认为我理解很多第一段。我想我会用谷歌搜索其中一些术语并研究 Python 是如何使用它们的 :) 谢谢
  • 好的 - 我正在研究,我发现它正在将我推向与 Ryan 的第三点相似的方向。对于有一定 Python 基础的人来说,这可能是一个非常简单的问题——但多态性在 Python 中扮演什么角色?
  • Python 具有无限多态性。只要给定对象具有必需的字段或方法,在运行时,在该代码行,代码就会运行。换句话说,该对象甚至不需要预先声明该字段或方法,但如果您愿意,可以稍后将其添加到该对象中。多态性不依赖于继承,因为鸭子类型完全绕过了编译时要求。
  • 我想我是一个明确的人。编译和祈祷不是我的风格。 Python 只是以懒惰的名义倒退了一大步。
【解决方案2】:
  • 不要把所有东西都放在类中。 Python 的内置列表和字典将带您走得更远。
  • 不必担心每个模块只保留一个类。按用途而非类别划分模块。
  • 对行为使用继承,而不是接口。不要为“Dog”和“Cat”创建一个“Animal”类来继承,这样你就可以拥有一个通用的“make_sound”方法。

这样做:

class Dog(object):
    def make_sound(self):
        return "woof!"

class Cat(object):
    def make_sound(self):
        return "meow!"

class LolCat(object):
    def make_sound(self):
        return "i can has cheezburger?"

【讨论】:

  • 我知道我可能遗漏了一些简单的东西......但你能解释一下你最后一点背后的“为什么”吗?
  • @froadie:并不是说拥有 Animal 类不好,只是完全没有必要,除非你想提供 make_sound() 的默认实现。
  • Python 使用“鸭子类型”的概念(或者在这种情况下是狗/猫类型:)。如果您将对象传递给期望它具有某个接口的方法,那么只要它具有该接口就可以了。继承有很多问题,因为耦合极其紧密,所以只有在你真正需要的时候才使用它。
  • @froadie:多态性隐含在动态语言中。继承恰好是告诉静态编译器类型相关的最简单方法。使用动态语言和廉价的例外(大部分)是不必要的。
  • @froadie:你在 Python 中学到的任何东西都不能“反弹”回 Java。它们是不同的语言。这不仅仅是不同的语法。基本概念不同。 Java 的静态声明特性使其与 Python 真正不同。
【解决方案3】:

在 Java 中您可能已经习惯了在 Python 中找不到的一件事,那就是严格的隐私。这与其说是需要寻找的东西,不如说是需要寻找的东西(当我刚开始时,我为寻找一个相当于“私人”的 Python 花了多长时间而感到尴尬!)。相反,Python 比 Java 更透明,更容易自省。这属于有时被描述为“我们在这里都是同意的成年人”的哲学。有一些约定和语言机制可以帮助防止意外使用“非公开”方法等,但 Python 中几乎不存在信息隐藏的整个思维方式。

【讨论】:

  • 所以基本上,在我看来,在将 Java 与 Python 进行比较时,一个反复出现的主题是 Python 更信任你——它给你更多的权力,但也有更大的把事情搞砸的能力.
  • 在搜索方面同上。头几天我花了很大一部分时间寻找私人等价物。
  • Python 的流行语是“我们都是成年人”。 Python 作为源代码分发。当您可以阅读源代码时,“私人”是什么意思?如有必要,您只需编辑源即可更改内容。
  • 我实际上认为如果您不了解约定,这种哲学是有害的。我说约定是因为语言支持的方式很少,所以你必须四处搜索。我见过很多 python 代码,其中所有内容都是公开的,因此,不知道要调用哪些方法以及可以安全更改哪些属性。单下划线约定 (self._blah_method()) 是更好的选择。它不强制隐私,但它确实说“除非你知道你在做什么,否则你不应该调用它”。第二个选项是双下划线。
  • ...我也认为“我们都是成年人”这句话是一把双刃剑。是的,它使挖掘和查找/修改现有代码变得更容易,但缺点是它会产生噪音。如果我下载了一个包并想使用它,我会看到许多(无效的)选项,除非包作者遵循可选的约定。在其他语言中,与我无关的部分被封装。我只看到班级的公开表面。并不是说 python 做不同的事情很糟糕,只是说它是一个带有缺点的选择。
【解决方案4】:

从 Java POV 来看,最重要的是,不为所有内容都创建类是完全可以的。在许多情况下,程序方法更简单、更短。

下一个最重要的事情是,您必须克服对象的类型控制它可以做什么的观念;相反,代码控制了哪些对象必须能够在运行时支持(这是由于鸭子类型)。

哦,尽可能使用原生列表和字典(不是自定义的后代)。

【讨论】:

    【解决方案5】:

    Python 中处理异常的方式不同于 它们在 Java 中的处理方式。在 Java 中,建议 是仅在异常情况下使用异常这不是 Python也是如此。

    在 Python 中,像 Iterator 这样的东西利用异常机制来表示没有更多的项目。但是这样的设计在 Java 中不被认为是好的做法。

    正如 Alex Martelli 在他的书中所说的那样 Python in a Nutshell 其他语言的异常机制(适用于Java) 是 LBYL(在你跳跃之前先看看): 是在尝试操作之前预先检查所有可能使操作无效的情况。

    与 Python 一样,方法是 EAFP(请求宽恕比许可更容易)

    【讨论】:

      【解决方案6】:

      “不要对所有事情都使用类”的推论:回调。

      进行回调的 Java 方式依赖于传递实现回调接口的对象(例如 ActionListener 及其 actionPerformed() 方法)。在 Python 中不需要这种东西,你可以直接传递方法甚至本地定义的函数:

      def handler():
         print("click!")
      button.onclick(handler)
      

      甚至是 lambda:

      button.onclick(lambda: print("click!\n")) 
      

      【讨论】:

      • -1 - 糟糕的 lambda 示例。 lambda 旨在包含单个 表达式,而不是语句,并返回该表达式的值。您的 lambda 示例虽然有效,但实际上是返回通过调用 print 返回的值(我相信这是 None)。如果你有一个需要打印 2 条语句的 lambda,你会告诉新手写lambda: print("first line") or print("second line")吗?
      【解决方案7】:

      引用的文章有一些很好的建议,很容易被错误引用和误解。还有一些不好的建议。

      留下 Java。重新开始。 “不要相信你的 [基于 Java] 的直觉”。说事情是“违反直觉的”在任何编程学科中都是一个坏习惯。学习一门新语言时,要从头开始,放弃你的习惯。你的直觉一定是错误的。

      语言是不同的。否则,它们将是具有不同语法的相同语言,并且会有简单的翻译器。因为没有简单的翻译器,所以没有简单的映射。这意味着直觉既无用又危险。

      • “Java 中的静态方法不会转换为 Python 类方法。”这种事情真的是有限和无益的。 Python 有一个 staticmethod 装饰器。它还有一个classmethod 装饰器,Java 没有与之对应的装饰器。

        顺便说一句,这一点还包括关于不要将所有内容不必要地包装在一个类中的更有帮助的建议。 “Java 静态方法的惯用翻译通常是模块级函数”。

      • Java 中的switch 语句可以通过多种方式实现。首先,最重要的是,它通常是一个if elif elif elif 构造。这篇文章在这方面没有帮助。如果您绝对确定这太慢(并且可以证明这一点),您可以使用 Python 字典作为从值到代码块的稍快的映射。盲目地将 switch 翻译成字典(不加思索)是非常糟糕的建议。

      • 不要使用 XML。脱离上下文时没有意义。在上下文中,这意味着不要依赖 XML 来增加灵活性。 Java 依赖于用 XML 描述东西;例如,WSDL 文件会重复检查代码时显而易见的信息。 Python 依赖于自省,而不是在 XML 中重述所有内容。

        但是 Python 具有出色的 XML 处理库。几个。

      • Getter 和 setter 在 Python 中不是必需的,它们在 Java 中是必需的。首先,您在 Python 中有更好的自省,因此您不需要 getter 和 setter 来帮助创建动态 bean 对象。 (为此,您使用collections.namedtuple)。

        但是,您有 property 装饰器,它将 getter(和 setter)捆绑到类似属性的构造中。关键是 Python 更喜欢裸属性。必要时,我们可以将 getter 和 setter 捆绑在一起,使其看起来好像有一个简单的属性。

        此外,如果属性不够复杂,Python 也有描述符类。

      • 代码重复在 Java 中通常是一种必要的弊端(例如方法重载),但在 Python 中则不然。正确的。 Python 使用可选参数而不是方法重载。

        要点继续谈到关闭;这不如明智地使用默认参数值的简单建议有用。

      【讨论】:

      • 虽然不同意这里的一些项目,但关于“namedtuple”的提示非常有帮助,你赢得了投票。
      • @S.Lott 我想重新开始,但我真的不想通过学习什么是字符串、int 等东西。你对书籍有什么建议吗?还是适合那些刚开始学习 Python,但已经有编程经验的人的网站?
      猜你喜欢
      • 2010-10-10
      • 2020-03-26
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      • 2016-02-13
      相关资源
      最近更新 更多