对于从静态语言(java/c#)转向动态语言(如 python)的人来说,最重要的问题

发布于 2024-09-19 06:07:47 字数 122 浏览 2 评论 0 原文

对于从静态语言(java/c#)转向 Python 等动态语言的人来说,最重要的问题是什么?

事情的完成方式似乎很酷,但重命名方法或添加/删除参数似乎很危险!

是为每种方法编写测试的唯一解决方案吗?

What are the top gotchas for someone moving from a static lang (java/c#) to dynamic language like python?

It seems cool how things can be done, but renaming a method, or adding/removing parameters seems so risky!

Is the only solution to write tests for each method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赠意 2024-09-26 06:07:50

第一次尝试 Python(主要来自 Java 背景)时,一些让我印象深刻的事情:

  1. 编写Pythonic代码。使用 Python 推荐的习惯用法,而不是使用旧的 Java/C 方式。这不仅仅是一个表面或教条的问题。实际上,Python 代码实际上始终比类 C 代码快得多。事实上,恕我直言,很多“Python 很慢”的说法是由于缺乏经验的程序员尝试用 Python 编写 Java/C 代码,最终导致性能受到很大影响,并认为 Python 很慢。慢得可怕。尽可能使用列表推导式和map/filter/reduce。

  2. 接受函数是真正的对象这一想法。将它们作为回调传递,使函数返回函数,了解闭包等。

  3. 您可以在 Python 中做很多很酷且几乎神奇的事情,例如您提到的重命名方法。这些东西非常适合展示 Python 的功能,但如果您不需要它们,则实际上没有必要。事实上,正如 S. Lott 指出的那样,最好避免看起来有风险的事情。

Some things that struck me when first trying out Python (coming from a mainly Java background):

  1. Write Pythonic code. Use idioms recommended for Python, rather than doing it the old Java/C way. This is more than just a cosmetic or dogmatic issue. Pythonic code is actually hugely faster in practice than C-like code practically all the time. As a matter of fact, IMHO a lot of the "Python is slow" notion floating around is due to the fact that inexperienced coders tried to code Java/C in Python and ended up taking a big performance hit and got the idea that Python is horribly slow. Use list comprehensions and map/filter/reduce whenever possible.

  2. Get comfortable with the idea that functions are truly objects. Pass them around as callbacks, make functions return functions, learn about closures etc.

  3. There are a lot of cool and almost magical stuff you can do in Python like renaming methods as you mention. These things are great to show off Python's features, but really not necessary if you don't need them. Indeed, as S. Lott pointed out, its better to avoid things that seem risky.

晨与橙与城 2024-09-26 06:07:49

“是为每种方法编写测试的唯一解决方案吗?”

您是说您没有为 Java 中的每个方法编写测试吗?

如果您用 Java 为每个方法编写测试,那么——嗯——什么都不会改变,不是吗?

重命名一个方法,看起来风险很大!

正确的。不要这样做。

添加/删除参数似乎很危险!

什么?你是在谈论可选参数吗?如果是这样,那么在 Java 中拥有多个重载名称似乎是危险且令人困惑的。有可选参数似乎更简单。


如果你在 SO 上搜索最常见的 Python 问题,你会发现有些问题是长期存在的问题。

  • 如何更新PYTHONPATH

  • 为什么某些随机浮点计算与数学抽象可能表明的不同。

  • 使用 Python 3 并从 Python 2 教程中键入代码。

  • 为什么 Python 没有超级复杂的 protectedprivatepublic 声明。

  • 为什么 Python 没有枚举类型。

第一个长期问题似乎是使用可变对象作为函数的默认值。只需避免这种情况即可。

"Is the only solution to write tests for each method?"

Are you saying you didn't write tests for each method in Java?

If you wrote tests for each method in Java, then -- well -- nothing changes, does it?

renaming a method, seems so risky!

Correct. Don't do it.

adding/removing parameters seems so risky!

What? Are you talking about optional parameters? If so, then having multiple overloaded names in Java seems risky and confusing. Having optional parameters seems simpler.


If you search on SO for the most common Python questions, you'll find that some things are chronic questions.

  • How to update the PYTHONPATH.

  • Why some random floating-point calculation isn't the same as a mathematical abstraction might indicate.

  • Using Python 3 and typing code from a Python 2 tutorial.

  • Why Python doesn't have super-complex protected, private and public declarations.

  • Why Python doesn't have an enum type.

The #1 chronic problem seems to be using mutable objects as default values for a function. Simply avoid this.

猫九 2024-09-26 06:07:49

我想说,第一个陷阱是尝试用动态语言编写静态类型代码。

毫不犹豫地使用标识符来指向字符串,然后在独立的代码部分中使用列表,

keys = 'foo bar foobar' # Imagine this coming in as an argument
keys = keys.split() # Now the semantically chose name for the argument can be 
                    # reused As the semantically chosen name for a local variable

毫不犹豫地将函数视为常规值:它们确实如此。采用以下解析器。假设我们想像对待所有 header 标签一样对待所有 ul 标签,就像对待 ol 标签一样。

class Parser(HTMLParser):
    def __init__(self, html):
        self.feed(html)

    def handle_starttag(self, tag, attrs):
        parse_method = 'parse_' + tag    
        if hasattr(self, parse_method):  
            getattr(self, parse_method)(attrs)


    def parse_list(self, attrs):
        # generic code

    def parse_header(self, attrs):
       # more generic code

    parse_h1 = parse_h2 = parse_h3 = parse_h4 = parse_h5 = parse_h6 = parse_header
    parse_ol = parse_ul = parse_list

这可以通过在 java 等语言的 handle_starttag 方法中使用不太通用的代码来完成,方法是跟踪哪些标记映射到相同的方法,但是如果您决定要处理 div 标记,您可以必须将其添加到调度逻辑中。在这里,您只需添加方法 parse_div 就可以了。

不要进行类型检查!鸭子类型!

def funtion(arg):
    if hasattr(arg, 'attr1') and hasattr(arg, 'attr2'):
         foo(arg):
    else:
         raise TypeError("arg must have 'attr1' and 'attr2'")

isinstance(arg, Foo) 相反。这使您可以传入任何具有 attr1attr2 的对象。例如,这允许您传入包裹在对象周围的跟踪类以进行调试。在 Java 中,您必须修改该类才能执行此操作。

正如 THC4k 所指出的,另一种(更Pythonic)的方法是 EAPF 习语。
我不喜欢这样,因为我喜欢尽早发现错误。如果您希望代码很少失败,那么效率会更高。不要告诉任何人我不喜欢它,尽管他们不会认为我知道如何编写Python。这是 THC4k 提供的示例。

try: 
    foo(arg): 
except (AttributeError, TypeError): 
    raise InvalidArgumentError(foo, arg)

我们是否应该捕获 AttributeError 和 TypeError 还是让它们传播到知道如何处理它们的地方,这是一个难以抉择的问题,但这只是一个例子,所以我们'会让它飞翔。

I would say that the number one gotcha is trying to write statically typed code in a dynamic language.

Dont hesitate to use an identifier to point to a string and then a list in self-contained sections of code

keys = 'foo bar foobar' # Imagine this coming in as an argument
keys = keys.split() # Now the semantically chose name for the argument can be 
                    # reused As the semantically chosen name for a local variable

don't hesitate to treat functions like regular values: they are. Take the following parser. Suppose that we want to treat all header tags alike and ul tags like ol tags.

class Parser(HTMLParser):
    def __init__(self, html):
        self.feed(html)

    def handle_starttag(self, tag, attrs):
        parse_method = 'parse_' + tag    
        if hasattr(self, parse_method):  
            getattr(self, parse_method)(attrs)


    def parse_list(self, attrs):
        # generic code

    def parse_header(self, attrs):
       # more generic code

    parse_h1 = parse_h2 = parse_h3 = parse_h4 = parse_h5 = parse_h6 = parse_header
    parse_ol = parse_ul = parse_list

This could be done by using less generic code in the handle_starttag method in a language like java by keeping track of which tags map to the same method but then if you decide that you want to handle div tags, you have to add that into the dispatching logic. Here you just add the method parse_div and you are good to go.

Don't typecheck! Duck-type!

def funtion(arg):
    if hasattr(arg, 'attr1') and hasattr(arg, 'attr2'):
         foo(arg):
    else:
         raise TypeError("arg must have 'attr1' and 'attr2'")

as opposed to isinstance(arg, Foo). This lets you pass in any object with attr1 and attr2. This allows you to for instance pass in a tracing class wrapped around an object for debugging purposes. You would have to modify the class to do that in Java AFAIK.

As pointed out by THC4k, another (more pythonic) way to do this is the EAPF idiom.
I don't like this because I like to catch errors as early as possible. It is more efficient if you expect for the code to rarely fail though. Don't tell anybody I don't like it though our they'll stop thinking that I know how to write python. Here's an example courtesy of THC4k.

try: 
    foo(arg): 
except (AttributeError, TypeError): 
    raise InvalidArgumentError(foo, arg)

It's a tossup as to if we should be catching the AttributeError and TypeError or just let them propagate to somewhere that knows how to handle them but this is just an example so we'll let it fly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文