python 对象变字典



The very first thing one must learn and believe without a shred of doubt is that In python, everything is an object.

毫无疑问,首先要学习并相信的第一件事是, 在python中,一切都是对象。

Python offers a host of magic methods (alternatively called dunder methods because of the “double underscores”) to make custom objects more intuitive, easy to use and pythonic. Let’s start with a very basic scenario:

Python提供了许多magic methods (由于使用“ 双下划线 ”,因此又称为dunder methods ),以使自定义对象更加直观,易于使用和使用pythonic。 让我们从一个非常基本的场景开始:

string_sum_output = 'hello' + ' world' + '!'
integer_sum_output = 10 + 20
print(string_sum_output)
print(integer_sum_output)o/p1:>> hello world!
o/p2:>> 30

At first glance o/p1 and o/p2 seems super normal. But let me ask you this,

乍看之下, o/p1o/p2似乎超常。 但是我问你这个

how does python decide when to do arithmetic sum and when to concatenate values if ‘+’ operator is used?

python如何确定何时进行算术求和以及何时连接值 如果使用'+'运算符

Most obvious answer will be based on data-types, which is not incorrect, but doesn’t reveal the real process of deciding though. That’s where magic methods come into picture. Certain behaviours of an objects can be controled and dictated by using these, so called, magic methods.

最明显的答案将基于数据类型, 这虽然不正确,但是并没有揭示确定的真正过程。 那就是magic方法出现的地方。 通过使用这些所谓的魔术方法 ,可以控制和控制对象的某些行为。

So in this article, we will see how to add certain behavioural traits to our custom classes, so that objects of those classes will have some special functionalities.

因此,在本文中,我们将看到如何在自定义类中添加某些行为特征 ,以便这些类的对象具有某些特殊功能。

(Student Class)

Following is our simple Student class:

以下是我们的简单Student类:


Student Class

学生


A very basic class, which takes three parameters to define a student — name, phone_number and standard.

一个非常基本的类,它有三个参数来定义一个学生- namephone_numberstandard

(Scenarios)

There are numerous magic methods available in python, we will see some basic and most widely used of those, to implement following scenarios:

在python中有许多魔术方法可用,我们将看到其中一些基本且使用最广泛的方法,以实现以下情况:

  1. What will be shown, when I print an object?
    打印对象时会显示什么?
  2. How can I compare between two objects?
    如何比较两个对象?
  3. What will be returned if I apply built-in length function on one object?
    如果我将内置 length 函数应用于一个对象, 将返回什么
  4. How to make the object iterable/iterator?
    如何使对象可迭代/迭代?
  5. How to support indexing on the object, i.e. obj[0]?
    如何支持在对象(即 obj[0] 上建立索引
  6. And finally, what will be the result if any arithmetic operator (‘+’, ‘-’, ‘*’ etc) is used with the objects?
    最后,如果将任何算术运算符('+','-','*'等)与对象一起使用,结果将如何?

(Scenario 1: What will be shown, when I print an object?)

So if we just create an object of current Student class, and try to print it something like following will show up:

因此,如果我们仅创建当前Student类的对象,然后尝试打印该对象,则将显示以下内容:

>>> student_object = Student('saumalya', 1111100000, 'XII', 'A')
>>> print(student_object)----- Output -----<__main__.Student object at 0x10ff67790>

Frankly speaking, this memory location identifier is not that useful to application developer/user, is it!

坦白地说,此内存位置标识符对应用程序开发人员/用户没有太大作用!

Let’s say, we want to see student’s name if we print a student object. In that case, we implement __str__ methods in our student class as shown below:

假设我们要打印学生对象就希望看到学生的名字 。 在这种情况下,我们实现__str__ 我们学生班的方法如下所示:


__str__

__str__

method

方法


Now when we print the same object, this happens:

现在,当我们打印相同的对象时,会发生这种情况:

>>> print(student_object)----- Output -----saumalya

It is mandatory to return single string data from ‘__str__' method, because this method actually decides the output of — ‘str(student_object)’ method call, which is called by ‘print(student_object)’ method implicitly.

必须从' __str__'方法返回单个字符串数据,因为该方法实际上决定了''str(student_object)'方法调用的输出,该输出由'print(student_object)'方法隐式调用。

方案2: 如何比较两个对象 ? (Scenario 2: How can I compare between two objects?)

When we talk about value comparison, there are total 5 basic types of comparison possible: equality, greater than, greater than equal to, smaller than andsmaller than equals to . Python provides magic methods for each of those comparisons: __eq__, __gt__, __ge__, __lt__ and __le__ respectively to support comparison operators for our object comparison, We will do the comparisons based on which standard the students are in:

当我们谈论价值比较时,总共可能有5种基本比较类型: equalitygreater thangreater than equal tosmaller thansmaller than equals to 。 Python提供神奇的方法为每个比较: __eq____gt____ge____lt____le__分别支持比较操作我们的对象比较,我们将在此基础上做了比较standard的学生是:


Implemented __eq__,

__gt__, __ge__, __lt__ and

__le__

methods

实施 __eq__,__gt__,__ge__,__lt__

__le__

方法


See how simply we can compare the objects using comparison operators:

看看我们如何使用比较运算符比较对象:

>>> student_1 = Student('magne', 1111100000, 'XI')
>>> student_2 = Student('isolde', 2222200000, 'XII')
>>> student_3 = Student('try', 3333300000, 'ix')
>>> print(student_1 == student_3)
>>> print(student_2 >= student_1)
>>> print(student_3 > student_2)
>>> print(student_1 < student_3)
>>> print(student_2 <= student_2)----- Output -----False
True
False
False
True

Note, we used one private static method ‘_get_standard_weight(std: str)’ to do some custom derivation before comparison. Similarly, we can implement any complex logic based on our requirement, which makes these magic methods so powerful.

注意,在比较之前,我们使用了一个私有静态方法'_get_standard_weight(std:str)'做一些自定义派生。 同样,我们可以根据需要实现任何复杂的逻辑,这使这些魔术方法变得如此强大。

(House Class:)

For rest of the three scenarios, we will use House class, only because next functionalities make more sense in context of a house, instead of a student. Similarly all magic methods will not be useful for each custom classes, user must choose based on relevance.

对于这三种情况的其余部分,我们将使用House类,仅是因为在house背景下(而不是student ,下一个功能更有意义。 同样,所有魔术方法对每个自定义类都不有用,用户必须根据相关性进行选择。


House Class

房屋


Again quite a basic class, which takes three parameters to define a housename, symbol and student_list.

还是一个非常基本的类,它使用三个参数来定义house - namesymbolstudent_list

方案3: 如果将内置 length 函数应用于对象, 将返回什么 (Scenario 3: What will be returned if built-in length function is applied on objects?)

Intuitively we might want number of students in a house as output of len(house_object) call. To achieve that we need to implement __len__ in our house class, as shown below:

直观地,我们可能希望一housestudents人数作为len(house_object)调用的输出。 为了实现这一点,我们需要实现__len__ 在我们的house课程中,如下所示:


__len__ method

__len__方法


Okay, is it working? let’s test!

好的,可以吗? 让我们测试一下!

>>> house_object = House('Gryffindor'
                             , 'Lion'
                             , [student_1, student_2, student_3]
                        )
>>> print(len(house_object))----- Output -----3

(Scenario 4: How to make the object iterable/iterator ?)

Now before I answer that, we have to discuss a bit about iterator and iterable in python.

现在,在我回答之前,我们必须讨论一些关于iterator和python中iterable问题。

In simple words, an object is said to be iterable if it can be looped over. For example, lists, tuples, ranges etc. Whereas Iterators are stateful objects. The iterator objects are capable of keeping information about the current state and can produce the next element if next() method is applied on it.

用简单的话说,如果对象可以循环,就可以iterable 。 例如, liststuplesranges等。而Iterators是有状态的对象。 迭代器对象能够保留有关当前状态的信息,并且如果将next()方法应用于其上,则可以生成下一个元素。

Note, To make an object iterable, the class has to implement __iter__ method and return an iterator from it. Because, looping constructs like for , while will take the iterator object and get the next elements one after another and assign to the loop variable.

注意,要使对象可迭代,该类必须实现__iter__ 方法并从中返回iterator 。 因为, for循环构造, while将采用iterator对象并iterator获取下一个元素并分配给loop变量。

(Making objects of House class ‘Iterable’:)


__iter__ method

__iter__方法


As you can see, __iter__ method is returning an iterator object. The iterator object is created by applying iter() method on the student_list . That is possible because built-in list class is also an iterable.

如您所见, __iter__ 方法返回一个iterator对象。 通过在student_list上应用iter()方法来创建iterator对象。 这是可能的,因为内置list类也是iterable

>>> house_object = House('Gryffindor'
                             , 'Lion'
                             , [student_1, student_2, student_3]
                        )
>>> for student_object in house_object:
    print(student_object)----- Output -----magne
isolde
gry

Printing the ‘student_object’ inside the loop, directly prints name of that student because ‘__str__' is defined to return student name. (Scenario 1).

在循环内打印“ student_object”,直接打印该学生的姓名,因为定义了“ __str__'以返回学生姓名。 ( 方案1)。

(Making objects of House class `Iterator`:)


__next__ method and updated

__next__方法并更新了

__iter__ method

__iter__方法


Note, __next__ method is implemented such a way, it will always return the next student on the student_list and the state is maintained using current_student_id instance variable. Moreover __iter__ now returns the object itself (after re-initiating the state variable current_student_id) — not an iterator created of the list, because house object itself is an iterator now.

注意, __next__方法是以这种方式实现的,它将始终返回student_list上的下一个学生,并且使用current_student_id实例变量维护状态。 而且__iter__ 现在返回对象本身(在重新启动状态变量current_student_id ),而不是列表的iterator ,因为house对象本身现在是一个iterator

>>> house_object = House('Gryffindor'
                             , 'Lion'
                             , [student_1, student_2, student_3]
                        )
>>> print(next(house_object))
>>> print(next(house_object))
>>> print(next(house_object))>>> print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")>>> for student_object in house_object:
>>>     print(student_object, end=', ')----- Output -----magne
isolde
gry
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
magne, isolde, gry,

‘__next__’ method must raise ‘StopIteration’ error once the available states come to end, the loop constructs wait for that to happen to stop the looping.

一旦可用状态结束,“ __ next__”方法必须引发“ StopIteration”错误,循环构造会等待这种情况停止循环。

方案5: 如何支持在对象上建立索引 ? (Scenario 5: How to support indexing on the object?)

At times, we face situations, where indexing comes quite handy. Indexing is a method by which we can extract data from a sequential data structure by specifying the index of the data.

有时,我们会遇到索引很方便的情况。 索引 是一种方法,通过指定数据的索引,我们可以从顺序数据结构中提取数据

Now, we can implement the similar behaviour on our object also. For example I want house_object[1] to return isolde , although we are actually doing index operation on student_list but I want that transition to be implicit. That way user can apply much more complicated logic than just indexing some list type instance variable.

现在,我们也可以在对象上实现类似的行为。 例如,我希望house_object[1]返回isolde ,尽管实际上我们正在对student_list进行索引操作,但我希望该转换是隐式的。 这样,用户不仅可以为某些list类型的实例变量建立索引,还可以应用更为复杂的逻辑。

To achieve this, we have to implement __getitem__ in our class and write the indexing logic, for our example, the logic is really simple, just return the value of same index from student_list.

为此,我们必须实现__getitem__ 在我们的类中并编写索引逻辑,对于我们的示例,该逻辑非常简单,只需从student_list返回相同索引的值即可。

class House:
    def __init__(self, name: str, symbol: str, student_list: list):
        self.name = name
        self.symbol = symbol
        self.student_list = student_list
        self.current_student_id = -1


    def __len__(self):
        return len(self.student_list)


    def __next__(self):
        self.current_student_id += 1
        try:
            return self.student_list[self.current_student_id]
        except IndexError:
            raise StopIteration()


    def __iter__(self):
        self.current_student_id = 0
        return self


    def __getitem__(self, item):
        return self.student_list[item]

Now we can do this:

现在我们可以这样做:

>>> house_object = House('Gryffindor'
                             , 'Lion'
                             , [student_1, student_2, student_3]
                        )
>>> print(house_object[2])----- Output -----gry

Note, in this approach, we can support slicing also:

注意,在这种方法中,我们还可以支持切片

>>> house_object = House('Gryffindor'
                             , 'Lion'
                             , [student_1, student_2, student_3]
                        )
>>> for student in house_object[1:2]:
>>>     print(student)----- Output -----isolde
gry

方案6: 如果将任何算术运算符(+,-,*等)与对象一起使用,结果将如何? (Scenario 6: what will be the result if any arithmetic operator (+, -, * etc) is used with the objects?)

That will be decided based on the implementation of magic methods like __add__, __sub__, __mult__, __div__ etc. As all these methods work exactly similar manner, we will see one(__add__) in our example, and I am sure anyone can implement the rest following same pattern.

这将根据诸如__add____sub____mult____div__等魔术方法的实现来决定。由于所有这些方法的工作方式都非常相似,因此我们在示例中将看到一个( __add__ ),我相信任何人都可以实现其余方法遵循相同的模式。

So here is how we declare to merge the students, when two house_object are added:

因此,当添加两个house_object时,这是我们声明合并学生的方式:

class House:
    def __init__(self, name: str, symbol: str, student_list: list):
        self.name = name
        self.symbol = symbol
        self.student_list = student_list
        self.current_student_id = -1


    def __len__(self):
        return len(self.student_list)


    def __next__(self):
        self.current_student_id += 1
        try:
            return self.student_list[self.current_student_id]
        except IndexError:
            raise StopIteration()


    def __iter__(self):
        self.current_student_id = 0
        return self


    def __getitem__(self, item):
        return self.student_list[item]


    def __add__(self, other):
        return self.student_list + other.student_list

Now we see the magic:

现在我们看到了魔术:

>>> new_student_1 = Student('Maeve', 9999900000, 'X')
>>> new_student_2 = Student('Otis', 8888800000, 'X')
>>> new_student_3 = Student('Eric', 7777700000, 'X')
>>> new_house_object = House(
    'Ravenclaw',
    'Eagle',
    [new_student_1, new_student_2, new_student_3]
)
>>> print(house_object + new_house_object)----- Output -----[magne, isolde, raxa, Maeve, Otis, Eric]

Similarly __sub__, __mult__ etc methods can be implemented to support respective operators.

类似地,可以实现__sub____mult__等方法来支持相应的运算符。

Note: To show the names of student inside a list while we are printing student_list, implement __repr__ method in Student class exactly similarly to __str__ method.

注意:要在我们打印student_list时在list显示学生的姓名,请实现__repr__ Student类中的方法与__str__完全相似 方法。

I hope, this article will help reader to be more pythonic. There are lots other magic method that are exteemely useful too. As the purpose of this article was to introduce readers to python magic methods, I discussed about only a few of them. __new__ and __init__ are two most important magic methods, but I kept those out of this article solely because of the complexity. Maybe some other time, keep an eye out.

希望本文能帮助读者更多地了解pythonic 。 还有许多其他魔术方法也非常有用。 因为本文的目的是向读者介绍python魔术方法,所以我仅讨论了其中的几种方法。 __new____init__是两个最重要的魔术方法,但由于复杂性,我将其排除在本文之外。 也许再过一段时间,请注意。


翻译自: https://medium.com/swlh/make-python-objects-magical-45c0f003d9a1

python 对象变字典