Hva er klasse metoder i Python for?

stemmer
222

Jeg lærer meg selv Python og min siste leksjon var at Python er ikke Java , og så har jeg bare brukt en stund snu alle mine klassemetoder til funksjoner.

Jeg innser nå at jeg ikke trenger å bruke klassemetoder for hva jeg ville gjort med staticmetoder i Java, men nå er jeg ikke sikker på når jeg ville bruke dem. Alle råd jeg kan finne om Python Klassemetoder er langs linjene av nybegynnere som meg bør styre klar av dem, og standard dokumentasjon er på sitt mest dekkende når man diskuterer dem.

Har noen et godt eksempel på bruk av en klasse metode i Python eller i det minste kan noen fortelle meg når Klasse metoder kan fornuftig brukt?

Publisert på 01/09/2008 klokken 18:16
kilden bruker
På andre språk...                            


15 svar

stemmer
163

Klassemetoder for når du må ha metoder som ikke er spesifikke for noen bestemt eksempel, men likevel involvere klassen på noen måte. Det mest interessante ting om dem er at de kan overstyres av subklasser, noe som er rett og slett ikke mulig i Java statiske metoder eller Python modul nivå funksjoner.

Hvis du har en klasse MyClass, og en modul-nivå funksjon som opererer på MyClass (fabrikk, avhengighet injeksjon spire, etc), gjør det til en classmethod. Da vil den være tilgjengelig for å underklasser.

Svarte 01/09/2008 kl. 18:45
kilden bruker

stemmer
60

Fabrikk metoder (alternative konstruktører) er faktisk et klassisk eksempel på klassen metoder.

I utgangspunktet klassemetoder er egnet når du ønsker å ha en metode som naturlig passer inn i navne av klassen, men er ikke knyttet til en bestemt forekomst av klassen.

Som et eksempel på den utmerkede Unipath modulen:

gjeldende katalog

  • Path.cwd()
    • Returnere den faktiske gjeldende katalog; f.eks Path("/tmp/my_temp_dir"). Dette er en klassemetode.
  • .chdir()
    • Gjør selv gjeldende katalog.

Ettersom den aktuelle katalogen er prosess bred, den cwdhar fremgangsmåten ingen spesielle tilfelle med hvilken den skal være knyttet. Men å endre cwdtil katalogen av et gitt Pathtilfelle bør faktisk være en instansmetode.

Hmmm ... som Path.cwd()gjør faktisk returnere et Patheksempel, tror jeg det kan anses å være en fabrikk metode ...

Svarte 01/09/2008 kl. 19:08
kilden bruker

stemmer
45

Tenk på det på denne måten: vanlige metoder er nyttige for å skjule detaljene levering: du kan skrive myobj.foo()uten å tenke på om foo()metoden er implementert av myobjobjektets klasse eller en av de overordnede klasser. Klassemetoder er nøyaktig analog til dette, men med klassen objekt i stedet: de lar deg ringe MyClass.foo()uten å måtte bekymre deg om foo()er implementert spesielt av MyClassfordi det trengte sin egen spesialisert versjon, eller om det er å la sin overordnede klassen håndtere samtalen.

Klassemetoder er avgjørende når du gjør set-up eller beregning som går forut for etableringen av en faktisk eksempel, fordi før forekomsten foreligger du åpenbart ikke kan bruke forekomsten som sendepunkt for metodekall. Et godt eksempel kan sees i SQLAlchemy kildekoden; ta en titt på den dbapi()klassen metoden på følgende link:

https://github.com/zzzeek/sqlalchemy/blob/ab6946769742602e40fb9ed9dde5f642885d1906/lib/sqlalchemy/dialects/mssql/pymssql.py#L47

Du kan se at dbapi()metoden, som en database backend bruker til å importere den leverandørspesifikke database bibliotek den trenger on-demand, er en klasse metoden fordi det er behov for å kjøre før forekomster av et bestemt databasetilkobling begynner å bli opprettet - men at det ikke kan være en enkel funksjon eller statisk funksjon, fordi de ønsker at det skal være i stand til å ringe andre, støtte metoder som kan på samme måte trenger å være skrevet mer spesifikt i underklasser enn i foreldrenes klasse. Og hvis du sende til en funksjon eller statisk klasse, så du "glemme" og mister kunnskap om hvilken klasse gjør det initialiseres.

Svarte 19/08/2010 kl. 12:51
kilden bruker

stemmer
26

Jeg har nylig ønsket en meget lett logging klasse som ville utgang varierende mengder av produksjonen avhengig av logging nivå som kan programmatisk innstilt. Men jeg hadde ikke lyst på å bruke klassen hver gang jeg ønsket å sende ut en debugging melding eller feil eller advarsel. Men jeg ønsket også å kapsle funksjonen av dette logging anlegget og gjøre det gjenbrukbare uten utdeling av globals.

Så jeg brukte klassevariabler og @classmethoddekoratør for å oppnå dette.

Med min enkle Logging klasse, kunne jeg gjøre følgende:

Logger._level = Logger.DEBUG

Så, i min kode, hvis jeg ønsket å spytte ut en haug med feilsøkingsinformasjon, jeg bare måtte kode

Logger.debug( "this is some annoying message I only want to see while debugging" )

Feil kan bli ut satt med

Logger.error( "Wow, something really awful happened." )

I "produksjon" miljø, kan jeg angi

Logger._level = Logger.ERROR

og nå, bare feilmeldingen vil bli sendt ut. Debug meldingen vil ikke bli skrevet ut.

Her er min klasse:

class Logger :
    ''' Handles logging of debugging and error messages. '''

    DEBUG = 5
    INFO  = 4
    WARN  = 3
    ERROR = 2
    FATAL = 1
    _level = DEBUG

    def __init__( self ) :
        Logger._level = Logger.DEBUG

    @classmethod
    def isLevel( cls, level ) :
        return cls._level >= level

    @classmethod
    def debug( cls, message ) :
        if cls.isLevel( Logger.DEBUG ) :
            print "DEBUG:  " + message

    @classmethod
    def info( cls, message ) :
        if cls.isLevel( Logger.INFO ) :
            print "INFO :  " + message

    @classmethod
    def warn( cls, message ) :
        if cls.isLevel( Logger.WARN ) :
            print "WARN :  " + message

    @classmethod
    def error( cls, message ) :
        if cls.isLevel( Logger.ERROR ) :
            print "ERROR:  " + message

    @classmethod
    def fatal( cls, message ) :
        if cls.isLevel( Logger.FATAL ) :
            print "FATAL:  " + message

Og noen kode som tester det bare litt:

def logAll() :
    Logger.debug( "This is a Debug message." )
    Logger.info ( "This is a Info  message." )
    Logger.warn ( "This is a Warn  message." )
    Logger.error( "This is a Error message." )
    Logger.fatal( "This is a Fatal message." )

if __name__ == '__main__' :

    print "Should see all DEBUG and higher"
    Logger._level = Logger.DEBUG
    logAll()

    print "Should see all ERROR and higher"
    Logger._level = Logger.ERROR
    logAll()
Svarte 11/05/2010 kl. 01:48
kilden bruker

stemmer
23

Alternative konstruktører er klassisk eksempel.

Svarte 01/09/2008 kl. 18:27
kilden bruker

stemmer
10

Jeg tror det mest klare svar er AmanKow er en. Det koker ned til hvordan u ønsker å organisere koden din. Du kan skrive alt som modul nivå funksjoner som er innpakket i navne av modulen dvs.

module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass


usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass 
def f5():pass

usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()

Ovennevnte prosedyrekode er ikke godt organisert, som du kan se etter bare tre moduler det blir forvirrende, hva som hver metode gjøre? Du kan bruke lange beskrivende navn for funksjoner (som i java), men likevel koden din blir uhåndterlig veldig rask.

Den objektorientert måte er å bryte ned koden i håndterbare blokker dvs. kurs og gjenstander og funksjoner kan være assosiert med objekter instanser eller med klasser.

Med klasse funksjoner får du et annet nivå av divisjonen i koden sammenlignet med modul nivå funksjoner. Så du kan gruppere beslektede funksjoner i en klasse for å gjøre dem mer spesifikke for en oppgave du tildelt den klassen. For eksempel kan du lage en fil utility klasse:

class FileUtil ():
  def copy(source,dest):pass
  def move(source,dest):pass
  def copyDir(source,dest):pass
  def moveDir(source,dest):pass

//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")

På denne måten er mer fleksibel og mer vedlikeholdsvennlig, du grupperer funksjoner sammen og det mer tydelig for hva hver funksjon gjør. Også du unngå navnekonflikter, for eksempel funksjonen kopien kan eksistere i en annen importert modul (for eksempel nettverk kopi) som du bruker i koden din, så når du bruker fullt navn FileUtil.copy () du fjerner problemet og begge kopifunksjonene kan brukes ved siden av hverandre.

Svarte 14/05/2011 kl. 10:24
kilden bruker

stemmer
8

Når en bruker logger inn på min hjemmeside, er en Bruker () objekt instansiert fra brukernavn og passord.

Hvis jeg trenger et brukerobjekt uten at brukeren blir det å logge på (f.eks en admin bruker kanskje vil slette en annen brukerens konto, så jeg trenger på å bruke den brukeren og kaller sin slettemetoden):

Jeg har klassemetoder for å hente brukerobjektet.

class User():
    #lots of code
    #...
    # more code

    @classmethod
    def get_by_username(cls, username):
        return cls.query(cls.username == username).get()

    @classmethod
    def get_by_auth_id(cls, auth_id):
        return cls.query(cls.auth_id == auth_id).get()
Svarte 26/03/2012 kl. 06:36
kilden bruker

stemmer
6

Den lar deg skrive generiske klassen metoder som du kan bruke med alle kompatible klasse.

For eksempel:

@classmethod
def get_name(cls):
    print cls.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C.get_name()

Hvis du ikke bruker @classmethodkan du gjøre det med selv søkeord, men det er behov for en instans av klassen:

def get_name(self):
    print self.name

class C:
    name = "tester"

C.get_name = get_name

#call it:
C().get_name() #<-note the its an instance of class C
Svarte 26/12/2012 kl. 15:11
kilden bruker

stemmer
5

Jeg pleide å jobbe med PHP og nylig ble jeg spurt meg selv, hva som skjer med denne classmethod? Python manualen er svært teknisk og svært kort i ord så det ikke vil hjelpe med å forstå denne funksjonen. Jeg var googling og googling og jeg fant svaret -> http://code.anjanesh.net/2007/12/python-classmethods.html .

Hvis du er lat til å klikke den. Min forklaring er kortere og lavere. :)

i PHP (kanskje ikke alle vet PHP, men dette språket er så rett frem at alle skal forstå hva jeg snakker om) har vi statiske variabler som dette:


class A
{

    static protected $inner_var = null;

    static public function echoInnerVar()
    {
        echo self::$inner_var."\n";
    }

    static public function setInnerVar($v)
    {
        self::$inner_var = $v;
    }

}

class B extends A
{
}

A::setInnerVar(10);
B::setInnerVar(20);

A::echoInnerVar();
B::echoInnerVar();

Utgangen vil være i begge tilfeller 20.

Men i python kan vi legge @classmethod dekoratør og dermed er det mulig å ha utgang 10 og 20 henholdsvis. Eksempel:


class A(object):
    inner_var = 0

    @classmethod
    def setInnerVar(cls, value):
        cls.inner_var = value

    @classmethod
    def echoInnerVar(cls):
        print cls.inner_var


class B(A):
    pass


A.setInnerVar(10)
B.setInnerVar(20)

A.echoInnerVar()
B.echoInnerVar()

Smart, ikke?

Svarte 22/02/2010 kl. 13:27
kilden bruker

stemmer
4

Klassemetoder gi en "semantisk sukker" (vet ikke om dette begrepet er mye brukt) - eller "semantisk convenience".

Eksempel: du har et sett med klasser som representerer stedene. Du ønsker kanskje å ha klassen metoden all()eller find()å skrive User.all()eller User.find(firstname='Guido'). Det kan gjøres ved hjelp av modul nivå funksjoner selvfølgelig ...

Svarte 17/08/2010 kl. 15:53
kilden bruker

stemmer
4

Ærlig talt? Jeg har aldri funnet en bruk for staticmethod eller classmethod. Jeg har til gode å se en operasjon som ikke kan gjøres ved hjelp av en global funksjon eller en instansmetode.

Det ville være annerledes hvis python brukes privat og beskyttet medlemmer mer som Java gjør. I Java, trenger jeg en statisk metode for å kunne få tilgang til en forekomst private medlemmer til å gjøre ting. I Python, det er sjelden nødvendig.

Vanligvis jeg ser folk bruke staticmethods og classmethods når alle de virkelig trenger å gjøre er å bruke python modulnivå navnerom bedre.

Svarte 01/09/2008 kl. 18:54
kilden bruker

stemmer
2

Hva bare slo meg, kommer fra Ruby, som er en såkalt klasse metode og en såkalt eksempel metoden er bare en funksjon med semantisk betydning påført sitt første parameter, som er stille sendes når funksjonen kalles som en metode for et objekt (ie obj.meth()).

Normalt at gjenstanden må være et eksempel, men @classmethod fremgangsmåten arkitekt endringer reglene for å passere en klasse. Du kan kalle en klassemetode på en forekomst (det er bare en funksjon) - den første argyment vil være sin klasse.

Fordi det er bare en funksjon , kan det bare bli erklært en gang i et gitt omfang (dvs. classdefinisjon). Det følger derfor som en overraskelse til en Rubyist, at du ikke kan ha en klassemetode og en forekomst metode med samme navn .

Tenk på dette:

class Foo():
  def foo(x):
    print(x)

Du kan ringe foopå en forekomst

Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>

Men ikke på en klasse:

Foo.foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)

Nå legger @classmethod:

class Foo():
  @classmethod
  def foo(x):
    print(x)

Ringe på en forekomst går nå sin klasse:

Foo().foo()
__main__.Foo

som ikke ringer på en klasse:

Foo.foo()
__main__.Foo

Det er bare konvensjon som tilsier at vi bruker selffor det første argumentet på en forekomst metode og clspå en klasse metode. Jeg brukte verken her for å illustrere at det er bare et argument. I Ruby selfer et nøkkelord.

Kontrast med Ruby:

class Foo
  def foo()
    puts "instance method #{self}"
  end
  def self.foo()
    puts "class method #{self}"
  end
end

Foo.foo()
class method Foo

Foo.new.foo()
instance method #<Foo:0x000000020fe018>

Python klassen metoden er bare en dekorert funksjon , og du kan bruke de samme teknikkene for å lage dine egne dekoratører . En dekorert metode brytes den virkelige metode (i tilfellet med @classmethodden passerer den ytterligere argumentet klasse). Den underliggende metoden er der fortsatt, skjult men fortsatt tilgjengelig .


fotnote: Jeg skrev dette etter et navn sammenstøt mellom en klasse og instansmetode pirret min nysgjerrighet. Jeg er langt fra en Python-ekspert og vil gjerne kommentarer hvis noe av dette er feil.

Svarte 24/03/2017 kl. 20:45
kilden bruker

stemmer
2

Dette er et interessant tema. Min ta på det er at python classmethod fungerer som en singleton snarere enn en fabrikk (som returnerer en produsert en forekomst av en klasse). Grunnen til at det er en singel er at det er en vanlig objekt som er produsert (ordlisten), men bare én gang for klassen, men felles for alle tilfeller.

For å illustrere dette her er et eksempel. Merk at alle tilfeller ha en referanse til én ordbok. Dette er ikke Factory mønster som jeg forstår det. Dette er trolig svært unik for python.

class M():
 @classmethod
 def m(cls, arg):
     print "arg was",  getattr(cls, "arg" , None),
     cls.arg = arg
     print "arg is" , cls.arg

 M.m(1)   # prints arg was None arg is 1
 M.m(2)   # prints arg was 1 arg is 2
 m1 = M()
 m2 = M() 
 m1.m(3)  # prints arg was 2 arg is 3  
 m2.m(4)  # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
 M.m(5)   # prints arg was 4 arg is 5
Svarte 07/09/2012 kl. 05:06
kilden bruker

stemmer
1

Jeg spurte meg selv det samme spørsmålet mange ganger. Og selv om gutta her prøvde hardt å forklare det, IMHO det beste svaret (og enkleste) svaret jeg har funnet er den beskrivelse av klasse metoden i Python Documentation.

Det er også referanse til den statiske metode. Og i tilfelle noen vet allerede instansmetoder (som jeg antar), kan dette svaret være den siste brikken for å sette det hele sammen ...

Videre og dypere utdypning om dette emnet finner du også i dokumentasjonen: The standard type hierarki (bla ned til Instance metoder seksjon)

Svarte 14/10/2014 kl. 07:07
kilden bruker

stemmer
0

En klasse definerer et sett av eksempler, selvfølgelig. Og metoder for en klasse arbeid på de enkelte tilfeller. Klassen metoder (og variable) et sted for å henge annen informasjon som er relatert til det sett av forekomster over alt.

For eksempel hvis din klasse definerer et sett av studenter kan det være lurt klassevariabler eller metoder som definerer ting som sett med klasse elevene kan være medlemmer av.

Du kan også bruke klassemetoder for å definere verktøy for å arbeide på hele settet. For eksempel Student.all_of_em () kan returnere alle de kjente studenter. Selvfølgelig hvis sett tilfeller har mer struktur enn bare et sett du kan gi klassemetoder for å vite om den strukturen. Students.all_of_em (grade = 'junior')

Teknikker som dette har en tendens til å føre til lagring av elementer i settet av instanser inn i datastrukturer som er forankret i klassevariabler. Du må passe på å unngå frustrerende søppelrydding da.

Svarte 08/09/2016 kl. 01:29
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more