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/p1
和o/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
类:
A very basic class, which takes three parameters to define a student — name
, phone_number
and standard
.
一个非常基本的类,它有三个参数来定义一个学生- name
, phone_number
和standard
。
情境 (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中有许多魔术方法可用,我们将看到其中一些基本且使用最广泛的方法,以实现以下情况:
What will be shown, when I print an object?
打印对象时会显示什么?
How can I compare between two objects?
如何比较两个对象?
What will be returned if I apply built-in
length
function on one object?如果我将内置
length
函数应用于一个对象, 将返回什么 ?How to make the object iterable/iterator?
如何使对象可迭代/迭代?
How to support indexing on the object, i.e.
obj[0]
?如何支持在对象(即
obj[0]
上建立索引 ?And finally, what will be the result if any arithmetic operator (‘+’, ‘-’, ‘*’ etc) is used with the objects?
最后,如果将任何算术运算符('+','-','*'等)与对象一起使用,结果将如何?
方案1:当我打印对象时,将显示什么? (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__
我们学生班的方法如下所示:
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种基本比较类型: equality
, greater than
, greater than equal to
, smaller than
和smaller than equals to
。 Python提供神奇的方法为每个比较: __eq__
, __gt__
, __ge__
, __lt__
和__le__
分别支持比较操作我们的对象比较,我们将在此基础上做了比较standard
的学生是:
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
,下一个功能更有意义。 同样,所有魔术方法对每个自定义类都不有用,用户必须根据相关性进行选择。
Again quite a basic class, which takes three parameters to define a house
— name
, symbol
and student_list
.
还是一个非常基本的类,它使用三个参数来定义house
- name
, symbol
和student_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:
直观地,我们可能希望一house
的students
人数作为len(house_object)
调用的输出。 为了实现这一点,我们需要实现__len__
在我们的house
课程中,如下所示:
Okay, is it working? let’s test!
好的,可以吗? 让我们测试一下!
>>> house_object = House('Gryffindor'
, 'Lion'
, [student_1, student_2, student_3]
)
>>> print(len(house_object))----- Output -----3
场景4:如何使对象可迭代/迭代? (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
。 例如, lists
, tuples
, ranges
等。而Iterators
是有状态的对象。 迭代器对象能够保留有关当前状态的信息,并且如果将next()
方法应用于其上,则可以生成下一个元素。
Note, To make an object iterable, the class has to implement
__iter__
method and return aniterator
from it. Because, looping constructs likefor
,while
will take theiterator
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’:)
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`:)
Note,
__next__
method is implemented such a way, it will always return the next student on thestudent_list
and the state is maintained usingcurrent_student_id
instance variable. Moreover__iter__
now returns the object itself (after re-initiating the state variablecurrent_student_id
) — not aniterator
created of the list, because house object itself is aniterator
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 printingstudent_list
, implement__repr__
method inStudent
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__是两个最重要的魔术方法,但由于复杂性,我将其排除在本文之外。 也许再过一段时间,请注意。
P.S.: Any suggestions will be highly appreciated. I am available at saumalya75@gmail.com
and linkedin.com/in/saumalya-sarkar-b3712817b .
PS:任何建议将不胜感激。 我可以通过saumalya75@gmail.com
和linkedin./in/saumalya-sarkar-b3712817b来获得 。
翻译自: https://medium.com/swlh/make-python-objects-magical-45c0f003d9a1
python 对象变字典