Có thể có các phương thức tĩnh trong Python mà tôi có thể gọi mà không cần khởi tạo một lớp, như:
ClassName.static_method()
Có thể có các phương thức tĩnh trong Python mà tôi có thể gọi mà không cần khởi tạo một lớp, như:
ClassName.static_method()
Câu trả lời:
Đúng, sử dụng trang trí tĩnh
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 thức cũ để xác định phương thức tĩnh, sử dụng staticmethod
như một hàm thay vì 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
), chỉ là không sử dụng cú pháp trang trí đẹp
Cuối cùng, sử dụng một staticmethod()
cách tiết kiệm! Có rất ít tình huống trong đó 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 ẩn. Để 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, ...): ...
Biểu mẫu @staticmethod là một trình trang trí hàm - xem mô tả về các định nghĩa hàm trong các định nghĩa hàm để biết chi tiết.
Nó có thể được gọi hoặc trên lớp (chẳng hạn
C.f()
) hoặc trên một thể hiện (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 ++. Đối với một khái niệm cao cấp hơn, 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 loại tiêu chuẩn trong Phân cấp loại tiêu chuẩn .
Mới trong phiên bản 2.2.
Thay đổi trong phiên bản 2.4: Đã thêm cú pháp trang trí chức năng.
ClassName.methodName()
như thể nó là phương thức tĩnh, và sau đó self
sẽ không được cung cấp cho phương thức. Như bạn đã nói, vẫn có thể gọi phương thức này là ClassInstance.methodName()
và self
sẽ được cung cấp làm tham số đầu tiên, bất kể tên của nó là gì.
Tôi nghĩ rằng Steven thực sự đúng . Sau đó, để trả lời câu hỏi ban đầu, để thiết lập một phương thức lớp, chỉ cần giả sử rằng đối số đầu tiên sẽ không phải 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 cách 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 thể hiện (vì nó sẽ được gọi bởi một thể hiện thay vì một lớp). Miễn là "rollCall" được gọi từ lớp chứ không phải là một thể hiện, mã sẽ hoạt động tốt. Nếu chúng ta cố gắng gọi "rollCall" từ một ví dụ, ví dụ:
rex.rollCall(-1)
tuy nhiên, nó sẽ khiến một ngoại lệ được đưa ra bởi vì nó sẽ gửi hai đối số: chính nó và -1 và "rollCall" chỉ được xác định để chấp nhận một đối số.
Ngẫu nhiên, rex.rollCall () sẽ gửi đúng số lượng đối số, nhưng cũng sẽ gây ra ngoại lệ vì bây giờ n sẽ đại diện cho một thể hiện Dog (tức là rex) khi hàm dự kiến n là số.
Đây là nơi trang trí xuất hiện: Nếu chúng ta đi trước phương thức "rollCall" với
@staticmethod
sau đó, bằng cách nói rõ rằng phương thức này là tĩnh, chúng ta thậm chí có thể gọi nó từ một thể hiện. Hiện nay,
rex.rollCall(-1)
sẽ làm việc Việc chèn @staticmethod trước một định nghĩa phương thức, sau đó, ngăn một cá thể 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ử đoạn 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)
TypeError: unbound method rollCall() must be called with Dog instance as first argument (got int instance instead)
T.my_static_method()
hoặc type(my_t_instance).my_static_method()
, vì điều này rõ ràng hơn và rõ ràng rằng tôi đang gọi một phương thức tĩnh.
Có, hãy kiểm tra trang trí tĩnh :
>>> class C:
... @staticmethod
... def hello():
... print "Hello World"
...
>>> C.hello()
Hello World
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ỉ ở đó trong trường hợp bạn muốn có thể gọi nó từ một ví dụ (đó không phải là điều bạn muốn làm)
Hầu hết, bạn chỉ sử dụng các chức năng mặc dù ...
class Dummy: def static1(): print "hello from static1" @staticmethod def static2(): print "hello from static2" Dummy.static2() Dummy.static1()
Kết quả: xin chào từ static2 TracBack <cuộc gọi gần đây nhất>: Tệp "ll.py", dòng 46, trong <module> Dummy.static1 () TypeError: phương thức không gắn kết static1 () phải là được gọi với ví dụ Dummy là đối số đầu tiên (không có gì thay thế)
self
như là đối số đầu tiên trừ khi bạn nói không. (xem: trang trí)
self
ref thích hợp tùy thuộc vào cách gọi của nó. Trường hợp thử nghiệm: pastebin.com/12DDV7DB .
staticmethod
trang trí cho phép một người gọi hàm trên cả lớp và một thể hiện (giải pháp này không thành công khi gọi hàm trên một thể hiện).
class C: def callme(): print('called'); C.callme()
Các phương thức 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 cần 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 như thế này (mặc dù Pythonic sử dụng dấu gạch dưới thay vì CamelCase nhiều hơn một chút ):
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 như bạn mô tả là classmethod
, sự khác biệt là classmethod lấy lớp làm đối số đầu tiên ẩn và nếu được phân lớp, thì nó sẽ nhận lớp con làm đối số đầu tiên ẩn.
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à một 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 nó được thực hiện tồi nếu bạn sử dụng bất cứ điều gì khác.
Chúng thường được sử dụng như là các nhà xây dựng thay thế.
new_instance = ClassName.class_method()
Một ví dụ dựng sẵn là dict.fromkeys()
:
new_dict = dict.fromkeys(['key1', 'key2'])
Ngoài các đặc thù về cách các đối tượng phương thức tĩnh hoạt động, có một loại vẻ đẹp nhất định mà bạn có thể tấn công với chúng 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 hơn và tự ghi lại tài liệu trong đó bối cảnh một số thành phần được sử dụng và nó giải thích lý tưởng cho việc đặt tên 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 về cách các mô-đun thử nghiệm ánh xạ tới các mô-đun thực tế trong các thử nghiệm cho người theo chủ nghĩa thuần túy .
Tôi thường thấy khả thi khi áp dụng phương pháp này để tổ chức mã tiện ích của dự án. Rất thường xuyên, mọi người ngay lập tức vội vàng và tạo ra một utils
gói và kết thúc với 9 mô-đun trong đó một mô-đun có 120 LỘC và phần còn lại là hai chục LỘC 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à chỉ tạo các mô-đun cho những con thú thực 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
Có lẽ tùy chọn đơn giản nhất là đặ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 bên trong (có tác dụ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 chuyển ra bên ngoài.
Hãy nói rằng tập tin 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 là một phần của lớp, bạn có thể sử dụng trình trang trí tĩnh .
Vì vậy, các phương thức tĩnh là các phương thức có thể được gọi mà không tạo đối tượng của một lớp. Ví dụ :-
@staticmethod
def add(a, b):
return a + b
b = A.add(12,12)
print b
Trong ví dụ trên, phương thức add
được gọi bởi tên lớp A
chứ không phải tên đối tượng.
Các phương thức tĩnh của Python có thể được tạo theo hai cách.
Sử dụng tĩnh điện ()
class Arithmetic:
def add(x, y):
return x + y
# create add static method
Arithmetic.add = staticmethod(Arithmetic.add)
print('Result:', Arithmetic.add(15, 10))
Đầu ra:
Kết quả: 25
Sử dụng @staticmethod
class Arithmetic:
# create add static method
@staticmethod
def add(x, y):
return x + y
print('Result:', Arithmetic.add(15, 10))
Đầu ra:
Kết quả: 25
Tôi gặp 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']
>>>
Không có nghĩa gì khi tạo 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à một tập hợp các phương thức có liên quan theo một cách nào đó. Trong ví dụ của tôi ở trên, tất cả các hàm trong cmath hoạt động trên các số phức theo một cách nào đó.
@staticmethod
trang trí hoặc sử dụng một con trỏ hàm, khi bạn chỉ cần tránhself
tham số đầu tiên ? Chà, đối với một đối tượnga
, bạn sẽ không thể gọia.your_static_method()
, được phép sử dụng trong các ngôn ngữ khác, nhưng dù sao nó cũng bị coi là một thực tiễn xấu và trình biên dịch luôn cảnh báo về điều đó