在Python中使用静态方法 - 最佳实践 [英] Using static methods in python - best practice

查看:143
本文介绍了在Python中使用静态方法 - 最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

静态方法何时以及如何在python中使用?我们已经建立了使用类方法作为工厂方法来创建对象的实例,应尽可能避免。换句话说,最好的做法是使用类方法作为替代构造函数(参见 python对象的工厂方法 - 最佳做法)。



假设我有一个类用于表示数据库中的一些实体数据。想象一下,数据是一个包含字段名和字段值的 dict 对象,其中一个字段是使数据唯一的ID号。

  class Entity(object):
def __init __(self,data,db_connection):
self._data = data
self。 _db_connection

这里,我的 __ init __ data dict 对象。假设我只有一个ID号,我想创建一个 Entity 实例。首先我需要找到其余的数据,然后创建一个我的 Entity 对象的实例。从上一个问题,我们确定使用类方法作为工厂方法应该尽可能避免。

  class Entity对象):

@classmethod
def from_id(cls,id_number,db_connection):
filters = [['id','is',id_number]]
data = db_connection.find(filters)
return cls(data,db_connection)

def __init __(self,data,db_connection):
self._data = data
self._db_connection


#创建实体
entity = Entity.from_id(id_number,db_connection)

上面是一个例子,什么不要做,或至少如果有一个替代品什么不做。现在我想知道是否编辑我的类方法,使它更多的是一个实用的方法,而少一个工厂方法是一个有效的解决方案。换句话说,以下示例是否符合使用静态方法的最佳实践。

  class Entity(object):

@staticmethod
def data_from_id(id_number,db_connection):
filters = [['id','is',id_number]]
data = db_connection.find )
返回数据


#创建实体
data = Entity.data_from_id(id_number,db_connection)
entity = Entity(data)

或者使用独立函数从ID号查找实体数据更有意义。

  def find_data_from_id(id_number,db_connection):
filters = [['id','is',id_number]]
data = db_connection.find(filters)
返回数据


#创建实体。
data = find_data_from_id(id_number,db_connection)
entity = Entity(data,db_connection)

注意:我不想更改我的 __ init __ 方法。以前人们建议让我的 __ init __ 方法看起来像这样 __ init __(self,data = None,id_number = None)但是可以有101种不同的方式来找到实体数据,所以我宁愿保持这种逻辑在一定程度上分开。有意义吗?

解决方案


静态方法何时以及如何在python中使用? p>

glib的答案是:不是很经常。



非常无用的答案是:当他们使你的代码更可读时。






首先,绕行到文档


Python中的静态方法类似于Java或C ++中的方法。另请参阅 classmethod(),用于创建备用类构造函数的变体。


所以,当你在C ++中需要一个静态方法时,你需要在Python中使用一个静态方法。



好吧,



在Java中,没有函数,只有方法,所以你最终创建的伪类只是静态方法的束。在Python中做同样的事情的方法是只使用自由函数。



这很明显。然而,它是好的Java风格看起来尽可能硬的一个合适的类楔入一个函数,所以你可以避免写这些伪类,而做同样的事情是坏的Python风格 - 再次,使用自由函数,而这



C ++与Java没有相同的限制,但许多C ++风格都是非常相似的。 (另一方面,如果你是一个现代C ++程序员谁内部化的自由函数是类的接口的一部分成语,你的直觉静态方法有用可能是相当不错的Python) / p>




但是如果你是从第一个原则来,而不是从另一种语言来,这里有一个更简单的方法来看事情:



A @staticmethod 基本上只是一个全局函数。如果你有一个函数 foo_module.bar(),如果它被拼写为 foo_module.BazClass.bar(),使它成为 @staticmethod 。如果没有,不要。这真的是所有的。唯一的问题是建立自己的本能,为一个惯用的Python程序员提供更多的可读性。



当然使用 @classmethod 当你需要访问类,但不是instance-alternate构造函数是范例的情况下,如docs暗示。虽然你经常可以通过明确引用一个 @staticmethod 来模拟一个 @classmethod class






最后,找到你的特定类别问题:



如果客户端需要通过ID来查找数据的唯一原因是构造一个 Entity 听起来像一个实现细节,你不应该暴露,它也使客户端代码更复杂。只需使用构造函数。如果你不想修改你的 __ init __ (你是对的,有很好的理由,你可能不想),使用 @ classmethod 作为替代构造函数: Entity.from_id(id_number,db_connection)



另一方面,如果该查找对于在与其他情况下与 Entity 构造无关的客户端固有地是有用的,则看起来这与该无关 Entity 类(或至少不超过同一模块中的任何其他类)。所以,只是让它是一个自由功能。


When and how are static methods suppose to be used in python? We have already established using a class method as factory method to create an instance of an object should be avoided when possible. In other words, it is not best practice to use class methods as an alternate constructor (See Factory method for python object - best practice).

Lets say I have a class used to represent some entity data in a database. Imagine the data is a dict object containing field names and field values and one of the fields is an ID number that makes the data unique.

class Entity(object):
    def __init__(self, data, db_connection):
        self._data = data
        self._db_connection

Here my __init__ method takes the entity data dict object. Lets say I only have an ID number and I want to create an Entity instance. First I will need to find the rest of the data, then create an instance of my Entity object. From my previous question, we established that using a class method as a factory method should probably be avoided when possible.

class Entity(object):

    @classmethod
    def from_id(cls, id_number, db_connection):
        filters = [['id', 'is', id_number]]
        data = db_connection.find(filters)
        return cls(data, db_connection)

    def __init__(self, data, db_connection):
        self._data = data
        self._db_connection


# Create entity
entity = Entity.from_id(id_number, db_connection)

Above is an example of what not to do or at least what not to do if there is an alternative. Now I am wondering if editing my class method so that it is more of a utility method and less of a factory method is a valid solution. In other words, does the following example comply with the best practice for using static methods.

class Entity(object):

    @staticmethod
    def data_from_id(id_number, db_connection):
        filters = [['id', 'is', id_number]]
        data = db_connection.find(filters)
        return data


# Create entity
data = Entity.data_from_id(id_number, db_connection)
entity = Entity(data)

Or does it make more sense to use a standalone function to find the entity data from an ID number.

def find_data_from_id(id_number, db_connection):
    filters = [['id', 'is', id_number]]
    data = db_connection.find(filters)
    return data


# Create entity.
data = find_data_from_id(id_number, db_connection)
entity = Entity(data, db_connection)

Note: I do not want to change my __init__ method. Previously people have suggested making my __init__ method to look something like this __init__(self, data=None, id_number=None) but there could be 101 different ways to find the entity data so I would prefer to keep that logic separate to some extent. Make sense?

解决方案

When and how are static methods suppose to be used in python?

The glib answer is: Not very often.

The even glibber but not quite as useless answer is: When they make your code more readable.


First, let's take a detour to the docs:

Static methods in Python are similar to those found in Java or C++. Also see classmethod() for a variant that is useful for creating alternate class constructors.

So, when you need a static method in C++, you need a static method in Python, right?

Well, no.

In Java, there are no functions, just methods, so you end up creating pseudo-classes that are just bundles of static methods. The way to do the same thing in Python is to just use free functions.

That's pretty obvious. However, it's good Java style to look as hard as possible for an appropriate class to wedge a function into, so you can avoid writing those pseudo-classes, while doing the same thing is bad Python style—again, use free functions—and this is much less obvious.

C++ doesn't have the same limitation as Java, but many C++ styles are pretty similar anyway. (On the other hand, if you're a "Modern C++" programmer who's internalized the "free functions are part of a class's interface" idiom, your instincts for "where are static methods useful" are probably pretty decent for Python.)


But if you're coming at this from first principles, rather than from another language, there's a simpler way to look at things:

A @staticmethod is basically just a global function. If you have a function foo_module.bar() that would be more readable for some reason if it were spelled as foo_module.BazClass.bar(), make it a @staticmethod. If not, don't. That's really all there is to it. The only problem is building up your instincts for what's more readable to an idiomatic Python programmer.

And of course use a @classmethod when you need access to the class, but not the instance—alternate constructors are the paradigm case for that, as the docs imply. Although you often can simulate a @classmethod with a @staticmethod just by explicitly referencing the class (especially when you don't have much subclassing), you shouldn't.


Finally, getting to your specific question:

If the only reason clients ever need to look up data by ID is to construct an Entity, that sounds like an implementation detail you shouldn't be exposing, and it also makes client code more complex. Just use a constructor. If you don't want to modify your __init__ (and you're right that there are good reasons you might not want to), use a @classmethod as an alternate constructor: Entity.from_id(id_number, db_connection).

On the other hand, if that lookup is something that's inherently useful to clients in other cases that have nothing to do with Entity construction, it seems like this has nothing to do with the Entity class (or at least no more than anything else in the same module). So, just make it a free function.

这篇关于在Python中使用静态方法 - 最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆