超越Python中的工厂

2024-09-29 23:29:59 发布

您现在位置:Python中文网/ 问答频道 /正文

从Java来到Python,我被告知工厂不是Python。因此,我想找一个跟Python一样的方法。(我把我的目标简单化了,这样我就不用描述我的整个计划了,这非常复杂)。在

我的脚本将读取人名(以及他们的一些信息),然后从中构造Person类型的对象。名字可能重复,我只希望每个名字有一个人实例。这些人也可能属于男人和女人的亚类。在

一种方法是创建一个PersonFactory,它将返回一个新实例化的Man或Woman一个对先前实例化的同名男/女的引用。另一种方法是创建一组所有的Person对象,并在实例化一个新对象之前,每次都检查是否存在具有给定名称的Person。不过,这两种方法在我看来都不像Python。对于Python来说,第一个似乎太麻烦了(创建一个完整的类来处理另一个对象的创建?真的吗?)第二个会很快变得昂贵,因为我有很多名字要处理。在


Tags: 对象实例方法脚本信息类型目标工厂
3条回答

我不认为工厂是非Python式的。不过,你不需要整堂课。Java和Python之间的一个很大的区别是,在Python中可以有类之外的代码。所以您可能需要创建一个工厂函数。也可以将工厂设置为Person类上的类方法:

class Person:

    name_map = {}

    @classmethod
    def person_from_name(cls, name):
        if name not in cls.name_map:
            cls.name_map[name] = cls(name)
        return cls.name_map[name]

    def __init__(self, name):
        etc...

Python代码中的模式通常与Java中的模式相同,但我们并没有把它放在重要位置。在Java中,你会有一个全新的类,这意味着一个全新的.Java文件,你需要使它成为一个单例,等等。Java似乎滋生了这种复杂性。一个简单的类方法就可以了,所以只需使用它。在

将“no two objects with same key”注册放在__new__中,如下所示:

class Person(object):
    person_registry = {}
    mens_names = set('Tom Dick Harry'.split())
    womens_names = set('Mary Linda Susan'.split())
    gender = "?"
    def __new__(cls, *args):
        if cls is Person:
            fname,lname = args[0].split()
            key = (lname, fname)
            if key in Person.person_registry:
                return Person.person_registry[key]

            if fname in Person.mens_names:
                return Man(*args)
            if fname in Person.womens_names:
                return Woman(*args)
        else:
            return object.__new__(cls, *args)

    def __init__(self, name):
        fname,lname = name.split()
        Person.person_registry[(lname, fname)] = self

class Man(Person):
    gender = "M"

class Woman(Person):
    gender = "W"

p1 = Person("Harry Turtledove")
print p1.__class__.__name__, p1.gender

p2 = Person("Harry Turtledove")

print p1 is p2

印刷品:

^{pr2}$

我也对你的男人和女人的区别做了一番尝试,但我对此并不感到兴奋。在

一个独立的函数def PersonFactory(name, gender):是很好的,尽管像@Ned所建议的那样,将它打包成一个classmethod应该不会有什么影响(在这种特殊情况下,它也不会有太大帮助,因为要实例化的person的确切类必须有所不同)。我认为最干净的实现实际上是作为一个独立的函数,只是因为我更喜欢使用一个类方法来返回它所调用的类的实例(而不是其他类的实例),但这是一个风格上的问题,不能说是定义得很明确。在

我会对其进行编码(我希望有一些明确的假设,例如,性别编码为M或{},如果没有指定,则从名称中推断出来&c):

def gender_from_name(name): ...

person_by_name = {}

class_by_gender = {'M': Man, 'F': Woman}

def person_factory(name, gender=None):
  p = person_by_name.get(name)
  if p is None:
    if gender is None:
      gender = gender_from_name(name)
    p = person_by_name[name] = class_by_gender[gender](name)
  return p

相关问题 更多 >

    热门问题