python several confusing magic methods
magic methods
https://www.educba.com/python-magic-method/?msclkid=8119e878ce8511ec9d52cc88840aaf9b
魔法方法是一组预定义的功能方法,一般不需要程序员关注,所以称为魔法方法, 这里翻译成 神秘方法,更加合适。
Magic methods are a collection of pre-defined functional method from the python library functions that cannot be declared or called directly. Instead, these functions can be called or invoked by executing some other related code snippet methods. This type of methods are simple to use and implement, as it does not require specific or any kind of extra manual effort from the programmer. Hence it is named as the ‘Magic Method’.
What is Python Magic Method?
- Python is an interpreted, object-oriented programming that gives you the ability to write procedural code and/or object-oriented as we know that creating Objects simplifies complicated data structures handling. In addition to that, magic methods eases the ability to create object-oriented programming.
- Before Diving into a magic method, let’s understand why they are created in the first place, they are created?
- Below is one example of class one using a magic method and the other is without the magic method. In the first one __init__ magic method is used, which can be used to initialize more than one instance variable in one go. A class Sports is defined as taking two instance variables into account that is name and sport.
- Both instance variables can be defined in one go using the __inti__ magic method. In case 2, the same thing is repeated, but this time we are using a set method to initialize the instance variable. Here for 2 variables, we have to call this method twice.
https://www.geeksforgeeks.org/dunder-magic-methods-python/?msclkid=8119c107ce8511eca07df1a2100f52f8
魔法方法带有两个下划线作为前后缀。
如果程序员需要使用的话,需要在定义的子类中做重载。
最常用的是 对象初始化方法 __init__
Dunder or magic methods in Python are the methods having two prefix and suffix underscores in the method name. Dunder here means “Double Under (Underscores)”. These are commonly used for operator overloading. Few examples for magic methods are:
__init__, __add__, __len__, __repr__
etc.The
__init__
method for initialization is invoked without any call, when an instance of a class is created, like constructors in certain other programming languages such as C++, Java, C#, PHP etc. These methods are the reason we can add two strings with ‘+’ operator without any explicit typecasting.
https://www.cnblogs.com/lightsong/p/15974345.html
__new__ 方法一般用于元类生成一般类场景。
class Meta(type): def __new__(cls, name, bases, dct): x = super().__new__(cls, name, bases, dct) x.attr = 100 return x class Foo(metaclass=Meta): pass Foo.attr
confusing magic methods -- attribute reference
http://www.sefidian.com/2021/06/06/python-__getattr__-and-__getattribute__-magic-methods/
__getattr__
对象中的属性,需要存在,才能访问。
否则,访问一个不存在的属性,则会导致异常。
Let’s start with
__getattr__
. This method will allow you to “catch” references to attributes that don’t exist in your object. Let’s see a simple example to understand how it works:In this example, the attribute access fails (with an
AttributeError
) because the attributedoes_not_exist
doesn’t exist.
class Dummy(object): passd = Dummy() d.does_not_exist # Fails with AttributeError
改用此方法捕获不存在方法的访问, 不会抛出异常。
class Dummy(object): def __getattr__(self, attr): return attr.upper()d = Dummy() d.does_not_exist # 'DOES_NOT_EXIST' d.what_about_this_one # 'WHAT_ABOUT_THIS_ONE'
但是如果属性存在,则不会激活此函数。
__getattribute__
此方法,会对所有的属性的访问,都会被激活。
__getattribute__
is similar to__getattr__
, with the important difference that__getattribute__
will intercept EVERY attribute lookup, doesn’t matter if the attribute exists or not. Let me show you a simple example:In that example, the
d
object already has an attributevalue
. But when we try to access it, we don’t get the original expected value (“Python”); we’re just getting whatever__getattribute__
returned. It means that we’ve virtually lost thevalue
attribute; it has become “unreachable”.
__setattr__
https://python-reference.readthedocs.io/en/latest/docs/dunderattr/setattr.html
>>> # this example uses __setattr__ to dynamically change attribute value to uppercase >>> class Frob: ... def __setattr__(self, name, value): ... self.__dict__[name] = value.upper() ... >>> f = Frob() >>> f.bamf = "bamf" >>> f.bamf 'BAMF'
__delattr__
https://python-reference.readthedocs.io/en/latest/docs/dunderattr/delattr.html
>>> class Frob: ... def __delattr__(self, name): ... print "deleting `{}`".format(str(name)) ... del self.__dict__[name] ... print "`{}` deleted".format(str(name)) ... >>> f = Frob() >>> f.bamf = 10 >>> del f.bamf deleting `bamf` `bamf` deleted
confusing magic methods -- descriptor
https://rszalski.github.io/magicmethods/?msclkid=b255353ece8911ec85246d3d9339a225#descriptor
属性值作为一个对象(descriptor类产生的对象),具有动态计算能力, 依赖的环境为 其定义的类 和 实例。
适应范围: 依赖计算。
Descriptors are classes which, when accessed through either getting, setting, or deleting, can also alter other objects. Descriptors aren't meant to stand alone; rather, they're meant to be held by an owner class. Descriptors can be useful when building object-oriented databases or classes that have attributes whose values are dependent on each other. Descriptors are particularly useful when representing attributes in several different units of measurement or representing computed attributes (like distance from the origin in a class to represent a point on a grid).
To be a descriptor, a class must have at least one of
__get__
,__set__
, and__delete__
implemented. Let's take a look at those magic methods:
__get__(self, instance, owner)
- Define behavior for when the descriptor's value is retrieved.
instance
is the instance of the owner object.owner
is the owner class itself.__set__(self, instance, value)
- Define behavior for when the descriptor's value is changed.
instance
is the instance of the owner class andvalue
is the value to set the descriptor to.__delete__(self, instance)
- Define behavior for when the descriptor's value is deleted.
instance
is the instance of the owner object.
class Meter(object): '''Descriptor for a meter.''' def __init__(self, value=0.0): self.value = float(value) def __get__(self, instance, owner): return self.value def __set__(self, instance, value): self.value = float(value) class Foot(object): '''Descriptor for a foot.''' def __get__(self, instance, owner): return instance.meter * 3.2808 def __set__(self, instance, value): instance.meter = float(value) / 3.2808 class Distance(object): '''Class to represent distance holding two descriptors for feet and meters.''' meter = Meter() foot = Foot()
https://blog.finxter.com/python-__get__-magic-method/?msclkid=529d2a00ce8c11ec909b69d870207cef
例如下面, 根据宿主对象中的dirname属性,动态计算directory size值。
import os class DirectorySize: def __get__(self, obj, objtype=None): return len(os.listdir(obj.dirname)) class Directory: size = DirectorySize() # Descriptor instance def __init__(self, dirname): self.dirname = dirname # Regular instance attribute
confusing magic methods -- indexer
__getitem__
https://www.geeksforgeeks.org/__getitem__-in-python/
数据类型如果允许使用 [] 去访问元素, 则必然实现了此魔法方法。
此方法是 容器协议的一部分。
用于 list索引值, 或者 dict查询。
__getitem__()
is a magic method in Python, which when used in a class, allows its instances to use the[]
(indexer) operators. Say x is an instance of this class, thenx[i]
is roughly equivalent totype(x).__getitem__(x, i)
.The method
__getitem__(self, key)
defines behavior for when an item is accessed, using the notationself[key]
. This is also part of both the mutable and immutable container protocols.
The
__getitem__
magic method is usually used for list indexing, dictionary lookup, or accessing ranges of values. Considering how versatile it is, it’s probably one of Python’s most underutilized magic methods.
# Code to demonstrate use # of __getitem__() in python class Test(object): # This function prints the type # of the object passed as well # as the object item def __getitem__(self, items): print (type(items), items) # Driver code test = Test() test[5] test[5:65:5] test['GeeksforGeeks'] test[1, 'x', 10.0] test['a':'z':2] test[object()]
outputs
<class 'int'> 5 <class 'slice'> slice(5, 65, 5) <class 'str'> GeeksforGeeks <class 'tuple'> (1, 'x', 10.0) <class 'slice'> slice('a', 'z', 2) <class 'object'> <object object at 0x7f75bcd6d0a0>
不同于属性的引用方法, 这两个魔法方法适用于索引属性, 例如 数组,词典,列表。
在这两个方法中,可以提供校验和转换。
There are getter and setter methods as a part of these magical methods. They are implemented by
__getitem__()
and__setitem__()
methods. But, these methods are used only in indexed attributes like arrays, dictionaries, lists e.t.c. Instead of directly accessing and manipulating class attributes, it provides such methods, so these attributes can be modified only by its own instances and thus implements abstraction.Instead of making class attributes as public, these methods make them private, provide validation that only correct values are set to the attributes and the only correct caller has access to these attributes.
class bank_record: def __init__(self, name): self.record = { "name": name, "balance": 100, "transaction":[100] } def __getitem__(self, key): return self.record[key] def __setitem__(self, key, newvalue): if key =="balance" and newvalue != None and newvalue>= 100: self.record[key] += newvalue elif key =="transaction" and newvalue != None: self.record[key].append(newvalue) def getBalance(self): return self.__getitem__("balance") def updateBalance(self, new_balance): self.__setitem__("balance", new_balance) self.__setitem__("transaction", new_balance) def getTransactions(self): return self.__getitem__("transaction") def numTransactions(self): return len(self.record["transaction"]) sam = bank_record("Sam") print("The balance is : "+str(sam.getBalance())) sam.updateBalance(200) print("The new balance is : "+str(sam.getBalance())) print("The no. of transactions are: "+str(sam.numTransactions())) sam.updateBalance(300) print("The new balance is : "+str(sam.getBalance())) print("The no. of transactions are: "+str(sam.numTransactions())) print("The transaction history is: "+ str(sam.getTransactions()))
数据类型决定了其可拥有的魔法方法
https://phoenixnap.com/kb/python-data-types?msclkid=3185a6f7ce7b11eca6bae10924ed6255
容易混淆的两种概念是 attribute 和 item
attribute是 object中的一般的概念, 在python中所有的存在都是对象, 每个对象都有 属性, 可以使用 object.attribute 写法来访问。
item 是abc抽象数据结构中的某些数据结构的实现, 例如 list dict string arrary, 这些数据结构可以看成数据的容器,使用如下写法来访问 object[index]
如下图, 拥有item性质的数据结构有, list tuple string dict(dictionary)
但是这里需要说明的是 dict.get 方法, 实质上是对 __getitem__ 的封装,提供了查找不到,返回值的定制能力。
https://www.tutorialspoint.com/python/dictionary_get.htm?msclkid=18e13d38ce9711ecaecabb37596c6ae5
dict.get(key, default = None)
对于查不到返回值定制的需求, 在collection模块中使用 defaultdict来实现。
Basic Data Types in Python
A data type is a characteristic that tells the compiler (or interpreter) how a programmer intends to use the data. There are two general categories of data types, differing whether the data is changeable after definition:
1. Immutable. Data types that are not changeable after assignment.
2. Mutable. Data types that are changeable after assignment.
Variables store different types of data. Creating a variable of a particular data type creates an object of a data type class. The Python interpreter automatically assumes a type when creating a variable.
The data type of any object is found using the built-in
type()
function. The output shows the name of the class for the given object.
https://docs.python.org/3/library/collections.abc.html?msclkid=6681fc77ce7711eca913c4b402c654b9
所有的数据结构都继承于ABC
Collections Abstract Base Classes
The collections module offers the following ABCs:
ABC
Inherits from
Abstract Methods
Mixin Methods
__contains__
__hash__
__iter__
__next__
__iter__
__reversed__
send
,throw
close
,__iter__
,__next__
__len__
__call__
__contains__
,__iter__
,__len__
__getitem__
,__len__
__contains__
,__iter__
,__reversed__
,index
, andcount
__getitem__
,__setitem__
,__delitem__
,__len__
,insert
Inherited
Sequence
methods andappend
,reverse
,extend
,pop
,remove
, and__iadd__
__getitem__
,__len__
Inherited
Sequence
methods
__contains__
,__iter__
,__len__
__le__
,__lt__
,__eq__
,__ne__
,__gt__
,__ge__
,__and__
,__or__
,__sub__
,__xor__
, andisdisjoint
__contains__
,__iter__
,__len__
,add
,discard
Inherited
Set
methods andclear
,pop
,remove
,__ior__
,__iand__
,__ixor__
, and__isub__
__getitem__
,__iter__
,__len__
__contains__
,keys
,items
,values
,get
,__eq__
, and__ne__
__getitem__
,__setitem__
,__delitem__
,__iter__
,__len__
Inherited
Mapping
methods andpop
,popitem
,clear
,update
, andsetdefault
__len__
__contains__
,__iter__
__contains__
,__iter__
__contains__
,__iter__
__await__
send
,throw
close
__aiter__
__anext__
__aiter__
asend
,athrow
aclose
,__aiter__
,__anext__