Hướng dẫn what is dynamic method in python? - phương thức động trong python là gì?

Python sẽ cho phép bạn khai báo một chức năng trong một hàm, vì vậy bạn không phải thực hiện thủ thuật

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
2.

def __init__(self):

    def dynamo(self, arg):
        """ dynamo's a dynamic method!
        """
        self.weight += 1
        return arg * self.weight
    self.weight = 50

    setattr(self.__class__, 'dynamo', dynamo)

Nếu bạn muốn có một số phiên bản của hàm, bạn có thể đặt tất cả những thứ này vào một vòng lặp và thay đổi những gì bạn đặt tên cho chúng trong hàm

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
3:

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50

(Tôi biết đây không phải là mã tuyệt vời, nhưng nó có điểm). Theo như thiết lập tài liệu, tôi biết điều đó là có thể nhưng tôi phải tìm nó trong tài liệu.

EDIT: Bạn có thể đặt DocString qua

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
4, vì vậy bạn có thể làm điều gì đó như thế này trong cơ thể vòng lặp của bạn:: You can set the docstring via
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
4, so you could do something like this in your loop body:

dynamo.__doc__ = "Adds %s to the weight" % i

Một bản chỉnh sửa khác: Với sự giúp đỡ từ @eliben và @bobince, vấn đề đóng cửa cần được giải quyết.: With help from @eliben and @bobince, the closure problem should be solved.

Trước khi tôi bắt đầu viết mã Python, tôi đã dành phần lớn thời gian làm việc với PHP. Có một vài điều mà PHP làm cho các công dân hạng nhất cho ngôn ngữ. Một trong số đó là sự bao gồm lớp động và cái còn lại là khả năng gọi một cách tự động là một hàm.

Mặt khác, Python không làm cho một trong hai điều này dễ dàng. Có lý do chính đáng. Cả hai lớp tự động tải và các chức năng thực thi tự động nghiêng về phía phép thuật của lập trình. Mã sử ​​dụng các cuộc gọi chức năng động có thể trở nên khó hiểu rất nhanh.

Đơn giản là tốt hơn phức tạp. Phức tạp tốt hơn so với phức tạp ... số lượng dễ đọc.

Cuộc gọi chức năng động là gì?

Bạn có thể tự hỏi tôi muốn nói gì khi "tự động" gọi một hàm. Hãy xem xét một ví dụ nhanh trong PHP. Ngay cả khi bạn chưa bao giờ nhìn vào PHP, bạn sẽ có thể hiểu những gì đang xảy ra.

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15

Lưu ý: Trong ví dụ này, các khai báo loại là tùy chọn, nhưng chúng là một thực tiễn tốt.

Trong ví dụ này, hàm

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
5 có thể được gọi miễn là chúng ta biết tên của hàm, tức là
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
6. Miễn là chúng ta biết tên của chức năng chúng ta muốn gọi, chúng ta có thể thực thi chức năng và thậm chí vượt qua trong các đối số.

Đây là ý tưởng đằng sau việc thực thi chức năng động. Hàm sẽ được thực thi không được xác định khi mã được viết. Nó được xác định trong thời gian chạy.

Làm điều này trong Python phức tạp hơn một chút. Như chúng tôi đã nói trước đó, điều đó không nhất thiết là xấu. Để làm điều này trong Python, bạn phải truy cập vào không gian tên toàn cầu. Python làm cho bạn làm điều này một cách rõ ràng nơi PHP được ngầm định.

def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25

Trong ví dụ này, chúng tôi sử dụng chức năng

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
7 để truy cập không gian tên toàn cầu.
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
7 Trả về một từ điển bao gồm
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
6 làm khóa và giá trị là một tham chiếu đến hàm
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
5. Nếu bạn không quen thuộc với
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
7, một thay đổi đơn giản đối với mã của chúng tôi có thể cho bạn một ý tưởng rõ ràng về những gì chúng tôi đang làm.

def area(length: int, width: int):
    print(length * width)

print(area)
# Output: 

print(globals()["area"])
# Output: 

Bạn có thể thấy rằng cả

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
6 và
dynamo.__doc__ = "Adds %s to the weight" % i
3 đều chỉ vào cùng một địa chỉ trong bộ nhớ
dynamo.__doc__ = "Adds %s to the weight" % i
4. Điều này có nghĩa là trong phạm vi hiện tại gọi
dynamo.__doc__ = "Adds %s to the weight" % i
5 và
dynamo.__doc__ = "Adds %s to the weight" % i
6 sẽ chạy cùng một hàm.

Đừng lạm dụng toàn cầu

Chỉ vì bạn có thể làm điều gì đó không có nghĩa là bạn nên. Sử dụng

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
7 theo cách này thường được cau mày vì không pythonic hay an toàn. Sẽ an toàn hơn khi sử dụng
dynamo.__doc__ = "Adds %s to the weight" % i
8 hoặc
dynamo.__doc__ = "Adds %s to the weight" % i
9 để chỉ truy cập vào phạm vi cục bộ, nhưng vẫn không lý tưởng.can do something does not mean you should. Using
def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
7 in this way is often frowned on as neither pythonic nor safe. It is safer to use
dynamo.__doc__ = "Adds %s to the weight" % i
8 or
dynamo.__doc__ = "Adds %s to the weight" % i
9 to access just the local scope, but still not ideal.

May mắn thay, các đối tượng trong phạm vi theo cách này không nguy hiểm như nó có thể. Python được xây dựng trong các chức năng và các lớp có sẵn trong khóa

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
0. Điều này rất quan trọng, vì nó có nghĩa là gọi
function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
1 sẽ tăng
function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
2. Bạn thực sự sẽ cần phải gọi
function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
3.

Hãy trung thực là Python được xây dựng trong các chức năng và các lớp không phải là đối tượng có thể khai thác duy nhất trong bất kỳ chương trình nào.

Một cách tốt hơn là sử dụng một lớp để gói gọn các phương thức bạn muốn cung cấp để thực hiện khi chạy. Bạn có thể tạo từng hàm như một phương thức của lớp. Khi tên của một hàm được cung cấp, bạn có thể kiểm tra xem đó có phải là thuộc tính của lớp và có thể gọi được không.

import math

class Rectangle:
    length: int
    width: int

    def __init__(self, length: int, width: int):
        self.length = length
        self.width = width

    def do_area(self):
        area = self.length * self.width
        print(f"The area of the rectangle is: {area}")

    def do_perimeter(self):
        perimeter = (self.length + self.width) * 2
        print(f"The perimeter of the rectangle is: {perimeter}")

    def do_diagonal(self):
        diagonal = math.sqrt(self.length ** 2 + self.width ** 2)
        print(f"The diagonal of the rectangle is: {diagonal}")

    def solve_for(self, name: str):
        do = f"do_{name}"
        if hasattr(self, do) and callable(func := getattr(self, do)):
            func()

rectangle = Rectangle(3, 5)

rectangle.solve_for('area')
rectangle.solve_for('perimeter')
rectangle.solve_for('diagonal')

# Output: 
# The area of the rectangle is: 15
# The perimeter of the rectangle is: 16
# The diagonal of the rectangle is: 5.830951894845301

Nếu bạn đang nhìn vào tuyên bố

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
4 trong phương thức
function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
5 và nhận được một chút bối rối. Đừng lo. Tôi đang sử dụng một số cú pháp mới trong Python 3.8.

Biểu thức gán

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
6 cho phép bạn cả đặt giá trị của một biến và đánh giá kết quả của một biểu thức trong một dòng.

Chức năng tương đương với ...

def solve_for(self, name: str):
    do = f"get_{name}"
    if hasattr(self, do) and callable(getattr(self, do)):
        func = getattr(self, do)
        func()

Sự khác biệt là

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
7 không cần phải được đánh giá hai lần.

Hãy trở lại ví dụ của chúng tôi.

Phương pháp

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
5 thực sự đang thực hiện hầu hết các công việc nặng nhọc ở đây. Đầu tiên nó đưa
function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
9 và nối
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
0 lên phía trước. Đây thường là một ý kiến ​​hay. Lớp học của bạn có thể sẽ có một vài phương thức và thuộc tính bổ sung mà bạn không muốn phơi bày.

Khi tên của hàm đã được xác định, chúng ta có thể kiểm tra để đảm bảo đó là thuộc tính hợp lệ và hàm mà chúng ta có thể gọi. Điều cuối cùng chúng tôi làm chỉ đơn giản là gọi hàm.

Đối số chức năng động

Chuyển các đối số cho chức năng động là thẳng về phía trước. Chúng tôi chỉ đơn giản là có thể thực hiện

function area( int $length, int $width ) {
    print( $length * $width );
}

$area_func_name = 'area';

// Method 1
call_user_func( $area_func_name, 4, 5 );
// Output: 20

// Method 2
$area_func_name( 3, 5 );
// Output: 15
5 chấp nhận
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
2 và
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
3 sau đó chuyển điều đó cho
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
4.

def solve_for(self, name: str, *args, **kwargs):
    do = f"get_{name}"
    if hasattr(self, do) and callable(func := getattr(self, do)):
        func(*args, **kwargs)

Tất nhiên, bạn sẽ cần xử lý các đối số trong hàm sẽ được gọi. Hiện tại, không có phương pháp

def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
5 nào trong ví dụ của chúng tôi chấp nhận các đối số.

Một trong những phức tạp của việc sử dụng các đối số với thực thi chức năng động là sự cần thiết của mỗi hàm để xử lý các đối số giống nhau. Điều này đòi hỏi bạn phải chuẩn hóa các đối số chức năng của bạn.

Chức năng động sử dụng trong Python

Hai trong số các cách sử dụng phổ biến để thực hiện chức năng động trong PHP là các cuộc gọi lại và móc. Tuy nhiên, trong Python, cả hai đều không phổ biến.

Tôi nghĩ rằng Python tập trung vào việc trở thành rõ ràng khiến các nhà phát triển không thể tiến tới chương trình meta và ma thuật. Python cũng cung cấp các nhà trang trí có thể được sử dụng để móc một cách rõ ràng hoặc bọc một chức năng. Hai điều này giới hạn việc sử dụng các cuộc gọi chức năng động.

Tôi nghĩ rằng ví dụ tốt nhất về thực thi chức năng động trong Python là xác thực hình thức trong Django. Giả sử chúng tôi có một hình thức như thế này ...

from django import forms

class RegisterForm(forms.Form):
    username = forms.CharField()
    email = forms.EmailField()

Khi Django xác nhận và phân tích các giá trị cho các loại dữ liệu Python gốc, nó sẽ gọi một hàm cho mỗi trường. Hàm là

def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
6 trong đó
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
7 là tên của trường.

Trong ví dụ này, chúng tôi có thể thêm một phương thức để đảm bảo giá trị của tên là hợp lệ và được định dạng theo cách chúng tôi muốn.

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
0

Đây là một ví dụ rất đơn giản. Chúng tôi chỉ lấy bất cứ giá trị nào được đưa ra trong

def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
8 và làm cho nó thường xuyên.
def area(length: int, width: int):
    print(length * width)

area_func = globals()["area"]

area_func(5, 5)
# Output: 25
9 được gọi bằng phương pháp
def area(length: int, width: int):
    print(length * width)

print(area)
# Output: 

print(globals()["area"])
# Output: 
0 của Django.

Phương pháp

def area(length: int, width: int):
    print(length * width)

print(area)
# Output: 

print(globals()["area"])
# Output: 
1 từ Django là một ví dụ điển hình về cách thực thi một hàm một cách linh hoạt.

def __init__(self):

    for i in range(0,10):

        def dynamo(self, arg, i=i):
            """ dynamo's a dynamic method!
            """
            self.weight += i
            return arg * self.weight

        setattr(self.__class__, 'dynamo_'+i, dynamo)
        self.weight = 50
1

Lý do

def area(length: int, width: int):
    print(length * width)

print(area)
# Output: 

print(globals()["area"])
# Output: 
1 tồn tại không phải là vì không thể làm điều này theo bất kỳ cách nào khác. Nhưng bởi vì nó cung cấp một giao diện sạch cho các hình thức xây dựng nhà phát triển ở Django.

Tôi nghĩ rằng đây là một ví dụ tốt về lý do tại sao bạn có thể muốn sử dụng mẫu này. Nói chung, tôi khuyên bạn nên tránh nó, nhưng có những lúc nó làm cho thư viện hoặc API dễ dàng sử dụng. Trong những trường hợp đó, đừng ngại làm điều đó, nhưng hãy chắc chắn rằng bạn làm điều đó một cách an toàn!

Chức năng động trong Python là gì?

Mã Python có thể được nhập động và các lớp có thể được tạo động khi chạy.Các lớp có thể được tạo động bằng cách sử dụng hàm loại () trong python.Hàm loại () được sử dụng để trả về loại đối tượng.type() function in Python. The type() function is used to return the type of the object.

Làm thế nào để Python cho phép thêm các phương thức một cách linh hoạt?

Thêm các phương thức động trong Python..
Từ các loại Nhập phương thức Lớp người (đối tượng): def __init __ (tự, tên): tự.....
người lớp (đối tượng): def __init __ (tự, tên): tự.....
Lớp UpperList (danh sách): Pass def to_upper (self): Đối với chỉ mục, mục trong liệt kê (tự): tự [index] = item ..

Có phải thiết lập cấu trúc động trong Python?

Các bộ trong Python có thể được định nghĩa là các bộ sưu tập động có thể thay đổi của các yếu tố độc đáo bất biến.Các yếu tố chứa trong một bộ phải là bất biến.mutable dynamic collections of immutable unique elements. The elements contained in a set must be immutable.

Phương thức trong Python là gì?

Việc sử dụng phổ biến các loại.MethodType đang kiểm tra xem một số đối tượng có phải là phương thức hay không.Ví dụ: >>> Nhập các loại >>> Lớp A (đối tượng): ... Phương thức def (tự): ... Pass ... >>>checking whether some object is a method. For example: >>> import types >>> class A(object): ... def method(self): ... pass ... >>>