Python “tanrı sınıfı” nı yeniden düzenlerim?


10

Sorun

Ana sınıfı biraz “ Tanrı Nesnesi ” olan bir Python projesi üzerinde çalışıyorum . Vardır bu yüzden birçok özellik ve yöntemlere friggin!

Sınıfa yeniden bakmak istiyorum.

Şimdiye kadar…

İlk adım olarak, nispeten basit bir şey yapmak istiyorum; ama en basit yaklaşımı denediğimde, bazı testler ve mevcut örnekler kırıldı.

Temelde, sınıfın özniteliklerin bir listesi var - ama açıkça onlara bakabilir ve “Bu 5 nitelik birbiriyle ilişkilidir… Bu 8 de ilişkilidir… ve sonra gerisi var.”

getattr

Temelde sadece ilgili özellikleri dikte benzeri bir yardımcı sınıfta gruplamak istedim. __getattr__İş için ideal olacağını düşündüm . Bu yüzden nitelikleri ayrı bir sınıfa taşıdım ve eminim __getattr__sihrini mükemmel şekilde çalıştı…

İlk başta .

Ama sonra örneklerden birini çalıştırmayı denedim. Örnek alt sınıf, bu niteliklerden birini doğrudan ( sınıf düzeyinde ) ayarlamaya çalışır . Ancak, öznitelik artık üst sınıfta “fiziksel olarak” bulunmadığından, özniteliğin var olmadığını söyleyen bir hata aldım.

@Emlak

Sonra @propertydekoratör hakkında okudum . Ama sonra da ana sınıfın bir özelliği self.x = blaholduğunda yapmak istediğiniz alt sınıflar için problemler yarattığını okudum x.

İstenen

  • self.whateverEbeveynin whateverözelliği sınıfın (veya örneğin) kendisinde "fiziksel olarak" bulunmasa bile, tüm istemci kodunun çalışmaya devam etmesini sağlayın.
  • İlgili nitelikleri dikte benzeri kaplarda gruplayın.
  • Ana sınıftaki kodun aşırı gürültüsünü azaltın.

Örneğin, ben yok sadece bunu değiştirmek istiyorum:

larry = 2
curly = 'abcd'
moe   = self.doh()

Bunun içine:

larry = something_else('larry')
curly = something_else('curly')
moe   = yet_another_thing.moe()

… Çünkü bu hala gürültülü. Bu, verileri yönetebilen bir şeye başarılı bir şekilde basit bir öznitelik oluştursa da, orijinalin 3 değişkeni vardı ve düzeltilmiş versiyonun hala 3 değişkeni var.

Ancak, böyle bir şeyle iyi olurdu:

stooges = Stooges()

Ve eğer bir arama self.larrybaşarısız olursa, bir şey orada olup olmadığını kontrol eder stoogesve görür larry. (Ancak, bir alt larry = 'blah'sınıf sınıf düzeyinde yapmaya çalışırsa da çalışmalıdır .)

özet

  • Bir üst sınıftaki ilgili özellik gruplarını, tüm verileri başka bir yerde depolayan tek bir özellikle değiştirmek istiyorum
  • larry = 'blah'Sınıf düzeyinde (ör.) Kullanan mevcut istemci koduyla çalışmak istiyorum
  • Alt sınıfların, hiçbir şey değiştiğini bilmeden bu yeniden düzenlenmiş özellikleri genişletmesine, geçersiz kılmasına ve değiştirmesine izin vermeye devam etmek istiyorum


Mümkün mü? Yoksa yanlış ağacı mı havlıyorum?


6
Uygulamanın bazı bölümlerini ayırsanız bile, hala bu büyük tanrı benzeri arayüze sahip olmakta ısrar ediyorsanız, avantajlarının yarısını kaçırıyorsunuz. Kısayollar sağlayabilirsiniz, ancak değişkenleri farklı ad alanlarına koymak ve bunlara tam olarak yeniden yönlendirmek size çok az şey verir.

1
@delnan: Tamam, onun yerine ne önerirsiniz?
Zearin

Yanıtlar:


9

Bir python "Tanrı nesnesi" yazıp yeniden düzenledikten sonra sempati duyuyorum. Yaptığım şey orijinal nesneyi yöntemlere göre alt bölümlere ayırmak. Örneğin, orijinal şu ​​sahte kod gibi görünüyordu:

method A():
    self.bla += 1

method B():
    self.bla += 1

do stuff():
    self.bla = 1
    method A()
    method B()
    print self.bla

Stuff yöntemi bağımsız bir "birim" iştir. Orijinalin somutlaştırdığı yeni bir sınıfa göç ettim. Bu da gerekli özellikleri ortaya çıkardı. Bazıları sadece alt sınıf tarafından kullanıldı ve düz bir şekilde hareket edebildiler. Diğerleri paylaşıldı ve paylaşılan bir sınıfa taşındı.

"Tanrı nesnesi" başlangıçta paylaşılan sınıfın yeni bir kopyasını oluşturur ve yeni alt sınıfların her biri, init yönteminin bir parçası olarak bir işaretçiyi kabul eder. Örneğin, postanın soyulmuş bir versiyonu:

#!/usr/bin/env python
# -*- coding: ascii -*-
'''Functions for emailing with dirMon.'''

from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders
import os
import smtplib
import datetime
import logging

class mailer:
    def __init__(self,SERVER="mail.server.com",FROM="support@server.com"):
        self.server = SERVER
        self.send_from = FROM
        self.logger = logging.getLogger('dirMon.mailer')

    def send_mail(self, send_to, subject, text, files=[]):
        assert type(send_to)==list
        assert type(files)==list
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug(' '.join(("Sending email to:",' '.join(send_to))))
            self.logger.debug(' '.join(("Subject:",subject)))
            self.logger.debug(' '.join(("Text:",text)))
            self.logger.debug(' '.join(("Files:",' '.join(files))))
        msg = MIMEMultipart()
        msg['From'] = self.send_from
        msg['To'] = COMMASPACE.join(send_to)
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject
        msg.attach( MIMEText(text) )
        for f in files:
            part = MIMEBase('application', "octet-stream")
            part.set_payload( open(f,"rb").read() )
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
            msg.attach(part)
        smtp = smtplib.SMTP(self.server)
        mydict = smtp.sendmail(self.send_from, send_to, msg.as_string())
        if self.logger.isEnabledFor(logging.DEBUG):
            self.logger.debug("Email Successfully Sent!")
        smtp.close()
        return mydict

Bir kez oluşturulur ve postalama yeteneklerine ihtiyaç duyan farklı sınıflar arasında paylaşılır.

Yani sizin için, larryihtiyacınız olan özelliklere ve yöntemlere sahip bir sınıf oluşturun . Müşterinin söylediği her yerde larry = blahdeğiştirin larryObj.larry = blah. Bu, mevcut arayüzü bozmadan işleri alt projelere taşır.

Yapılacak tek şey "iş birimleri" aramaktır. "Tanrı Nesnesi" nin bir parçasını kendi yöntemine dönüştürürseniz, bunu yapın . Ancak, yöntemi onun dışına koyun. Bu sizi bileşenler arasında bir arabirim oluşturmaya zorlar.

Bu zemini döşemek, her şeyin onu takip etmesine izin verir. Örneğin, yardımcı nesnenin posta ile nasıl arayüz oluşturduğunu gösteren bir parçası:

#!/usr/bin/env python
'''This module holds a class to spawn various subprocesses'''
import logging, os, subprocess, time, dateAdditionLib, datetime, re

class spawner:
    def __init__(self, mailer):
        self.logger = logging.getLogger('dirMon.spawner')
        self.myMailer = mailer

Mümkün olan en küçük iş birimine konsantre olun ve dışarı çıkarın. Bunu yapmak daha kolaydır ve kurulumla hızlı bir şekilde oynamanıza izin verir. Hareketli şeylerin özelliklerine bakmayın, çoğu durumda onlarla yapılan görevlere yardımcı olurlar . Paylaşılan durumun bir parçası olduğu için , yöntemlerle uğraştıktan sonra kalan her şey muhtemelen orijinal nesnede kalmalıdır .

Ancak , yeni nesneler artık arayan nesneleri özelliğine dokunmak yerine ihtiyaç duydukları özellikleri init değişkenleri olarak kabul etmelidir. Daha sonra, arayanın paylaşılan özellikleri gerektiği gibi güncellemek için kullanabileceği gerekli değerleri döndürürler. Bu, nesnelerin ayrıştırılmasına yardımcı olur ve daha sağlam bir sistem sağlar.


1
Harika bir cevap Spencer. Teşekkür ederim! Burada uygun olamayacak kadar spesifik bazı takip sorularım var. Bunları görüşmek için sizinle özel olarak iletişime geçebilir miyim?
Mart'ta Zearin

@Zearin, profilimde e-posta adresim var. Bu bir şirket projesi içindi ve orada bulunan tescilli şeyler nedeniyle deponun tam bir kopyasını veremem. Yeterli zaman verildiğinde, anlık görüntülerden önce / sonra temizleyebilirim, ancak bunun size ne kadar yardımcı olacağından emin değilim.
Spencer Rathbun

Profilinizde herhangi bir e-posta adresi göremiyorum. Her türlü bilgi var, ancak iletişim bilgisi yok. ☺ Size nasıl ulaşmalıyım?
Zearin

Anladım. Cybermen: “Sil! Sil! Sil!”
Zearin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.