Câu hỏi Phương pháp tĩnh trong Python?


Có thể có các phương thức tĩnh trong Python để tôi có thể gọi chúng mà không khởi tạo một lớp, như:

ClassName.StaticMethod ( )

1392
2018-04-09 21:23


gốc




Các câu trả lời:


Đúng, bằng cách sử dụng staticmethod người trang trí

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

MyClass.the_static_method(2) # outputs 2

Lưu ý rằng một số mã có thể sử dụng phương pháp cũ để xác định phương thức tĩnh, sử dụng staticmethod như một chức năng hơn là một trang trí. Điều này chỉ nên được sử dụng nếu bạn phải hỗ trợ các phiên bản Python cũ (2.2 và 2.3)

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

MyClass.the_static_method(2) # outputs 2

Điều này hoàn toàn giống với ví dụ đầu tiên (sử dụng @staticmethod), không sử dụng cú pháp trang trí đẹp

Cuối cùng, sử dụng staticmethod() một cách tiết kiệm! Có rất ít tình huống mà các phương thức tĩnh là cần thiết trong Python, và tôi đã thấy chúng được sử dụng nhiều lần trong đó một hàm "cấp cao nhất" riêng biệt sẽ rõ ràng hơn.


Sau đây là nguyên văn từ tài liệu::

Một phương thức tĩnh không nhận được một đối số đầu tiên ngầm định. Để khai báo một phương thức tĩnh, sử dụng thành ngữ này:

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

Dạng @staticmethod là một hàm người trang trí - xem mô tả các định nghĩa hàm trong Định nghĩa chức năng để biết chi tiết.

Nó có thể được gọi là trên lớp (chẳng hạn như C.f()) hoặc trên một cá thể (chẳng hạn như C().f()). Ví dụ được bỏ qua ngoại trừ lớp của nó.

Các phương thức tĩnh trong Python tương tự như các phương thức được tìm thấy trong Java hoặc C ++. Để có khái niệm nâng cao hơn, hãy xem classmethod().

Để biết thêm thông tin về các phương thức tĩnh, hãy tham khảo tài liệu về phân cấp kiểu tiêu chuẩn trong Phân cấp loại tiêu chuẩn.

Tính năng mới trong phiên bản 2.2.

Thay đổi trong phiên bản 2.4: Cú pháp trang trí hàm được thêm vào.


1699
2018-04-09 21:24



Tại sao thêm @staticmethod trang trí hoặc sử dụng con trỏ hàm, khi bạn có thể đơn giản tránh self tham số? Vâng, đối với một đối tượng a, bạn sẽ không thể gọi a.your_static_method(), được cho phép trong các ngôn ngữ khác, nhưng nó được coi là một thực hành không tốt và trình biên dịch luôn cảnh báo về nó - SomethingSomething
Tôi đang sử dụng python 2.7.12, với trang trí @staticmethod tôi không thể gọi phương thức tĩnh đầu tiên được xác định. Lỗi givin của nó: TypeError: đối tượng 'staticmethod' không thể gọi - Supratim Samantray
Supratim Samantray, bạn có chắc không? bởi vì đây rõ ràng là nó có thể được sử dụng sau 2.4. - realslimshanky


tôi nghĩ vậy Steven thực sự đúng. Để trả lời câu hỏi ban đầu, sau đó, để thiết lập một phương thức lớp, chỉ cần giả định rằng đối số đầu tiên sẽ không là một cá thể gọi, và sau đó đảm bảo rằng bạn chỉ gọi phương thức từ lớp đó.

(Lưu ý rằng câu trả lời này đề cập đến Python 3.x. Trong Python 2.x bạn sẽ nhận được một TypeError để gọi phương thức trên chính lớp đó.)

Ví dụ:

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)

Trong mã này, phương thức "rollCall" giả định rằng đối số đầu tiên không phải là một cá thể (vì nó sẽ là nếu nó được gọi bởi một cá thể thay vì một lớp). Miễn là "rollCall" được gọi từ lớp chứ không phải là một cá thể, mã sẽ hoạt động tốt. Nếu chúng tôi cố gắng gọi "rollCall" từ một ví dụ, ví dụ:

rex.rollCall(-1)

tuy nhiên, nó sẽ gây ra một ngoại lệ được nâng lên vì nó sẽ gửi hai đối số: chính nó và -1, và "rollCall" chỉ được định nghĩa để chấp nhận một đối số.

Ngẫu nhiên, rex.rollCall () sẽ gửi số lượng đối số chính xác, nhưng cũng sẽ gây ra một ngoại lệ được nâng lên vì bây giờ n sẽ đại diện cho một cá thể Dog (tức là rex) khi hàm mong đợi n là số.

Đây là nơi trang trí đến: Nếu chúng ta đứng trước phương thức "rollCall" với

@staticmethod

sau đó, bằng cách nói rõ rằng phương thức là tĩnh, chúng ta thậm chí có thể gọi nó từ một cá thể. Hiện nay,

rex.rollCall(-1)

sẽ hoạt động. Việc chèn @staticmethod trước một định nghĩa phương thức, sau đó, dừng một cá thể từ việc gửi chính nó làm đối số.

Bạn có thể xác minh điều này bằng cách thử mã sau có và không có dòng @staticmethod đã nhận xét.

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



Ví dụ đầu tiên (gọi bởi lớp không có @staticmethod) không hoạt động đối với tôi trên Python 2.7. Tôi nhận được "TypeError: unbound method rollCall () phải được gọi với ví dụ Dog là đối số đầu tiên (có int instance thay thế)" - tba
Điều này không hoạt động. Cả hai Dog.rollCall (-1) và rex.rollCall (-1) trả về cùng TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead) - Mittenchops
@MestreLion Tôi nghĩ rằng đây không phải là một lợi ích to lớn, vì tất cả những gì nó làm là lộn xộn lên các phương thức tĩnh và dụ và làm cho một cái nhìn giống như cái kia. Nếu bạn biết một phương thức là tĩnh, bạn nên truy cập nó như một phương thức tĩnh. Thực tế là phương pháp không cần hoặc sử dụng thể hiện của bạn nên tự hiển nhiên ở bất cứ nơi nào bạn sử dụng phương pháp. Tôi luôn sử dụng T.my_static_method() hoặc là type(my_t_instance).my_static_method(), vì điều này là rõ ràng hơn và làm cho nó ngay lập tức rõ ràng rằng tôi đang gọi một phương pháp tĩnh. - Asad Saeeduddin


Có, hãy xem staticmethod trang trí:

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

74
2018-04-09 21:24





Bạn không thực sự cần phải sử dụng @staticmethod trang trí. Chỉ cần khai báo một phương thức (không mong đợi tham số tự) và gọi nó từ lớp đó. Trình trang trí chỉ có trong trường hợp bạn muốn có thể gọi nó từ một cá thể (cũng không phải là những gì bạn muốn làm)

Chủ yếu, bạn chỉ cần sử dụng các hàm mặc dù ...


43
2018-04-10 16:00



Hoặc điều này không hiệu quả, hoặc không rõ ý bạn là gì. Tôi sẽ xóa bỏ phiếu giảm giá của tôi nếu một ví dụ làm việc được đăng. - Eric Wilson
Điều này không làm việc, mặc dù nó sẽ có ý nghĩa rằng nó nên. Con trăn ngớ ngẩn ...;) - weberc2
Điều này không hoạt động bên trong một lớp học. Python sẽ vượt qua self làm đối số đầu tiên trừ khi bạn không nói. (xem: trang trí) - Navin
Trên thực tế điều này là sai trong 2,7 và hợp pháp như của 3.X (thử nghiệm tốt trong 3,2). Đó là bạn không thể gọi một phương thức từ ngữ cảnh của một lớp mà không có trình trang trí @staticmethod trong 2.7 và dưới đây. Trong 3.2 nó hoạt động và sẽ chèn một self ref một cách thích hợp tùy thuộc vào cách gọi của nó. Kiểm tra trường hợp: pastebin.com/12DDV7DB. - spinkus
Về mặt kỹ thuật chính xác, nhưng là một giải pháp khủng khiếp. Các staticmethod decorator cho phép người ta gọi hàm trên cả lớp và một cá thể (giải pháp này thất bại khi gọi hàm trên một cá thể). - Ethan Furman


Phương pháp tĩnh trong Python?

Có thể có các phương thức tĩnh trong Python để tôi có thể gọi chúng   mà không khởi tạo một lớp, như:

ClassName.StaticMethod()

Có, các phương thức tĩnh có thể được tạo ra như thế này (mặc dù nó có nhiều hơn một chút Pythonic để sử dụng dấu gạch dưới thay vì CamelCase cho các phương thức):

class ClassName(object):

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

Ở trên sử dụng cú pháp trang trí. Cú pháp này tương đương với

class ClassName(object):

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

    static_method = staticmethod(static_method)

Điều này có thể được sử dụng như bạn đã mô tả:

ClassName.static_method()

Một ví dụ dựng sẵn của một phương thức tĩnh là str.maketrans() trong Python 3, là một hàm trong string mô-đun trong Python 2.


Một tùy chọn khác có thể được sử dụng khi bạn mô tả là classmethod, sự khác biệt là classmethod được lớp như là một đối số đầu tiên tiềm ẩn, và nếu được phân lớp, thì nó sẽ nhận được lớp con làm đối số đầu tiên ngầm định.

class ClassName(object):

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

Lưu ý rằng cls không phải là tên bắt buộc cho đối số đầu tiên, nhưng hầu hết các lập trình viên Python có kinh nghiệm sẽ xem xét việc thực hiện nó nếu bạn sử dụng bất kỳ thứ gì khác.

Đây thường được sử dụng như là các nhà thầu thay thế.

new_instance = ClassName.class_method()

Ví dụ dựng sẵn là dict.fromkeys():

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

28
2018-01-24 04:34





Ngoài những đặc thù của cách đối tượng phương thức tĩnh hành xử, có một loại vẻ đẹp nhất định mà bạn có thể tấn công với họ khi nói đến việc tổ chức mã cấp mô-đun của bạn.

# 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

Bây giờ nó trở nên trực quan và tự tạo tài liệu hơn một chút trong bối cảnh các thành phần nhất định được sử dụng và nó lý tưởng cho việc đặt tên cho các trường hợp thử nghiệm riêng biệt cũng như có cách tiếp cận đơn giản. .

Tôi thường xuyên tìm thấy nó khả thi để áp dụng cách tiếp cận này để tổ chức một mã số tiện ích của dự án. Khá thường xuyên, mọi người ngay lập tức đổ xô và tạo ra utils gói và kết thúc với 9 mô-đun trong đó một có 120 LOC và phần còn lại là hai chục LOC ở tốt nhất. Tôi thích bắt đầu với điều này và chuyển đổi nó thành một gói và tạo ra các mô-đun chỉ cho những con thú thật sự xứng đáng với chúng:

# 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





Có lẽ tùy chọn đơn giản nhất là chỉ cần đặt các hàm đó bên ngoài lớp:

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"

Sử dụng phương thức này, các hàm sửa đổi hoặc sử dụng trạng thái đối tượng nội bộ (có các hiệu ứng phụ) có thể được giữ trong lớp và các hàm tiện ích có thể sử dụng lại có thể được di chuyển ra ngoài.

Giả sử tệp này được gọi dogs.py. Để sử dụng chúng, bạn sẽ gọi dogs.barking_sound() thay vì dogs.Dog.barking_sound.

Nếu bạn thực sự cần một phương thức tĩnh để trở thành một phần của lớp, bạn có thể sử dụng staticmethod trang trí.


8
2017-07-30 16:10





Tôi gặp phải câu hỏi này theo thời gian. Trường hợp sử dụng và ví dụ mà tôi thích là:

jeffs@jeffs-desktop:/home/jeffs  $ python36
Python 3.6.1 (default, Sep  7 2017, 16:36:03) 
[GCC 6.3.0 20170406] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cmath
>>> print(cmath.sqrt(-4))
2j
>>>
>>> dir(cmath)
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj', 'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj', 'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']
>>> 

Nó không có ý nghĩa để tạo ra một đối tượng của lớp cmath, bởi vì không có trạng thái trong một đối tượng cmath. Tuy nhiên, cmath là tập hợp các phương thức tất cả có liên quan theo một cách nào đó. Trong ví dụ trên, tất cả các hàm trong hành vi cmath trên các số phức trong một số cách.


-1
2018-01-08 06:53