Vraag Statische methoden in Python?


Is het mogelijk om statische methoden in Python te gebruiken, zodat ik ze kan bellen zonder een klasse te initialiseren, zoals:

ClassName.StaticMethod ( )

1391
2018-04-09 21:23


oorsprong


antwoorden:


Ja, met behulp van de staticmethod decorateur

class MyClass(object):
    @staticmethod
    def the_static_method(x):
        print x

MyClass.the_static_method(2) # outputs 2

Merk op dat sommige code de oude methode voor het definiëren van een statische methode kan gebruiken, gebruikmakend van staticmethod als een functie in plaats van een decorateur. Dit zou alleen moeten worden gebruikt als je oude versies van Python (2.2 en 2.3) moet ondersteunen

class MyClass(object):
    def the_static_method(x):
        print x
    the_static_method = staticmethod(the_static_method)

MyClass.the_static_method(2) # outputs 2

Dit is volledig identiek aan het eerste voorbeeld (gebruik @staticmethod), gewoon zonder de syntax van de mooie decorator

Eindelijk, gebruik staticmethod() spaarzaam! Er zijn maar weinig situaties waarin statische methoden nodig zijn in Python en ik heb ze vaak gebruikt waar een afzonderlijke "top-level" -functie duidelijker zou zijn geweest.


Het volgende is woordelijk uit de documentatie::

Een statische methode ontvangt geen impliciet eerste argument. Gebruik dit idioom om een ​​statische methode te declareren:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

De @staticmethod-vorm is een functie decorateur - zie de beschrijving van functiedefinities in Functiedefinities voor details.

Het kan in de klas worden genoemd (zoals C.f()) of op een instantie (zoals C().f()). De instantie wordt genegeerd behalve voor de klasse.

Statische methoden in Python komen overeen met die in Java of C ++. Zie voor een geavanceerder concept classmethod().

Raadpleeg voor meer informatie over statische methoden de documentatie over de standaardtypehiërarchie in De standaard type hiërarchie.

Nieuw in versie 2.2.

Gewijzigd in versie 2.4: Functie-decoratorsyntaxis toegevoegd.


1696
2018-04-09 21:24



ik denk dat Steven heeft eigenlijk gelijk. Als u de oorspronkelijke vraag wilt beantwoorden, moet u voor het instellen van een klassemethode gewoon aannemen dat het eerste argument geen aanroepexemplaar is en zorgt u er vervolgens voor dat u alleen de methode uit de klasse aanroept.

(Merk op dat dit antwoord verwijst naar Python 3.x. In Python 2.x krijg je een TypeError voor het aanroepen van de methode op de klasse zelf.)

Bijvoorbeeld:

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    def rollCall(n): #this is implicitly a class method (see comments below)
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))

fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)

In deze code veronderstelt de methode "rollCall" dat het eerste argument geen instantie is (zoals het zou zijn als het door een instantie zou worden aangeroepen in plaats van een klasse). Zolang "rollCall" wordt aangeroepen vanuit de klasse in plaats van een instantie, werkt de code prima. Als we "rollCall" vanuit een instance proberen te bellen, bijvoorbeeld:

rex.rollCall(-1)

het zou echter een uitzondering veroorzaken, omdat het twee argumenten zou sturen: zelf en -1, en "rollCall" is alleen gedefinieerd om één argument te accepteren.

Overigens zou rex.rollCall () het juiste aantal argumenten verzenden, maar zou ook een uitzondering veroorzaken omdat nu n een dog-instantie (d.w.z. rex) zou voorstellen wanneer de functie verwacht dat n numeriek is.

Hier komt de decoratie in: Als we de methode "rollCall" voorafgaan met

@staticmethod

vervolgens, door expliciet te stellen dat de methode statisch is, kunnen we deze zelfs vanuit een instantie aanroepen. Nu,

rex.rollCall(-1)

zou werken. Het invoegen van @staticmethod vóór een methodedefinitie stopt dan dat een instantie zichzelf verzendt als een argument.

U kunt dit verifiëren door de volgende code te proberen met en zonder de regel @staticmethod die is weergegeven.

class Dog:
    count = 0 # this is a class variable
    dogs = [] # this is a class variable

    def __init__(self, name):
        self.name = name #self.name is an instance variable
        Dog.count += 1
        Dog.dogs.append(name)

    def bark(self, n): # this is an instance method
        print("{} says: {}".format(self.name, "woof! " * n))

    @staticmethod
    def rollCall(n):
        print("There are {} dogs.".format(Dog.count))
        if n >= len(Dog.dogs) or n < 0:
            print("They are:")
            for dog in Dog.dogs:
                print("  {}".format(dog))
        else:
            print("The dog indexed at {} is {}.".format(n, Dog.dogs[n]))


fido = Dog("Fido")
fido.bark(3)
Dog.rollCall(-1)
rex = Dog("Rex")
Dog.rollCall(0)
rex.rollCall(-1)

176
2018-04-18 09:16



Ja, bekijk de staticmethod decorateur:

>>> class C:
...     @staticmethod
...     def hello():
...             print "Hello World"
...
>>> C.hello()
Hello World

74
2018-04-09 21:24



U hoeft het echt niet te gebruiken @staticmethod decorateur. Gewoon een methode declareren (die de zelfparameter niet verwacht) en deze vanuit de klas aanroepen. De decorateur is er alleen voor het geval je het ook vanuit een instantie wilt kunnen bellen (wat niet was wat je wilde doen)

Meestal gebruik je gewoon functies ...


43
2018-04-10 16:00



Statische methoden in Python?

Is het mogelijk om statische methoden in Python te gebruiken, zodat ik ze kan bellen   zonder een klasse te initialiseren, zoals:

ClassName.StaticMethod()

Ja, statische methoden kunnen op deze manier worden gemaakt (hoewel het een beetje meer is pythonic om underscores te gebruiken in plaats van CamelCase voor methoden):

class ClassName(object):

    @staticmethod
    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

Het bovenstaande gebruikt de syntaxis van de decorator. Deze syntaxis is gelijk aan

class ClassName(object):

    def static_method(kwarg1=None):
        '''return a value that is a function of kwarg1'''

    static_method = staticmethod(static_method)

Dit kan worden gebruikt zoals u hebt beschreven:

ClassName.static_method()

Een ingebouwd voorbeeld van een statische methode is str.maketrans() in Python 3, wat een functie was in de string module in Python 2.


Een andere optie die kan worden gebruikt zoals u beschrijft, is de classmethod, het verschil is dat de klassemethode de klasse als een impliciet eerste argument krijgt en bij subklassen de subklasse als het impliciete eerste argument krijgt.

class ClassName(object):

    @classmethod
    def class_method(cls, kwarg1=None):
        '''return a value that is a function of the class and kwarg1'''

Let daar op cls is geen vereiste naam voor het eerste argument, maar de meeste ervaren Python-codeerders zullen het als slecht beschouwen als u iets anders gebruikt.

Deze worden meestal gebruikt als alternatieve constructors.

new_instance = ClassName.class_method()

Een ingebouwd voorbeeld is dict.fromkeys():

new_dict = dict.fromkeys(['key1', 'key2'])

28
2018-01-24 04:34



Afgezien van de bijzonderheden van hoe statische methode-objecten je gedragen, er is een bepaalde schoonheid die je met hen kunt inslaan als het gaat om het organiseren van je code op moduleniveau.

# garden.py
def trim(a):
    pass

def strip(a):
    pass

def bunch(a, b):
    pass

def _foo(foo):
    pass

class powertools(object):
    """
    Provides much regarded gardening power tools.
    """
    @staticmethod
    def answer_to_the_ultimate_question_of_life_the_universe_and_everything():
        return 42

    @staticmethod
    def random():
        return 13

    @staticmethod
    def promise():
        return True

def _bar(baz, quux):
    pass

class _Dice(object):
    pass

class _6d(_Dice):
    pass

class _12d(_Dice):
    pass

class _Smarter:
    pass

class _MagicalPonies:
    pass

class _Samurai:
    pass

class Foo(_6d, _Samurai):
    pass

class Bar(_12d, _Smarter, _MagicalPonies):
    pass

...

# tests.py
import unittest
import garden

class GardenTests(unittest.TestCase):
    pass

class PowertoolsTests(unittest.TestCase):
    pass

class FooTests(unittest.TestCase):
    pass

class BarTests(unittest.TestCase):
    pass

...

# interactive.py
from garden import trim, bunch, Foo

f = trim(Foo())
bunch(f, Foo())

...

# my_garden.py
import garden
from garden import powertools

class _Cowboy(garden._Samurai):
    def hit():
        return powertools.promise() and powertools.random() or 0

class Foo(_Cowboy, garden.Foo):
    pass

Het wordt nu een beetje meer intuïtief en zelfdocumenterend in welke context bepaalde componenten bedoeld zijn om te gebruiken en het is ideaal om verschillende testgevallen te benoemen en om een ​​directe benadering te hebben voor hoe testmodules toewijzen aan feitelijke modules die getest worden voor puristen .

Ik vind het vaak haalbaar om deze benadering toe te passen bij het organiseren van de projectcode van een project. Heel vaak haasten mensen zich en creëren een utils pakket en eindigen met 9 modules waarvan er één 120 LOC heeft en de rest zijn op zijn best twee dozijn LOC's. Ik geef er de voorkeur aan om hiermee te beginnen en het om te zetten naar een pakket en modules te maken voor de beesten die ze echt verdienen:

# utils.py
class socket(object):
    @staticmethod
    def check_if_port_available(port):
        pass

    @staticmethod
    def get_free_port(port)
        pass

class image(object):
    @staticmethod
    def to_rgb(image):
        pass

    @staticmethod
    def to_cmyk(image):
        pass

9
2017-12-29 19:47



Misschien is de eenvoudigste optie gewoon om die functies buiten de klas te houden:

class Dog(object):
    def __init__(self, name):
        self.name = name

    def bark(self):
        if self.name == "Doggy":
            return barking_sound()
        else:
            return "yip yip"

def barking_sound():
    return "woof woof"

Met behulp van deze methode kunnen functies die de interne objectstatus wijzigen of gebruiken (bijwerkingen hebben) in de klasse worden bewaard en kunnen de herbruikbare hulpprogramma-functies naar buiten worden verplaatst.

Laten we zeggen dat dit bestand wordt genoemd dogs.py. Om deze te gebruiken, zou je bellen dogs.barking_sound() in plaats van dogs.Dog.barking_sound.

Als je echt een statische methode nodig hebt om deel uit te maken van de klas, kun je de staticmethod decorateur.


7
2017-07-30 16:10