Hướng dẫn python dynamically change class attributes - python tự động thay đổi thuộc tính lớp

Các thuộc tính lớp có thể được đọc trên lớp hoặc một thể hiện, nhưng bạn chỉ có thể đặt chúng trên lớp (cố gắng đặt chúng trên một thể hiện sẽ chỉ tạo một thuộc tính thể hiện sẽ theo dõi thuộc tính lớp).

Nếu điều kiện được biết đến tại thời điểm nhập khẩu, bạn chỉ có thể kiểm tra nó trong cơ thể class:

xxx = True 

class A(object):
   cls_attr = 'value'

class B(A):
   if xxx:
       cls_attr = 'this_value'
   else
       cls_attr = 'that_value'

Bây giờ nếu bạn muốn thay đổi nó trong quá trình thực hiện chương trình, bạn phải sử dụng classmethod:

class B(A):
   @classmethod
   def set_cls_attr(cls, xxx):   
       if xxx:
           cls.cls_attr = 'this_value'
       else:
           cls.cls_attr = 'that_value'

Hoặc nếu bạn cần truy cập phiên bản của mình trong quá trình kiểm tra:

class B(A):
   def set_cls_attr(self, xxx):   
       cls = type(self)
       if xxx:
           cls.cls_attr = 'this_value'
       else:
           cls.cls_attr = 'that_value'

Logo Python

2021/06/05 - Chỉnh sửa:

Tôi đã viết bài viết này vào năm ngoái, và kể từ khi đã tìm hiểu thêm về cách Python hoạt động trong nội bộ. Các giải pháp dưới đây thực sự hoạt động, nhưng khá không hiệu quả.

Các chức năng của GetAttr, SetAttr, Hasattr rất tuyệt vời và có thời gian và địa điểm được sử dụng, nhưng chúng yêu cầu tra cứu đối tượng đó trước khi truy cập/kiểm tra thuộc tính.

Tuy nhiên, được coi là lập trình xấu, các lớp mở giống như Ruby/JavaScript (nghĩa là các lớp có thể được sửa đổi trong thời gian chạy) thực sự có thể là một mẫu lập trình khi phát triển kiến ​​trúc trình cắm. Và, đoán xem, Python cũng có chức năng đó. Mã này cho phép thêm các thuộc tính (thông thường các phương thức) vào các lớp, ngay cả khi đã được khởi tạo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

'''
Created on Mar 31, 2011

@author: Nabil Stendardo

'''
def noop(*args,**kwargs):
    pass
def modify_class(cls,name=None,default=noop):
    """
    Modify an class attribute/method.
    
    This decorator factory returns a decorator which modifies on the fly (i.e. monkeypatches)
    the class "cls" by adding or replacing the attribute (typically method) indicated by the
    variable "name" (which defaults to the name of the wrapper function) with the result 
    of the decorated function, to which is passed as only parameter the old attribute with the same name
    (or a default value, by default a dummy function, if none exists).
    
    @param cls: the class to modify
    @param name: the name of the attribute/method to modify in the class 
    (defaults to the decorated function name)
    @param default: the value which is passed to the decorated function if there is no
    attribute named 'name' in 'cls' (defaults to a dummy function)
    @return: a decorator  
    """
    def wrapper(fn):
        """
        The actual decorator returned by modify_class, which actually modifies the class.
        
        @param fn: the function to decorate
        @return: the argument function.
        """
        if name is None:
            name_ = fn.__name__
        else:
            name_ = name
        original_method = getattr(cls,name_,default)
        new_method = fn(original_method)
        setattr(cls,name_,new_method)
        return fn
    return wrapper

##TESTING CODE
import unittest2
class TestModifyClass(unittest2.TestCase):
    def test_modifyClass(self):
        class Foo(object):
            def baz(self):
                return 0
            def bar(self,argument):
                return argument**2
        foo = Foo() # Note: the foo object is instantiated BEFORE the class modification 
        @modify_class(Foo)
        def baz(parent):
            # Note: Different signature
            def baz(self,argument):
                return self.bar(argument)
            return baz
        @modify_class(Foo)
        def bar(parent):
            def bar(self,argument):
                return parent(self,argument) * 3
            return bar
        @modify_class(Foo,'bar')
        # Note: Different wrapper name
        def toto(parent):
            def bar(self,argument):
                return parent(self,argument) + 1
            return bar
        for i in range(25):
            self.assertEqual(foo.baz(i),(i**2)*3+1)
if __name__ == '__main__':
    unittest2.main()

__ getattr __ trong Python là gì?

Hàm python getAttr () được sử dụng để nhận giá trị của thuộc tính của một đối tượng và nếu không tìm thấy thuộc tính nào của đối tượng đó, giá trị mặc định được trả về.used to get the value of an object's attribute and if no attribute of that object is found, default value is returned.

__ slots __ là gì?

Tuyên bố __Slots__ cho phép chúng tôi khai báo rõ ràng các thành viên dữ liệu, khiến Python dành không gian cho họ trong bộ nhớ và ngăn chặn việc tạo các thuộc tính __dict__ và __weakref__.Nó cũng ngăn chặn việc tạo ra bất kỳ biến nào không được khai báo trong __Slots__.allows us to explicitly declare data members, causes Python to reserve space for them in memory, and prevents the creation of __dict__ and __weakref__ attributes. It also prevents the creation of any variables that aren't declared in __slots__.

Các khe Python là gì?

Các khe trong Python là một cơ chế đặc biệt được sử dụng để giảm bộ nhớ của các đối tượng.Trong Python, tất cả các đối tượng sử dụng từ điển động để thêm một thuộc tính.Các khe là một phương pháp loại tĩnh trong từ điển không có động vật này được yêu cầu để phân bổ thuộc tính.a special mechanism that is used to reduce memory of the objects. In Python, all the objects use a dynamic dictionary for adding an attribute. Slots is a static type method in this no dynamic dictionary are required for allocating attribute.