This is the 25th day of my participation in Gwen Challenge

‘Limit instance attributes :__slots__, turn a method into a property call: @Property decorator, multiple inheritance &MixIn, Custom classes, enumerated classes: Enum, metaclass’

Restrict instance attributes:__slots__

Restrict instance attributes such as name and age to Student instances only. Since ‘score’ is not put in __slots__, the score attribute cannot be bound, and attempting to bind score will result in an AttributeError error. Note: Attributes defined by __slots__ apply only to the current class instance, not to inherited subclasses

class Student(object) :
    __slots__ = ('name'.'age') Use a tuple to define the name of the property that is allowed to bind
s = Student()
s.name='a'
s.age=11
s.score=99 # AttributeError: 'Student' object has no attribute 'score'
Copy the code

A subclass instance is allowed to define its own __slots__ plus its parent’s __slots__.

To call a method as a property:@propertyA decorator

To turn a getter into a property, you simply add @property, and @ Property itself creates another decorator, @score.setter, that turns a setter into a property assignment

class Student(object) :

    @property
    def score(self) :
        return self._score

    @score.setter
    def score(self, value) :
        if not isinstance(value, int) :raise ValueError('score must be an integer! ')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100! ')
        self._score = value

s = Student()
s.score=11
s.score
Copy the code

So if you don’t say at sign score.setter you can only read this property

Multiple inheritance &MixIn

๏นโŠ™ This is different from Java, in Java can only single inheritance, much implementation. In Python, you simply add the parent class in parentheses.

class Dog(Mammal, RunnableMixIn) :
    pass
Copy the code

The above example is also called a mixin by design

The purpose of mixins is to add functionality to a class, so that when designing a class, we prioritize combining the functionality of multiple mixins through multiple inheritance, rather than designing multi-level and complex inheritance relationships.

Note The suffix MixIn (RunnableMixIn) should be added to the name of a class without adding the suffix MixIn (for example, RunnableMixIn).

Python comes with two types of network services, TCPServer and UDPServer, and to serve multiple users at the same time, you must use the multi-process or multi-threaded model, which is provided by ForkingMixIn and ThreadingMixIn.

UDP service in multithreaded mode:

class MyUDPServer(UDPServer, ThreadingMixIn) :
    pass
Copy the code

Custom classes

Python3 official documentation for custom classes

__str__().__repr__()

These are the same as Java’s toString() methods, except __str__() returns the string seen by the user, __repr__() returns the string seen by the program developer, and __repr__() is used for debugging

class Student(object) :
    def __init__(self, name) :
        self.name = name
    def __str__(self) : # 2
        return 'Student object (name=%s)' % self.name
    __repr__ = __str__ # 1
s=Student('ken')
s # 2
print(s) # 1 Student object (name=ken)
# Comment out the content of # 1 to see the effect
Copy the code

__iter__

If a class wants to be used for… An in loop, like a list or tuple, must implement an __iter__() method that returns an iterator. Python’s for loop then calls the iterator’s __next__() method to get the next value of the loop. Exit the loop until a StopIteration error is encountered.

It was also noted in a previous post by this blogger: Python3 Introduction Note 3: Advanced Features – Slicing, Iteration, List Generators, Generators, iterators

class Fib(object) :
    def __init__(self) :
        self.a, self.b = 0.1 Initialize two counters A, b

    def __iter__(self) :
        return self The instance itself is an iterator, so return itself

    def __next__(self) :
        self.a, self.b = self.b, self.a + self.b # Calculate the next value
        if self.a > 100: Conditions for exiting the loop
            raise StopIteration()
        return self.a # return the next value

for n in Fib():
    print(n) # 1 1 2 3 5 8... 89
Copy the code

__getitem__

  1. Fetch elements by subscript

    class Fib(object) :
        def __getitem__(self, n) :
            a, b = 1.1
            for x in range(n):
                a, b = b, a + b
            return a
    f = Fib()
    f[10] # 89
    Copy the code
  2. slice

Getitem () may pass an int or a slice, so check:

class Fib(object) :
    def __getitem__(self, n) :
        if isinstance(n, int) :# n is the index
            a, b = 1.1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice) :# n is slice
            start = n.start
            stop = n.stop
            step = n.step
            print('step:',step)
            if start is None:
                start = 0
            if step is None:
                step = 1
            a, b = 1.1
            L = []
            for x in range(stop):
                if x >= start:
                    if(x%step==0):
                        L.append(a)
                a, b = b, a + b
            return L
f=Fib()
print(f[:10]) # [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
print(f[:10:2]) # [1, 2, 5, 13, 34]
print(f[10]) # 89
Copy the code

__call__

Any class simply needs to define a __call__() method to call an instance directly.

How do you determine whether a variable is an object or a function? Using the callable() function, we can determine if an object is “callable”.

class Student(object) :
    def __init__(self, name) :
        self.name = name

    def __call__(self) :
        print('My name is %s.' % self.name)

s = Student('Michael')
if callable(s):
    s() # My name is Michael.
Copy the code

Dynamically returns a property:__getattr__

This is in the last noteGetting Started in Python Notes 6: Object-oriented programming”

class Student(object) :

    def __getattr__(self, attr) :
        if attr=='age':
            return lambda: 25
        elif attr =='name':
            return 'Amy'
s = Student()
print(s.age()) Note that this returns a lambda expression, and you need to call this method to get the value
print(s.name) # Amy 

Copy the code

Example of a chain call:

class Chain(object) :

    def __init__(self, path=' ') :
        self._path = path

    def __getattr__(self, path) :
        return Chain('%s/%s' % (self._path, path))

    def __call__(self, path) :
        return Chain('%s/%s' % (self._path, path))

    def __str__(self) :
        return self._path

    __repr__ = __str__

print(Chain().status.user.timeline.list) # /status/user/timeline/list

# Notice that chain returns the chain object, so this users(' Michael ') is well understood.
print(Chain().users('michael').repos) # /users/michael/repos
Copy the code

Use the Enum class: Enum

Enumeration types define a class type, and then each constant is a unique instance of class

from enum import Enum

Month = Enum('Month', ('Jan'.'Feb'.'Mar'.'Apr'.'May'.'Jun'.'Jul'.'Aug'.'Sep'.'Oct'.'Nov'.'Dec'))

for name, member in Month.__members__.items():
    print(name, '= >', member, ', ', member.value)

The # value attribute is an int constant automatically assigned to the member, counting from 1 by default.

# Jan => Month.Jan , 1
# Feb => Month.Feb , 2
# Mar => Month.Mar , 3
#.
#.
#.
# Dec => Month.Dec , 12

Copy the code

There are two ways to get enumeration constants:

  1. By member name
  2. According to the value value
from enum import Enum, unique

@unique The # @unique decorator helps us check to make sure there are no duplicate values.
class Weekday(Enum) :
    Sun = 0 # Sun value is set to 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6
print(Weekday.Mon,'=',Weekday.Mon.value) # Weekday.Mon = 1
print(Weekday['Mon'].'=',Weekday.Mon.value)  # Weekday.Mon = 1
print(Weekday(1),'=',Weekday.Mon.value)  # Weekday.Mon = 1
for name, member in Weekday.__members__.items():
    print(name, '= >', member)
Copy the code

Quiz: Change the gender property to an enumerated type, avoiding strings

class Gender(Enum) :
    Male = 0
    Female = 1

class Student(object) :
    def __init__(self, name, gender) :
        self.name = name
        self.gender = gender
    def __str__(self) :
          return 'Student object name={},gender={}'.format(self.name,self.gender)
    __repr__=__str__
bart = Student('Bart', Gender.Male)
print(bart) # Student object name=Bart,gender=Gender.Male
bart # Student object name=Bart,gender=Gender.Male
Copy the code

Using a metaclass

type()

This was also covered in the last post, and now I want to supplement it with other knowledge points

  1. type()The function can view the type of a type or variable
  2. type()Functions can either return the type of an object or create a new type
print(type(str)) # 
      
        STR is class, so type is type
      
print(type('123')) # 
      
        '123' is an example. So the type is STR
      

def fn(self, name='world') : Define the function first
    print('Hello, %s.' % name)
Copy the code

Create a Hello class using type() instead of class Hello(object)… Definition:

To create a class object, the type() function takes three arguments in turn:

  1. Class name;
  2. A collection of inherited parent classes. Note that Python supports multiple inheritance. If there is only one parent class, remember the single-element form of a tuple;
  3. The class method name is bound to the function. Here we bind the function fn to the method name Hello.

As shown here (these ides help us understand this function more quickly) :

def fn(self, name='world') :
    return name
Hello=type('Hello', (object,),dict(hello=fn)) Create Hello class
h=Hello() # note that Instance is created here
print(h.hello('1'))
print(type(Hello)) # <class 'type'>
print(type(h)) # <class '__main__.Hello'>
Copy the code

metaclass

In addition to using type() to dynamically create classes, you can control the creation behavior of classes by using metaclass, the most difficult magic code in Python object-oriented to understand and use (deprecated ๐Ÿ˜† hahaha).

The general understanding is that it can define the behavior when creating a class.

# metaclass is a template for the class, so it must be derived from type 'type' :
class ListMetaclass(type) :
    def __new__(cls, name, bases, attrs) :
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)
class MyList(list, metaclass=ListMetaclass) :
    pass
L = MyList()
L.add(1)
L # 1
Copy the code

A typical example of using metaclass is the ORM framework (๐Ÿ˜ฑ exposed). Here’s another example: ๐Ÿ˜„

The last

Welcome friends to discuss the question ~

If you think this article is good, please give it a thumbs-up ๐Ÿ˜

Let’s start this unexpected meeting! ~

Welcome to leave a message! Thanks for your support! ใƒพ(โ‰งโ–ฝโ‰ฆ*)o go!!

I’m 4ye. We should… next time. See you soon!! ๐Ÿ˜†