Mục đích của phương pháp lớp là gì?


250

Tôi đang tự học Python và bài học gần đây nhất của tôi là Python không phải là Java và vì vậy tôi đã dành một lúc để biến tất cả các phương thức Class của mình thành các hàm.

Bây giờ tôi nhận ra rằng tôi không cần sử dụng các phương thức Class cho những gì tôi sẽ làm với staticcác phương thức trong Java, nhưng bây giờ tôi không chắc chắn khi nào tôi sẽ sử dụng chúng. Tất cả các lời khuyên tôi có thể tìm thấy về các phương thức Lớp Python là cùng với những người mới như tôi nên tránh xa chúng, và tài liệu chuẩn là không rõ ràng nhất khi thảo luận về chúng.

Có ai có một ví dụ hay về việc sử dụng một phương thức Class trong Python hoặc ít nhất ai đó có thể cho tôi biết khi nào các phương thức Class có thể được sử dụng hợp lý không?

Câu trả lời:


178

Các phương thức lớp là khi bạn cần có các phương thức không cụ thể cho bất kỳ trường hợp cụ thể nào, nhưng vẫn liên quan đến lớp theo một cách nào đó. Điều thú vị nhất về chúng là chúng có thể bị ghi đè bởi các lớp con, điều mà đơn giản là không thể có trong các phương thức tĩnh của Java hoặc các hàm cấp mô-đun của Python.

Nếu bạn có một lớp MyClassvà một hàm cấp mô-đun hoạt động trên MyClass (nhà máy, cuống tiêm phụ thuộc, v.v.), hãy làm cho nó một classmethod. Sau đó, nó sẽ có sẵn cho các lớp con.


Tôi hiểu rồi. Nhưng, nếu tôi chỉ muốn phân loại một phương thức, thì điều đó không cần MyClass, nhưng theo một cách nào đó có ý nghĩa nếu tôi nhóm trong MyClass khác? Tôi có thể nghĩ đến việc chuyển nó sang mô đun trợ giúp mặc dù ..
swdev

Tôi có một câu hỏi liên quan đến câu hỏi gốc, có lẽ bạn có thể trả lời cùng một lúc không? Cách gọi phương thức lớp nào của một đối tượng là "tốt hơn" hay "thành ngữ hơn": obj.cls_mthd(...)hay type(obj).cls_mthd(...)?
Alexey

63

Các phương thức nhà máy (các hàm tạo thay thế) thực sự là một ví dụ cổ điển về các phương thức lớp.

Về cơ bản, các phương thức lớp phù hợp bất cứ lúc nào bạn muốn có một phương thức tự nhiên phù hợp với không gian tên của lớp, nhưng không được liên kết với một thể hiện cụ thể của lớp.

Ví dụ, trong mô-đun unipath xuất sắc :

Thư mục hiện tại

  • Path.cwd()
    • Trả về thư mục hiện tại thực tế; ví dụ Path("/tmp/my_temp_dir"). Đây là một phương pháp lớp.
  • .chdir()
    • Tạo cho mình thư mục hiện tại.

Vì thư mục hiện tại là quá trình rộng, cwdphương thức không có trường hợp cụ thể nào nên được liên kết. Tuy nhiên, việc thay đổi cwdthư mục của một Paththể hiện cụ thể thực sự phải là một phương thức thể hiện.

Hmmm ... Path.cwd()thực sự trả về một Pathví dụ, tôi đoán nó có thể được coi là một phương thức xuất xưởng ...


1
Vâng ... phương pháp nhà máy là điều đầu tiên xuất hiện trong tâm trí. Cũng dọc theo những dòng đó là những thứ sẽ triển khai một mẫu Singleton, như: getAndOptionallyCreateSomeSingleInstanceOfSomeResource ()
Jemenake

3
Trong python, đó là các phương thức tĩnh, không phải phương thức lớp.
Jaykul

46

Nghĩ về nó theo cách này: các phương thức bình thường rất hữu ích để ẩn các chi tiết của công văn: bạn có thể gõ myobj.foo()mà không cần lo lắng về việc foo()phương thức được thực hiện bởi myobjlớp của đối tượng hay một trong các lớp cha của nó. Các phương thức lớp hoàn toàn giống với phương thức này, nhưng với đối tượng lớp thay vào đó: chúng cho phép bạn gọi MyClass.foo()mà không phải lo lắng về việc có foo()được triển khai đặc biệt hay không bởi MyClassvì nó cần phiên bản chuyên biệt của riêng nó, hoặc liệu nó có để cho lớp cha của nó xử lý cuộc gọi hay không.

Các phương thức lớp là rất cần thiết khi bạn đang thực hiện thiết lập hoặc tính toán trước khi tạo một cá thể thực tế, bởi vì cho đến khi cá thể tồn tại, rõ ràng bạn không thể sử dụng cá thể làm điểm gửi cho các lệnh gọi phương thức của bạn. Một ví dụ tốt có thể được xem trong mã nguồn SQLAlchemy; hãy xem dbapi()phương thức lớp ở liên kết sau:

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

Bạn có thể thấy rằng dbapi()phương thức mà phụ trợ cơ sở dữ liệu sử dụng để nhập thư viện cơ sở dữ liệu cụ thể của nhà cung cấp mà nó cần theo yêu cầu, là một phương thức lớp vì nó cần chạy trước khi các phiên bản của một kết nối cơ sở dữ liệu cụ thể bắt đầu được tạo - nhưng không thể là một hàm đơn giản hoặc hàm tĩnh, bởi vì họ muốn nó có thể gọi các phương thức hỗ trợ khác, có thể cần phải được viết cụ thể hơn trong các lớp con so với trong lớp cha của chúng. Và nếu bạn gửi đến một hàm hoặc lớp tĩnh, thì bạn "quên" và mất kiến ​​thức về lớp nào đang thực hiện việc khởi tạo.


Liên kết bị hỏng, vui lòng điều chỉnh
piertoni

28

Gần đây tôi muốn có một lớp ghi nhật ký rất nhẹ sẽ tạo ra số lượng đầu ra khác nhau tùy thuộc vào mức ghi có thể được thiết lập theo chương trình. Nhưng tôi không muốn khởi tạo lớp mỗi lần tôi muốn xuất thông báo gỡ lỗi hoặc lỗi hoặc cảnh báo. Nhưng tôi cũng muốn gói gọn chức năng của cơ sở khai thác gỗ này và làm cho nó có thể tái sử dụng mà không cần tuyên bố của bất kỳ toàn cầu nào.

Vì vậy, tôi đã sử dụng các biến lớp và trình @classmethodtrang trí để đạt được điều này.

Với lớp Ghi nhật ký đơn giản của tôi, tôi có thể làm như sau:

Logger._level = Logger.DEBUG

Sau đó, trong mã của tôi, nếu tôi muốn phun ra một loạt thông tin gỡ lỗi, tôi chỉ cần mã hóa

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

Lỗi có thể được đưa ra với

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

Trong môi trường "sản xuất", tôi có thể chỉ định

Logger._level = Logger.ERROR

và bây giờ, chỉ có thông báo lỗi sẽ được xuất ra. Thông báo gỡ lỗi sẽ không được in.

Đây là lớp học của tôi:

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

Và một số mã kiểm tra nó chỉ là một chút:

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()

10
Điều này không có vẻ với tôi như phương pháp dụ lớp tốt là tốt cho vì nó có thể có tất cả được thực hiện theo một cách ít phức tạp hơn bằng cách chỉ làm cho tất cả các phương thức lớp chức năng mô-đun cấp và với việc từ bỏ lớp hoàn toàn.
martineau

10
Ồ, thậm chí quan trọng hơn, Python cung cấp một lớp ghi nhật ký rất đơn giản để sử dụng. Vì vậy, tệ hơn là tạo ra một giải pháp ít hơn tối ưu, tôi đã phát minh lại bánh xe. Tát tay đôi. Nhưng nó cung cấp một ví dụ làm việc, ít nhất. Tuy nhiên, không chắc chắn tôi đồng ý với việc thoát khỏi lớp học, ở cấp độ khái niệm. Đôi khi bạn muốn đóng gói mã để dễ sử dụng lại và phương thức ghi nhật ký là mục tiêu tuyệt vời để sử dụng lại.
Marvo

3
Tại sao bạn không sử dụng tĩnh điện?
bdforbes


11

Khi người dùng đăng nhập vào trang web của tôi, một đối tượng Người dùng () sẽ được khởi tạo ngay từ tên người dùng và mật khẩu.

Nếu tôi cần một đối tượng người dùng mà không có người dùng ở đó để đăng nhập (ví dụ: người dùng quản trị có thể muốn xóa tài khoản người dùng khác, vì vậy tôi cần khởi tạo người dùng đó và gọi phương thức xóa của nó):

Tôi có các phương thức lớp để lấy đối tượng người dùng.

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()

9

Tôi nghĩ câu trả lời rõ ràng nhất là câu trả lời của AmanKow . Nó nắm rõ cách bạn muốn tổ chức mã của mình. Bạn có thể viết mọi thứ dưới dạng các hàm cấp mô-đun được gói trong không gian tên của mô-đun tức là

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()

Mã thủ tục trên không được tổ chức tốt, vì bạn có thể thấy chỉ sau 3 mô-đun, nó bị lẫn lộn, mỗi phương thức làm gì? Bạn có thể sử dụng tên mô tả dài cho các hàm (như trong java) nhưng mã của bạn vẫn không thể quản lý được rất nhanh.

Cách hướng đối tượng là chia mã của bạn thành các khối có thể quản lý, tức là Lớp & đối tượng và hàm có thể được liên kết với các thể hiện đối tượng hoặc với các lớp.

Với các hàm lớp, bạn có được một mức phân chia khác trong mã của mình so với các hàm cấp mô-đun. Vì vậy, bạn có thể nhóm các hàm liên quan trong một lớp để làm cho chúng cụ thể hơn với một tác vụ mà bạn đã gán cho lớp đó. Ví dụ: bạn có thể tạo một lớp tiện ích tệp:

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")

Cách này linh hoạt hơn và dễ bảo trì hơn, bạn nhóm các chức năng lại với nhau và rõ ràng hơn với những gì mỗi chức năng làm. Ngoài ra, bạn ngăn ngừa xung đột tên, ví dụ, sao chép chức năng có thể tồn tại trong một mô-đun đã nhập khác (ví dụ: sao chép mạng) mà bạn sử dụng trong mã của mình, vì vậy khi bạn sử dụng tên đầy đủ FileUtil.copy (), bạn sẽ xóa vấn đề và cả hai chức năng sao chép có thể được sử dụng cạnh nhau.


1
Để sử dụng F1 (), f2 (), v.v., như bạn đã làm, bạn không nên sử dụng từ nhập mô-đun * và từ nhập sử dụng *?
Jblasco

@Jblasco Tôi đã sửa các câu lệnh nhập để loại bỏ sự nhầm lẫn, vâng, nếu bạn nhập mô-đun, bạn phải thêm tiền tố vào các hàm với tên mô-đun. tức là mô-đun nhập -> module.f1 () vv
firephil

Tôi không đồng ý với câu trả lời này; Python không phải là Java. Vấn đề về mã không thể quản lý chỉ rõ ràng phát sinh do sự lựa chọn có chủ ý của các tên nghèo trong ví dụ. Thay vào đó, nếu bạn sao chép các FileUtilphương thức lớp dưới dạng các chức năng của một file_utilmô-đun, nó sẽ có thể so sánh và không lạm dụng OOP khi không có đối tượng thực sự tồn tại (thực sự bạn có thể tranh luận rằng nó là tốt hơn, bởi vì bạn không kết thúc với from file_util import FileUtilhoặc tính dài dòng khác). Xung đột tên có thể được tránh tương tự trong mã thủ tục bằng cách thực hiện import file_utilthay vì from file_util import ....
Quên đi,

7

Thành thật? Tôi chưa bao giờ tìm thấy việc sử dụng cho tĩnh điện hoặc phân loại. Tôi vẫn chưa thấy một hoạt động không thể được thực hiện bằng cách sử dụng một hàm toàn cục hoặc một phương thức cá thể.

Sẽ khác nếu python sử dụng các thành viên riêng tư và được bảo vệ giống như Java. Trong Java, tôi cần một phương thức tĩnh để có thể truy cập các thành viên riêng của một cá thể để làm công cụ. Trong Python, điều đó hiếm khi cần thiết.

Thông thường, tôi thấy mọi người sử dụng staticmethod và classmethod khi tất cả những gì họ thực sự cần làm là sử dụng không gian tên cấp mô-đun của python tốt hơn.


1
Riêng tư: _variable_name và được bảo vệ: __variable_name
Bradley Kreider

1
Một ứng dụng không thể thiếu là setUpClass và tornDownClass của unittest . Bạn đang sử dụng unittests, phải không? :)
dbn

7

Nó cho phép bạn viết các phương thức lớp chung mà bạn có thể sử dụng với bất kỳ lớp tương thích nào.

Ví dụ:

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

class C:
    name = "tester"

C.get_name = get_name

#call it:
C.get_name()

Nếu bạn không sử dụng, @classmethodbạn có thể làm điều đó với từ khóa tự nhưng nó cần một thể hiện của Class:

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

5

Tôi đã từng làm việc với PHP và gần đây tôi đã tự hỏi mình, chuyện gì đang xảy ra với sự phân loại này? Hướng dẫn sử dụng Python rất kỹ thuật và rất ngắn gọn trong các từ vì vậy nó sẽ không giúp hiểu được tính năng đó. Tôi đã googling và googling và tôi đã tìm thấy câu trả lời -> http://code.anjanesh.net/2007/12/python- classmethods.html .

Nếu bạn lười nhấp vào nó. Giải thích của tôi ngắn hơn và dưới đây. :)

trong PHP (có thể không phải tất cả các bạn đều biết PHP, nhưng ngôn ngữ này rất đơn giản để mọi người hiểu những gì tôi đang nói) chúng ta có các biến tĩnh như thế này:


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();

Đầu ra sẽ trong cả hai trường hợp 20.

Tuy nhiên, trong python, chúng ta có thể thêm trang trí @ classmethod và do đó có thể có đầu ra 10 và 20 tương ứng. Thí dụ:


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()

Thông minh, phải không?


Một vấn đề tiềm ẩn với ví dụ Python của bạn là nếu B.setInnerVar(20)bị bỏ sót, nó sẽ in 10hai lần (thay vì đưa ra lỗi trong lệnh gọi echoInnerBar () thứ hai mà không inner_varđược xác định.
martineau

5

Các phương thức lớp cung cấp một "đường ngữ nghĩa" (không biết thuật ngữ này được sử dụng rộng rãi) - hay "tiện lợi ngữ nghĩa".

Ví dụ: bạn có một tập hợp các lớp đại diện cho các đối tượng. Bạn có thể muốn có phương thức lớp all()hoặc find()để viết User.all()hoặc User.find(firstname='Guido'). Điều đó có thể được thực hiện bằng cách sử dụng các chức năng cấp mô-đun ...


Tất nhiên, bạn ví dụ giả định rằng lớp đang theo dõi tất cả các thể hiện của nó và có thể truy cập chúng sau khi chúng được tạo - một cái gì đó không được thực hiện tự động.
martineau

1
"Đường ngữ nghĩa" nghe có vẻ phù hợp với "đường cú pháp".
XtL

3

Điều vừa xảy ra với tôi, đến từ Ruby, đó là một phương thức lớp được gọi là và phương thức cá thể được gọi là một hàm có ý nghĩa ngữ nghĩa được áp dụng cho tham số đầu tiên của nó, được truyền âm thầm khi hàm được gọi là phương thức một đối tượng (tức là obj.meth()).

Thông thường đối tượng đó phải là một thể hiện nhưng trình @classmethod trang trí phương thức thay đổi các quy tắc để truyền một lớp. Bạn có thể gọi một phương thức lớp trên một cá thể (nó chỉ là một hàm) - đối số đầu tiên sẽ là lớp của nó.

Bởi vì nó chỉ là một hàm , nó chỉ có thể được khai báo một lần trong bất kỳ phạm vi nào (nghĩa là classđịnh nghĩa). Do đó, nếu theo sau, gây bất ngờ cho Rubyist, rằng bạn không thể có một phương thức lớp và một phương thức cá thể có cùng tên .

Xem xét điều này:

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

Bạn có thể gọi foomột ví dụ

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

Nhưng không phải trên một lớp học:

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)

Bây giờ thêm @classmethod:

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

Gọi một cá thể bây giờ vượt qua lớp của nó:

Foo().foo()
__main__.Foo

cũng như kêu gọi một lớp học:

Foo.foo()
__main__.Foo

Đó chỉ là quy ước chỉ ra rằng chúng ta sử dụng selfcho đối số đầu tiên đó trên một phương thức cá thể và clstrên một phương thức lớp. Tôi đã không sử dụng ở đây để minh họa rằng đó chỉ là một đối số. Trong Ruby, selflà một từ khóa.

Tương phản với 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>

Phương thức lớp Python chỉ là một chức năng được trang trí và bạn có thể sử dụng các kỹ thuật tương tự để tạo ra các trang trí của riêng bạn . Một phương thức được trang trí bao bọc phương thức thực (trong trường hợp @classmethodnó vượt qua đối số lớp bổ sung). Phương thức cơ bản vẫn còn đó, ẩn nhưng vẫn có thể truy cập .


chú thích: Tôi đã viết điều này sau khi một cuộc đụng độ tên giữa một lớp và phương thức cá thể khơi gợi sự tò mò của tôi. Tôi xa một chuyên gia Python và muốn bình luận nếu bất kỳ điều này là sai.


"được âm thầm truyền khi hàm được gọi là phương thức của một đối tượng" - tôi tin rằng điều này không chính xác. AFICT, không có gì là "âm thầm trôi qua" trong Python. IMO, Python hợp lý hơn nhiều so với Ruby theo nghĩa này (ngoại trừ super()). AFICT, "ma thuật" xảy ra khi một thuộc tính được đặt hoặc đọc. Cuộc gọi obj.meth(arg)trong Python (không giống như Ruby) có nghĩa đơn giản (obj.meth)(arg). Không có gì được âm thầm truyền đi bất cứ nơi nào, obj.methchỉ là một đối tượng có thể gọi được, chấp nhận một đối số ít hơn hàm mà nó được tạo.
Alexey

obj.meth, lần lượt, có nghĩa là đơn giản getattr(obj, "meth").
Alexey

Có ý nghĩa để có một câu trả lời phù hợp cho những người đến từ các ngôn ngữ phổ biến khác. Tuy nhiên, một điều còn thiếu trong cuộc trò chuyện này, liên kết nó với nhau, là khái niệm về một mô tả Python . Các hàm là các mô tả và đó là cách đối số đầu tiên "tự động" được thông qua một thể hiện khi một hàm là một thuộc tính cho lớp. Đó cũng là cách phân loại được thực hiện và triển khai python thuần được cung cấp trong HOWTO tôi liên kết. Thực tế nó cũng là một vật trang trí là một loại phụ trợ
juanpa.arrivillaga

2

Đây là một chủ đề thú vị. Tôi cho rằng đó là classmethod python hoạt động giống như một singleton chứ không phải là một nhà máy (trả về một thể hiện của một lớp). Lý do nó là một singleton là có một đối tượng chung được tạo ra (từ điển) nhưng chỉ một lần cho lớp nhưng được chia sẻ bởi tất cả các trường hợp.

Để minh họa điều này ở đây là một ví dụ. Lưu ý rằng tất cả các trường hợp có một tham chiếu đến từ điển duy nhất. Đây không phải là mô hình Nhà máy như tôi hiểu. Điều này có lẽ rất độc đáo với trăn.

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

2

Tôi đã tự hỏi mình câu hỏi tương tự vài lần. Và mặc dù những người ở đây đã cố gắng hết sức để giải thích nó, IMHO câu trả lời tốt nhất (và đơn giản nhất) tôi đã tìm thấy là mô tả về phương thức Class trong Tài liệu Python.

Ngoài ra còn có tham chiếu đến phương thức Tĩnh. Và trong trường hợp ai đó đã biết các phương thức cá thể (mà tôi giả sử), câu trả lời này có thể là phần cuối cùng để kết hợp tất cả lại với nhau ...

Chi tiết hơn và sâu hơn về chủ đề này cũng có thể được tìm thấy trong tài liệu: Hệ thống phân cấp loại tiêu chuẩn (cuộn xuống phần phương pháp Instance )


1

@classmethodcó thể hữu ích để dễ dàng khởi tạo các đối tượng của lớp đó từ các tài nguyên bên ngoài. Hãy xem xét những điều sau đây:

import settings

class SomeClass:
    @classmethod
    def from_settings(cls):
        return cls(settings=settings)

    def __init__(self, settings=None):
        if settings is not None:
            self.x = settings['x']
            self.y = settings['y']

Sau đó, trong một tập tin khác:

from some_package import SomeClass

inst = SomeClass.from_settings()

Truy cập inst.x sẽ cho giá trị tương tự như cài đặt ['x'].


0

Một lớp định nghĩa một tập hợp các trường hợp, tất nhiên. Và các phương thức của một lớp làm việc trên các cá thể. Các phương thức lớp (và các biến) là nơi chứa thông tin khác có liên quan đến tập hợp các trường hợp trên tất cả.

Ví dụ: nếu lớp của bạn xác định một tập hợp các sinh viên, bạn có thể muốn các biến hoặc phương thức của lớp xác định những thứ như tập hợp các lớp mà sinh viên có thể là thành viên của.

Bạn cũng có thể sử dụng các phương thức lớp để xác định các công cụ để làm việc trên toàn bộ tập hợp. Ví dụ: Student.all_of_em () có thể trả về tất cả các sinh viên đã biết. Rõ ràng nếu tập hợp các thể hiện của bạn có nhiều cấu trúc hơn chỉ một tập hợp, bạn có thể cung cấp các phương thức lớp để biết về cấu trúc đó. Học sinh.all_of_em (lớp = 'đàn em')

Các kỹ thuật như thế này có xu hướng dẫn đến việc lưu trữ các thành viên của tập hợp các trường hợp vào các cấu trúc dữ liệu được bắt nguồn từ các biến lớp. Bạn cần phải cẩn thận để tránh làm phiền bộ sưu tập rác sau đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.