Feature or enhancement
The main purpose is in native Python object-oriented programming, it can capture in real time and learn that an object does not invoke any attribute or method. The emphasis is on learning the situation synchronously and processing it when an object is invoked, rather than judging the situation through the connection of code context. Of course, the latter is completely impossible to achieve real-time in the latest Python version, because there is no special method that will be invoked simultaneously when the object is called, it is impossible to establish a real-time code context to determine whether the object invokes any attribute or method.
In the latest version of Python, I have tried my best to use Python native code to achieve the above requirements, but all failed. To this end I come up with the ideas of achieving the main purpose
by enhancing Python itself, two alternative ways for solving the problem, and the Python core developers can choose either of the two solutions.
1.Add a new object-oriented programming special method
First I assume the name of this special method is __noinvokeattr__
.
By default, its definition should be:
def __noinvokeattr__(self):
pass
This special method will be called when the object does not invoke any other attribute or method. In actual application scenarios, this special method needs to be overridden to achieve some specific purposes of programming.
For example:
>>> class MyClass:
... def __init__(self):
... pass
...
... def __noinvokeattr__(self):
... print("The Object has not invoked any attribute or method.")
...
... def method(self):
... print("The object has invoked a method named 'method'.")
...
>>> obj = MyClass()
The Object has not invoked any attribute or method.
>>> obj
The Object has not invoked any attribute or method.
>>> obj.method()
The object has invoked a method named 'method'.
It is worth nothing that when the object is instantiated and assigned to obj
for the first time, since no other non-special attribute or method is invoked, the __noinvokeattr__
is called.
Of course, we can also allow __noinvokeattr__
to receive the parameter of whether the object invokes special method to set whether to ignore other special methods to deal with certain specific situations during programming.
>>> class MyClass:
... def __init__(self):
... pass
...
... def __noinvokeattr__(self, is_invoke_special_method):
... if is_invoke_special_method:
... pass
... else:
... print("The Object has not invoked any attribute or method.")
...
... def __getattr__(self, item):
... print("The object doesn't have an attribute named '" + str(item) + "'.")
...
>>> obj = MyClass()
>>> obj.method()
The object doesn't have an attribute named method.
2.Enhance __getattr__
features which has been a special method in Python
The second approach also achieves the main purpose
, and is similar to the first approach in terms of core operation logic design. However, it leverages the improvement and integration of Python’s existing special method to satisfy the requirements, instead of creating a new special method like __noinvokeattr__
.
In the latest version of Python now for the following code:
>>> class MyClass:
... def __getattr__(self, item):
... if item == None:
... print("The Object has not invoked any attribute or method.")
... if item:
... print("No attribute or method named '" + str(item) + "' exists in the ...| object.")
...
>>> obj = MyClass()
>>> obj
>>> obj.method()
No attribute or method named 'method' exists in the object.
Obviously, if obj
does not use dot notation, the __getattr__
method will not be called, let alone pass None
to the formal parameter item
.
The goal of enhancing __getattr__
features is to:
>>> class MyClass:
... def __getattr__(self, item):
... if item == None:
... print("The Object has not invoked any attribute or method.")
... if item:
... print("No attribute or method named '" + str(item) + "' exists in the ...| object.")
...
>>> obj = MyClass()
The Object has not invoked any attribute or method.
>>> obj
The Object has not invoked any attribute or method.
>>> obj.method()
No attribute or method named 'method' exists in the object.
After changing __getattr__
features, even if dot notation is not used, __getattr__
will be called and None
will be passed to the formal parameter item
when obj
does not invoke any attribute or method.
Because __getattr__
itself is called when the object attribute or method cannot be found in the latest Python version, even if the existing special method is called, None
will still be passed into the formal parameter item
. This compares with the first approach in this regard why obj = MyClass()
prints something despite calling __init__
.
Pitch
Based on the above ideas, we can easily realize the selective acquisition of data within a specific range of the dynamic data dict.
The following example is MyClass().status
stores a dynamic data dict about the status of the object, these dynamic data need to call the corresponding function to obtain in real time.
# Assuming this function takes 1 second to perform the calculation before returning the result.
def get_data_1():
...
# Assuming this function takes 1 minute to perform the calculation before returning the result.
def get_data_2():
...
# Assuming this function takes 1 hour to perform the calculation before returning the result.
def get_data_3():
...
class Dict(dict): # A similar dict class stores dynamic data about the status of the MyClass class.
def __get_value(self, key):
if key == "data_1" or key == None:
self["data_1"] = get_data_1()
elif key == "data_2" or key == None:
self["data_2"] = get_data_2()
elif key == "data_3" or key == None:
self["data_3"] = get_data_3()
def __getattr__(self, item):
if item == None: # The object has not invoked any attribute or method.
self.__get_value(None) # Get all dynamic data.
def __getitem__(self, item):
self.__get_value(item) # Get the specified dynamic data.
class MyClass:
@property
def status(self):
return Dict()
obj = MyClass()
'''
In memory, the status dict only stores the data specified by dictionary key access operators -> obj.status = {"data_1":get_data_1()}.
obj.status["data_1"] = get_data_1()
'''
obj_status_data_1 = obj.status["data_1"]
'''
In memory, the status dict stores all data, since no data is specified by dictionary key access operators -> obj.status = {"data_1":get_data_1(), "data_2":get_data_2(), "data_3":get_data_3}.
'''
obj_status = obj.status
The calculation time assumed in the comment before each function which is used to obtain data is to better magnify and highlight the characteristics of this dynamic data dict code design. The difference between using dictionary key access operators behind obj.status
is whether it consumes more memory and time, which depends on the programming choice.
Just like the above code example, many are the current usage habit of dict
:
The above code example | The assignment object of the current dict
|
Meaning in code example | Spend time |
---|---|---|---|
obj_status = obj.status |
entire dict
|
get all the data of the dynamic data dict | more than an hour |
obj_status_data_1 = obj.status["data_1"] |
the value corresponding to the key | get specified data | only one second |
We can find that the code design of this dynamic data dict uses that feature to make a distinction. We seem to be able use __call__
to distinguish whether to obtain only the specified data, however, due to the preceding code syntax condition before calling __call__
, it is destined that we will not be able to use the methods of dictionary operations after that. And that code design adheres to the concept of program optimization that does not load if not used, saves memory and time, and also caters to the programming habit of using dict
.
Although in the latest Python version, we can inherit the dict
class, and then override a series of related attributes and methods to achieve the same purpose (or when instantiating the dict
object, first store the function pointer which is obtain data, and execute the specified function pointer when needed), but it will be very troublesome and difficult to finish it step by step. Therefore, adding that feature to native Python is similar to the utility of syntactic sugar, which I call code sugar. It’s a bit like adding the mechanism of the programming language itself to turn the tasks that need to be completed through repetitive or complex code into simple and fast completion, similar to the relationship between the characters array of C and the new std::string of CPP.