2013-02-21 32 views
22

Bu, python kullanarak aynı verinin farklı biçimlerinden bir sınıf veya türün örneğinin oluşturulmasına yönelik en iyi uygulama ile ilgili bir sorudur. Bir sınıf metodu kullanmak daha mı iyidir yoksa ayrı bir işlevi tamamen kullanmak daha mı iyidir? Bir belgenin boyutunu tanımlamak için kullanılan bir dersim olduğunu söyleyelim. (Not: Bu yalnızca bir örnek olduğunu bir belgenin boyutunu açıklamak için en iyi yolu sınıfının bir örneğini DEĞİL oluşturmak için en iyi yolu bilmek istiyorum..)Python nesnesi için fabrika yöntemi - en iyi uygulama

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 

Benim __init__ yöntem bir boyut değerini alır bit olarak temsil edilir (bitler ve sadece bitler ve ben bu şekilde tutmak istiyorum) ama bir bayt cinsinden boyut değerine sahip olduğumu söyler ve sınıfımın bir örneğini oluşturmak isterim. Bir sınıf metodu kullanmak daha mı iyidir yoksa ayrı bir işlevi tamamen kullanmak daha mı iyidir?

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

Bu

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) 

VEYA

bir sorun gibi görünmeyebilir ve belki de her ikisi örnekler geçerlidir ama bu konuda böyle bir şey uygulamak gerekir her zaman düşünüyorum. Uzun bir süredir sınıf yöntemini tercih ettim çünkü sınıf ve fabrika yöntemini birbirine bağlamanın örgütsel faydalarını seviyorum. Ayrıca, bir sınıf yöntemi kullanmak, herhangi bir alt sınıfın örneklerini oluşturma yeteneğini korur, böylece daha fazla nesne yönlendirilir. Öte yandan, bir arkadaş bir kez “Şüphe edildiğinde, standart kütüphanenin ne yaptığını” söyledi ve ben de standart kütüphanede bunun bir örneğini bulmayacağım.

Her türlü geri bildiriminiz için teşekkür ederiz.

Alkış

+0

Bir bozuk para çeviririm. Çoğu python kitaplığı, prosedürel API'leri tercih ediyor gibi görünmektedir, ancak bunun nedeni, kod tabanınızda dahili olarak kullanılabilen yeniden kullanılabilir koddan farklı bir şekilde tüketilmesidir. – millimoose

+4

PS, “bytes” değişkenini çağırmayın; Bu yerleşik bir tür (2.6 ve üstü). – abarnert

+3

Ve tabi ki fark ettim ki aynı hatayı benim cevabımda yaptım: 'Boyut (bayt = 20)'. Yaptığımı yapma, dediğimi yap. :) – abarnert

cevap

22

Öncelikle, böyle bir şey gerek çoğu zaman, değil mi; Python'u Java gibi tedavi etmeye çalıştığınız bir işarettir ve çözüm geri adım atıp neden bir fabrikaya ihtiyacınız olduğunu sormaktır.

Genellikle yapılacak en basit şey, varsayılan/isteğe bağlı/anahtar sözcük bağımsız değişkenleri olan bir kurucuya sahip olmaktır. Java'da bu şekilde yazamayacağınız durumlar bile - aşırı yüklenen kurucuların C++ veya ObjC'de yanlış hissettikleri durumlarda bile - Python'da tamamen doğal görünebilir. Örneğin, size = Size(bytes=20) veya size = Size(20, Size.BYTES) makul görünüyor. Bu bakımdan, Size'dan devraldığı ve __init__ aşırı yüklenmenin makul olduğunu düşündüğü hiçbir şey eklemeyen Bytes(20) sınıfı. bazen ihtiyaç fabrika işlevleri yapmak ,

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

Ama:

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

Veya: Ve bunlar tanımlamak için önemsizdir. Peki, o zaman ne yapıyorsun? Eh, genellikle "fabrikalar" içine toplanmış iki tür şey vardır.

A @classmethod örnekler tüm stdlib- itertools.chain.from_iterable, datetime.datetime.fromordinal üzerinde -Orada olan bir "alternatif yapıcı" yapmak için deyimsel yolu vb

bir işlevi yapmak deyimsel yoludur olan "I do not gerçek sınıfın ne olduğuna dikkat edin "fabrika. Örneğin, yerleşik open işlevine bakın. 3.3'te ne döndüğünü biliyor musun? Umurunda mı? Hayır! İşte bu yüzden bir fonksiyon, io.TextIOWrapper.open ya da her neyse.

Verilen örneğiniz, tam olarak geçerli bir kullanım durumu gibi görünüyor ve "alternatif yapıcı" bölmesine oldukça açık bir şekilde uyuyor (eğer "ek argümanlar olan kurucuya" bin değilse).

+2

Buna katılıyorum - sadece bir @classmethod yerine başka bir tasarım seçimine işaret etmek adil - '__init __ (kilobytes = 345) 'yapmak için ... vs ... –

+0

@JonClements: İyi bir nokta - gerçekten düşünmeme rağmen İlk cümle ile uyuyor, bu kesinlikle yazılı olarak net değil, bu yüzden onu düzenleyeceğim. – abarnert

+0

Yup - bu kullanım vakası için düşündüğüm: http://dpaste.com/958194/ (n * base * öksürük olması hariç *) –