python对象的工厂方法 - 最佳实践 [英] Factory method for python object - best practice

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

问题描述

这是一个关于使用python从不同形式的相同数据创建类或类型的实例的最佳实践的问题。是更好地使用类方法还是更好地使用一个单独的函数?假设我有一个类用于描述文档的大小。 (注意:这只是一个例子,我想知道创建类的实例的最好方法,而不是描述文档大小的最好方法。)

  class Size(object):

用于描述文档大小的实用程序对象


BYTE = 8
KILO = 1024

def __init __(self,bits):
self._bits = bits

@property
def bits(self):
return float(self._bits)

@property
def bytes(self):
return self.bits / self。 BYTE

@property
def kilobits(self):
return self.bits / self.KILO

@property
def kilobytes self):
return self.bytes / self.KILO

@property
def megabits(self):
return self.kilobits / self.KILO

@property
def megabytes(self):
return self.kilobytes / self.KILO

我的 __ init __ 方法需要一个以位(位和只有位,我想保持这样的方式)表示的大小值,一个大小的值,以字节为单位,我想创建一个我的类的实例。是更好的使用类方法还是最好一起使用单独的函数?

  class Size(object):

用于描述文档大小的实用对象。


BYTE = 8
KILO = 1024

@classmethod
def from_bytes(cls,bytes):
bits = bytes * cls.BYTE
return cls(bits)

  def create_instance_from_bytes $ b bits = bytes * Size.BYTE 
return size(bits)

看起来像一个问题,也许这两个例子都是有效的,但我想每一次我需要实现这样的东西。很长一段时间我喜欢类方法方法,因为我喜欢把类和工厂方法绑在一起的组织优势。此外,使用类方法保留了创建任何子类的实例的能力,所以它更面向对象。另一方面,一个朋友曾经说过当有疑问,做标准库做什么,我还没有在标准库中找到这样的例子。



解决方案

首先,大多数时候你认为你需要这样的东西,你不会;这是一个迹象,你试图治疗Python像Java,解决方案是回退,问你为什么需要一个工厂。



通常,最简单的事情do是只有一个带有默认/可选/关键字参数的构造函数。即使在Java中你永远不会这样写的情况,即使在C ++或ObjC中重载构造函数感觉错误的情况下,在Python中也可能看起来很自然。例如, size = Size(bytes = 20) size = Size(20,Size.BYTES)合理。对于这种情况,从 Size 继承的 Bytes(20)类只添加一个 __ init __ 重载看起来合理。这些是微不足道的定义:

  def __init __(self,*,bits = None,bytes = None,kilobits = None, kilobytes = None):

或:

  BITS,BYTES,KILOBITS,KILOBYTES = 1,8,1024,8192#或object(),object(),object(),object()
def __init __ ,count,unit = Size.BITS):

但是,有时候你 >需要工厂功能。那么,你做什么呢?



A @classmethod 是做成一个替代构造函数的惯用方法 - 在stdlib - itertools.chain.from_iterable datetime.datetime.fromordinal 等。



一个函数是做一个我不在乎实际类是什么工厂的惯用方法。看看,例如,内置的 open 函数。你知道它在3.3中返回什么?你关心?不。这就是为什么它是一个函数,不是 io.TextIOWrapper.open 或任何。



合法的用例,并且很好地适合替代构造函数bin(如果它不适合具有额外参数的构造函数bin)。


This is a question regarding the best practice for creating an instance of a class or type from different forms of the same data using python. Is it better to use a class method or is it better to use a separate function altogether? Lets say I have a class used to describe the size of a document. (Note: This is simply an example. I want to know the best way to create an instance of the class NOT the best way to describe the size of a document.)

class Size(object):
    """
    Utility object used to describe the size of a document.
    """

    BYTE = 8
    KILO = 1024

    def __init__(self, bits):
        self._bits = bits

    @property
    def bits(self):
        return float(self._bits)

    @property
    def bytes(self):
        return self.bits / self.BYTE

    @property
    def kilobits(self):
        return self.bits / self.KILO

    @property
    def kilobytes(self):
        return self.bytes / self.KILO

    @property
    def megabits(self):
        return self.kilobits / self.KILO

    @property
    def megabytes(self):
        return self.kilobytes / self.KILO

My __init__ method takes a size value represented in bits (bits and only bits and I want to keep it that way) but lets say I have a size value in bytes and I want to create an instance of my class. Is it better to use a class method or is it better to use a separate function altogether?

class Size(object):
    """
    Utility object used to describe the size of a document.
    """

    BYTE = 8
    KILO = 1024

    @classmethod
    def from_bytes(cls, bytes):
        bits = bytes * cls.BYTE
        return cls(bits)

OR

def create_instance_from_bytes(bytes):
    bits = bytes * Size.BYTE
    return Size(bits)

This may not seem like an issue and perhaps both examples are valid but I think about it every time I need to implement something like this. For a long time I have preferred the class method approach because I like the organisational benefits of tying the class and the factory method together. Also, using a class method preserves the ability to create instances of any subclasses so it's more object orientated. On the other hand, a friend once said "When in doubt, do what the standard library does" and I am yet to find an example of this in the standard library.

Any feedback is much appreciated.

Cheers

解决方案

First, most of the time you think you need something like this, you don't; it's a sign that you're trying to treat Python like Java, and the solution is to step back and ask why you need a factory.

Often, the simplest thing to do is to just have a constructor with defaulted/optional/keyword arguments. Even cases that you'd never write that way in Java—even cases where overloaded constructors would feel wrong in C++ or ObjC—may look perfectly natural in Python. For example, size = Size(bytes=20), or size = Size(20, Size.BYTES) look reasonable. For that matter, a Bytes(20) class that inherits from Size and adds absolutely nothing but an __init__ overload looks reasonable. And these are trivial to define:

def __init__(self, *, bits=None, bytes=None, kilobits=None, kilobytes=None):

Or:

BITS, BYTES, KILOBITS, KILOBYTES = 1, 8, 1024, 8192 # or object(), object(), object(), object()
def __init__(self, count, unit=Size.BITS):

But, sometimes you do need factory functions. So, what do you do then? Well, there are two kinds of things that are often lumped together into "factories".

A @classmethod is the idiomatic way to do an "alternate constructor"—there are examples all over the stdlib—itertools.chain.from_iterable, datetime.datetime.fromordinal, etc.

A function is the idiomatic way to do an "I don't care what the actual class is" factory. Look at, e.g., the built-in open function. Do you know what it returns in 3.3? Do you care? Nope. That's why it's a function, not io.TextIOWrapper.open or whatever.

Your given example seems like a perfectly legitimate use case, and fits pretty clearly into the "alternate constructor" bin (if it doesn't fit into the "constructor with extra arguments" bin).

这篇关于python对象的工厂方法 - 最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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