Python Basics---Chapter9 Magic Methods, Properties, and Iterators

本文介绍了Python中的特殊方法(魔法方法),包括构造函数`__init__`和`super`函数的使用。文章还探讨了Python的协议,特别是序列和映射协议,如何实现基本的序列行为,并提供了无限序列的示例。此外,还讲解了属性、静态方法、类方法以及迭代器的工作原理,强调了关注对象行为而非其内在结构的设计原则。
摘要由CSDN通过智能技术生成


1. Preface

In Python, some names are spelled in a peculiar manner, with two leading and two trailing underscores which signals that the name has a special significance—you should never invent such names for your own programs. And this kind of methods are called magic methods .

2. Constructor __ init __

  • A constructor is an initializing method of a class which will be called automatically right after the object has been created.
class foobar:
    def __init__(self):
        self.somevar=42
fb=foobar()
fb.somevar
>>>42
  • You can give arguments to __init__ method
class foobar_2:
    def __init__(self,value):# with argument
        self.somevar=value
fb2=foobar_2(42)# set the argument
fb.somevar
>>>
42

3. super function

  • In inheritance, the __init__ of the subclass will overide that of the superclass, and lose some attributes of superclass.

class Bird:
    def __init__(self):
        self.hungry=True
    def eat(self):
        if self.hungry:
            ptint('It needs to eat')
            self.hungry=False
        else:
            print('NO,thanks!')
class SongBird(Bird):
    def __init__(self):
        self.sound='Squawk'
    def sing(self):
        print(self.sound)
sb=SongBird()
sb.eat()
>>>
--------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-11-8dc456f39f61> in <module>()
      1 sb=SongBird()
----> 2 sb.eat()

<ipython-input-10-469072ddb6f8> in eat(self)
      3         self.hungry=True
      4     def eat(self):
----> 5         if self.hungry:
      6             ptint('It needs to eat')
      7             self.hungry=False

AttributeError: 'SongBird' object has no attribute 'hungry'

SongBird class has attribute eat(), but does not have attribute hungry, because the __init__ of SongBird override the __init__ of Bird

  • Use super().\_\_init__() without any argument to solve the problem.
class Bird:
    def __init__(self):
        self.hungry=True
    def eat(self):
        if self.hungry:
            print('It needs to eat')
            self.hungry=False
        else:
            print('NO,thanks!')
class SongBird(Bird):
    def __init__(self):
        super().__init__() # bind the __init__ of superclass
        self.sound='Squawk'
    def sing(self):
        print(self.sound)
sb=SongBird()
sb.eat()
>>>
It needs to eat

super().method() can bind any methods in the superclass to methods in subclass

3. Protocol of Python

  • The word protocol is often used in Python to describe the rules governing some form of behavior. This is somewhat similar to the notion of interfaces mentioned in Chapter 7. The protocol says something about which methods you should implement and what those methods should do. Because polymorphism in Python is based on only the object’s behavior (and not on its ancestry, for example, its class or superclass, and so forth), this is an important concept: where other languages might require an object to belong to a certain class or to implement a certain interface, Python often simply requires it to follow some given protocol. So, to be a sequence, all you have to do is follow the sequence protocol.
  • protocol methods: __name__ : With some protocol methods, you can exert some corresponding operations on the class’ instance, and these oprations will automatically call the protocol methods.

4. The Basic Sequence and Mapping Protocol

  • Sequences and mappings are basically collections of items.

  • They have some protocol methods, and every protocol corresponds to a certain operation on the sequences or mappings

  • To implement their basic behavior (protocol),you need two magic methods if your objects are immutable, or fourif they are mutable. These are all attributes for sequence class, the behaviors a sequence should have.

    • __ len__(self): This method should return the number of items contained in the collection. =>len()

    • __ getitem__(self, key): This should return the value corresponding to the given key. =>list[n],dict[key]

    • __ setitem__(self, key, value): This should store value in a manner associated with key, so it can later be retrieved with __ getitem__.=>list[n]=x, dict[key]=y

    • __ delitem__(self, key): This is called when someone uses the __ del__ statement on a part of the object and should delete the element associated with key.=>del()

  • Some extra requirements are imposed on these methods.

    • For a sequence, if the key is a negative integer, it should be used to count from the end. In other words, treat x[-n] the same as x[len(x)-n].
    • If the key is of an inappropriate type (such as a string key used on a sequence), a TypeError may be raised.
    • If the index of a sequence is of the right type, but outside the allowed range, an
      IndexError should be raised.

5. Example: Creat a Infinite Sequence

  • This implements an arithmetic sequence—a sequence of numbers in which each is greater than the previous one by a constant amount. The first value is given by the constructor parameter start (defaulting to zero), while the step between the values is given by step (defaulting to one). You allow the user to change some of the elements by keeping the exceptions to the general rule in a dictionary called changed. If the element hasn’t been changed, it is calculated as self.start + key * self.step.
def check_index(key):
"""
Is the given key an acceptable index?
To be acceptable, the key should be a non-negative integer. If it
is not an integer, a TypeError is raised; if it is negative, an
IndexError is raised (since the sequence is of infinite length).
"""
    if not isinstance(key,int):
        raise TypeError
    if key<0:
        raise IndexError


class ArithmeticSequence:
    def __init__(self,start=0,step=1):
    """
    Initialize the sequence
   """
        self.start=start
        self.step=step
        self.changed={}


    def __getitem__(self,key):
    """
    get a value from the sequence
    """
        check_index(key)
        try:
            return self.changed[key]
        except :
            return self.start+key*self.step
    def __setitem__(self,key,value):
        check_index(key)
        self.changed[key]=value
a_s=ArithmeticSequence()
a_s[15]
>>>
15

a_s[15]=24
a_s[15]
>>>
24
  • It is impotant to figure out the actions of a class before you creat it, and the actions are the basics to construct a class.

  • The class name of integer object is int.

  • With the protocol methods implemented in the class, some sequence operations can be used on the class.

6. The property function

  • property(fget,fset,fdel,doc) : Taking accessors as parameters( getter first, then setter, the next is deletor, the final is docstring) so that the attribute will have certain properties corresponding to accessors. It is to call the corresponding accessor method when conduct a property. You can use either positional parameters or keyword parameters when using property().
class Rectangle:
    def __init__(self,width,height):
        self.width=width
        self.height=height
    def get_size(self):
        return self.width, self.height
    def set_size(self,size):
        self.width,self.height=size
    size=property(get_size,set_size)
    
r=Rectangle(10,15)
r.size  # call the corresponding accessor get_size which returns a tuple
>>>
(10, 15)

r.size=(100,150)
r.size
>>>
(100, 150)

Because that the size only contains the getter and the setter, so it can only be read or written.

Because when you use the properties of size, it will call the the getter and the setter, so you will get the returns of getter, and when you assign values to size, the form of value must accord with the form of setter’s parameter which is a tuple.

7. Static Methods and Class Methods

  • Static Methods and Class Methods are methods can be used directly by class withou instantializing the class.
  • It can be defined like this:
class MyClass:
    @staticmethod
    def smeth():
        print('This is a static method.')
    @classmethod
    def cmeth(cls):
        print('This is a class method of',cls)
MyClass().smeth()
MyClass().cmeth()
>>>
This is a static method.
This is a class method of <class '__main__.MyClass'>

Static methods are defined without self arguments, and they can be called directly on the class itself.

Class methods are defined with a self-like parameter normally called cls. You can call class methods directly on the class object too, but the cls parameter then automatically is bound to the class.

8. Iterators

  • The iterator protocol: to iterate means to repeat something several times. In addtion to sequences and dictionaries, you can iterate over other objects------objects that implement the __ iter__ method.
  • The __ iter__ method returns an iterator , which is any object with a method called __ next__ , which is callable without any arguments.
  • When you call the __ next__ method, the iterator should return its “next value.” If the method is called and the iterator has no more values to return, it should raise a StopIteration exception.
class Fib:
    def __init__(self):
        self.a=0
        self.b=1
    def __iter__(self): 
        return self
    def __next__(self):
        self.a,self.b=self.b,self.a+self.b
        return self.a
fibs=Fib()
for f in fibs:
    if f<1000:
        print(f)
>>>
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987

To make a class Fibs which can be iterated, this class should have a method __ iter__ which returns the iterator object (Fibs itself in this case) , this iterator object ( Fibs itself in this case) shoud have the __ next__ method to return the next value of the object.

  • In many cases, you would put the iter method in another object, which you would use in the for loop. That would then return your iterator. It is recommended that iterators implement an __iter__ method of their own in addition (returning self, just as I did here), so they themselves can be used directly in for loops.

9. What to do rather than what it is

When you construct a class, pay attention to the performances you want the object to have. The main work should be to construct method corresponding to the performances. For example, in the Fibs example, you want the object to be iterated, you just implement iterator protocols, and if you want the object to have the performances of sequence ( like read by index) ,just implement sequence protocol methods.

10. iter() and next()

iter() : the built-in function iter() can return a iterator object of a iterable object.
next() : the built-in function next() return the next value of the iterator object.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值