Python basic notes

Time:2019-10-8

First, inheritance

'''
1. What is inheritance
    Inheritance is a way of creating new classes. New classes are called subclasses and inherited classes are called base classes, parent classes and superclasses.
    Inheritance describes a "hereditary" relationship: subclasses can reuse attributes of the parent class

Inheritance in Python pays attention to two points:
   1. Supporting a subclass inheriting multiple parent classes at the same time in python.
   2. There are two categories in python:
            New Class: But any class that inherits object and its subclasses... They are all new types.
                In Python 3, if a class does not inherit human classes, it defaults to inherit object classes, that is, all classes in Python 3 are new classes.

            Classic Classes: Classes that do not inherit objects, and subclasses of that class... They are all classical classes.
                It is only in Python 2 that new and classical classes can be distinguished

2. Why to use inheritance
     Reducing Code Redundancy
3. How to Use Inheritance

class Parent1(object):
    pass
class Parent2:
    pass
class Subclass1(Parent1,Parent2):
    pass
print(Subclass1.__bases__)


# 2. Priority of property search in the context of inheritance
      # When a class is a classical class, in the case of multiple inheritance, when the attributes to be searched do not exist, they will be searched in a depth-first manner.
      # When a class is a new type of class, in the case of multiple inheritance, when the attributes to be searched do not exist, they will be searched in a breadth-first way.
Inheritance solves the problem of code redundancy between classes. It must be that one class is a subclass of another class. By summarizing the similarities between objects, we can get classes. By summarizing the similarities between classes, we can get the parent class of classes.
Sequence of Attribute Search in Multi-Inheritance Context: Objects - "Classes of Objects -" is found one by one in a left-to-right order.
# Once the problem of diamond inheritance arises, the difference between the new class and the classical class in attribute lookup is # new class: breadth first search, top class # classical class in the last branch: depth first search, top class in the first branch
# The way to reuse the function of the parent class in the new method derived from the subclass is as follows:

class OldboyPeople:
    school='Oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


class OldboyStudent(OldboyPeople):

    Stu1, "Li te Dan", 18,'female'
    def __init__(self,name,age,sex,num=0):
        OldboyPeople.__init__ (self, name, age, sex) #OldboyPeople.__init__ (stu1, Li te Dan, 18,'female')

        self.score=num

    def choose_course(self):
        print('%s is choosing course' %self.name)



class OldboyTeacher(OldboyPeople):

    def __init__(self,name,age,sex,level):
        OldboyPeople.__init__(self,name,age,sex)

        self.level=level

    def score(self,stu,num):
        stu.score=num


Stu1=OldboyStudent ("Li te Dan", 18,'female') #OldboyStudent.__init__ (stu1, "Li te Dan", 18,'female')
print(stu1.__dict__)

tea1=OldboyTeacher('egon',18,'male',10) ##OldboyTeacher.__init__(tea1,'egon',18,'male',10)
print(tea1.__dict__)



code

The second way to reuse parent functions in new methods derived from subclasses is to use Python 2: super (its own class name, object itself) only in subclasses to call super () in Python 3: super () to get a special object, which is specifically used to refer to attributes in the parent class!!!! Refer to the MRO list completely!!!! Note:  1. This way and inheritance depend strictly on inherited Mr. O List # 2. Access is a binding method, with the effect of automatically passing values.

class OldboyPeople:
    school='Oldboy'

    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


class OldboyStudent(OldboyPeople):


    def __init__(self,name,age,sex,num=0):
        OldboyPeople.__init__ (self, name, age, sex) #OldboyPeople.__init__ (stu1, Li te Dan, 18,'female')
        super(OldboyStudent,self).__init__(name,age,sex)

        self.score=num

    def choose_course(self):
        print('%s is choosing course' %self.name)



class OldboyTeacher(OldboyPeople):

    def __init__(self,name,age,sex,level):
        super().__init__(name,age,sex)

        self.level=level

    def score(self,stu,num):
        stu.score=num

Case study
class A:
    def test(self):
        print('A.test()')
        super().test()

class B:
    def test(self):
        print('from B')

class C(A,B):
    pass

obj=C()
print(C.mro())
#[, , , ]
obj.test()
'''
A.test()
from B
'''

code

Class inheritance has two meanings:

1. Change 2. Expansion

Composition refers to an object having an attribute whose value is an object of another class.
Using composition can reduce code redundancy between classes

Two. Polymorphism

1 polymorphism refers to the polymorphism of multiple forms of the same thing 2 polymorphism: can directly use the object advantages without considering the specific types of objects: normalization, simplification of the use of objects

Polymorphism is a concrete implementation mechanism of the two meanings of classes, that is, calling different classes to instantiate the same method under the object, the implementation process is different.

The standard type in Python is a good demonstration of the concept of polymorphism

import abc
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def speak(self):
        pass
    @abc.abstractmethod
    def run(self):
        pass
# abstract base classes: are used to specify specifications, but all subclasses inheriting this class must implement speak and run, and the names must be spoke and run
# Note: The abstract base class cannot be instantiated
Animal()

class People(Animal):
    def speak(self):
        print('say hello')
    def run(self):
        pass
class Dog(Animal):
    def speak(self):
        Print ('Wang Wang Wang Wang')
    def run(self):
        pass
class Pig(Animal):
    def speak(self):
        Print ('hum hum hum')
    def run(self):
        pass
obj1=People()
obj2=Dog()
obj3=Pig()
Obj1, obj2, obj3 are all animals.
obj1.speak()
obj2.speak()
obj3.speak()
def speak(animal):
    animal.speak()
speak(obj1)
speak(obj2)
speak(obj3)
obj1=[1,2,3]
obj2='hello'
obj3={'x':1}
print(obj1.__len__())
print(obj2.__len__())
print(obj3.__len__())
print(len(obj1))
print(len(obj2))
print(len(obj3))

code

Three, encapsulation

1 what is encapsulation, that is, data attribute or function attribute is stored in a namespace, which means that the content is hidden. The hiding is to make sure that the area is divided into the inside and outside, that is, the hiding is external to the inside (outside the class, and the inside can be accessed). 2 why do we need to encapsulate 1. data attributes??? 2. 2. function properties:?? 3 how to encapsulate? Begin with before the attributes defined in the class

The first level of encapsulation: class is sack, which itself is a kind of encapsulation

Encapsulation at the second level: Classes are defined as private and are only used internally and not accessible externally.

The third level of encapsulation: clear distinction between internal and external, internal implementation logic, external unknown, and provide an access interface for encapsulated logic for external use (this is the real encapsulation)

class People:
    __country='China' #_People__country='China'
    __n=111           #_People__n=111

    def __init__(self,name):
        self.__name=name #self._People__name=name

    def run(self):
        print('%s is running' %self.__name) #self._People__name

print(People.__country)

obj=People('egon')
print(obj.__name)
print(obj.run)
obj.run()

print(People.__dict__)
print(People._People__country)
print(obj.__dict__)
print(obj._People__name)
Attention should be paid to: 1. This kind of hiding is only a grammatical distortion, which does not really restrict access. 2. This distortion only occurs once when the grammar is detected in the class definition stage, and the new attributes at the beginning of after the class definition stage will not change.
3. In inheritance, if the parent does not want the subclass to override its own method, it can start with _ before the method.
The real intention of packaging:
The purpose of encapsulating data attributes or function attributes is to use them in the future. The purpose of encapsulating data attributes is not to allow external direct use of 1. encapsulating data attributes: hiding data attributes is to prevent external direct manipulation of hidden attributes, and indirectly manipulating attributes through interfaces opened in classes. We can attach arbitrary control logic to interfaces to strictly control users. Operations on attributes
2. Sealing function attributes: isolation complexity

IV. Category Methods and Decorators

There are two main types of functions defined in a class (three subspecies). One is binding method, the other is non-binding method # 1. Binding method:  A decorator classmethod # 2. Unbound method # features: neither bound to class nor bound to object, means that objects or classes can be invoked, but whoever calls is a normal function, there is no automatic value passing.
class Foo:
    def func1(self):
        Print ('methods bound to objects', self)

    @classmethod
    def func2(cls):
        Print ('methods bound to classes:', cls)

    @staticmethod
    def func3():
        Print ('ordinary function')

obj=Foo()
obj.func1()
print(obj)

Foo.func2()

# Binding method
print(obj.func1)
print(Foo.func2)

# unbound method
print(obj.func3)
print(Foo.func3)

What is an ornament?

Apparatus are functions, decoration is decoration, meaning adding new functions to other functions

Decorator Definition: Essentially function, function is to add new functions to other functions

Property decorator is to disguise a function attribute as a data attribute

1. Do not modify the source code of the decorated function (open and closed principle)

2. After adding new functions to the decorated function, the call mode of the decorated function is not changed.

user_list=[
    {'name':'alex','passwd':'123'},
    {'name':'linhaifeng','passwd':'123'},
    {'name':'wupeiqi','passwd':'123'},
    {'name':'yuanhao','passwd':'123'},
]

current_user={'username':None,'login':False}
def auth(auth_type='file'):
    def auth_deco(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                if current_user['username'] and current_user['login']:
                    res=func(*args,**kwargs)
                    return res
                Username = input ('username:'). strip ()
                Passwd = input ('password:'). strip ()

                for index,user_dic in enumerate(user_list):
                    if username == user_dic['name'] and passwd == user_dic['passwd']:
                        current_user['username']=username
                        current_user['login']=True
                        res=func(*args,**kwargs)
                        return res
                else:
                    Print ('User name or password error, login again')
            elif auth_type == 'ldap':
                Print ("Barbara little devil Fairy")
                res=func(*args,**kwargs)
                return res
        return wrapper
    return auth_deco


# auth (auth_type='file') is running a function and returning auth_deco, so @auth (auth_type='file')
# It's equivalent to @auth_deco, but now our auth_deco is used as a closure application, and the outer package auth leaves an auth_type='file'parameter for it.
@auth(auth_type='ldap')
def index():
    Print ('Welcome to Home Page')

@auth(auth_type='ldap')
def home():
    Print ('Here's your home')

def shopping_car():
    Print ('Look at the shopping cart, ah pro')

def order():
    Print ('View orders, ah pro')

# print(user_list)
index()
# print(user_list)
home()

# Decorator with ginseng

View Code

def deco(func):
    print('---')
    func.x=1
    func.y=2
    func.z=3
    return func

# Everything is an object.
@deco    #test=deco(test)
def test():
    print('test_func_run')
test.x=1
print(test.__dict__)

@deco  #Foo=deco(Foo)
class Foo:
    pass

f1=Foo()
print(f1.__dict__)
print(Foo.__dict__)
print(f1.x)

View Code

def Typed(**kwargs):
    def deco(obj):
        # print('+++++',kwargs)
        # print('obj_name',obj)
        for key,val in kwargs.items():
            # obj.__dict__[key]=[val]
            # obj.key=val
            setattr(obj,key,val)
        return obj
    # print('---',kwargs)
    return deco

@Typed(x=1,y=2,z=3)   #Typed(x=1,y=2,x=3)---> @deco ---->Foo=deco(Foo)
class Foo:
    pass
print(Foo.__dict__)

# @deco
@Typed(name='egon')
class Bar:
    pass
print(Bar.name)

View Code

Decorator = higher-order function + function nesting + closure

@ timer #@timer is equal to cal = timer (cal)
def cal(array):
    res=0
    for i in array:
        res+=i
    return res

cal(range(10))
'''
Closure: Putting defining variables in a scope is equivalent to hitting a package
'''
def father(name):
    def son():
        # name='alex'
        Print ('My father is [% s]'% name)
        def grandson():
            # name='wupeiqi'
            Print ('My grandfather is [% s]'% name)
        grandson()
    son()

father('XXX')
class Room:
    tag="mmp"
    def __init__(self,name,owner,width,length,heigh):
        self.name=name
        self.owner=owner
        self.width=width
        self.length=length
        self.heigh=heigh

    @property
    def cal_area(self):
        # print ('% s lives in% s total area is% s'% (self. owner, self. name, self. width * self. length))
        return self.width*self.length
    @property
    def cal_tiji(self):
        return self.length*self.width*self.heigh


    def test(cls):
        print('from test',self.name)

    @ Class method # Method for class usage only ___________ Method
    def tell_info(cls):
        print(cls)
        print('----->',cls.tag)


R1 = Room ('Toilet','av', 100, 100, 10000)
R2=Room ('''','abc', 10,10,10)

Room. tell_info()# has a special meaning, the class is bound to the instance when calling its own function attribute.


print(Room.tag)
# print ('% s lives in% s total area is% s'% (r1. owner, r1. name, r1. width * r1. length)

print(r1.cal_area)
print(r2.cal_area)
print(r1.cal_tiji)
print(r1.name)
print(r2.name)

View Code
class Room:
    tag="mmp"
    def __init__(self,name,owner,width,length,heigh):
        self.name=name
        self.owner=owner
        self.width=width
        self.length=length
        self.heigh=heigh

    @ Property # Attribute Method
    def cal_area(self):
        # print ('% s lives in% s total area is% s'% (self. owner, self. name, self. width * self. length))
        return self.width*self.length
    @property
    def cal_tiji(self):
        return self.length*self.width*self.heigh


    @ Classmethod # class method, a method specially used by classes
    def tell_info(cls,x):
        print(cls)
        print('----->',cls.tag,x)

    # def test(x,y):
    #     print(x,y)


    @ Static method # static method, class slave Toolkit
    def wash_body(a,b,c):
        Print ('% s% s% s% s bath', (a, b, c))

Room.wash_body('alex','yuanhao','wupenqi')


R1 = Room ('Toilet','alex', 100, 100, 10000)


View Code V. Attribute Method
class List(list):
    def append(self, object):
        if type(object)  is str:
            # self.append(object)
            # list.append(self,object)
            super().append(object)
        else:
            Print ('can only add strings')
    def show_midlle(self):
        mid_index=int(len(self)/2)
        return  self[mid_index]

l1=List('helloworld')
l1.append('SB')
print(l1)

View Code
class Chinese:
    country='China'
    def __init__(self,name):
        self.name=name

    def play_ball(self,ball):
        Print ('% s hit% s'% (self. name, ball))

p1=Chinese('alex')
print(p1.__dict__)

Check out
print(p1.name)
P1. play_ball ('basketball')

Increase in number

p1.age=18
print(p1.__dict__)
print(p1.age)

def test(self):
    Print ('Instance Function Properties')
p1.test=test
print(p1.__dict__)
p1.test(p1)

## Do not modify the underlying attribute dictionary
# p1.__dict__['sex']='male'
# print(p1.__dict__)
# print(p1.sex)

Amendment
p1.age=19
print(p1.__dict__)
print(p1.age)

Delete
del p1.age
print(p1.__dict__)

View Code
class Chinese:
    contry='China'
    dang='gongchandang'
    def __init__(self,name):
        self.name=name

    def play_ball(self,ball):
        Print ('% s is typing% s'% (self, name))
Check out
print(Chinese.contry)

Amendment
Chinese.contry='japan'
print(Chinese.contry)
p1=Chinese('alex')
print(p1.__dict__)
print(p1.contry)

Delete
del Chinese.dang
del Chinese.contry
print(Chinese.__dict__)

Increase in number
def eat_food(self,food):
    Chinese.eat=eat_food()
    print(Chinese.__dict__)

    p1.eat('aaa')

View Code
Built-in method:
_ str_: automatically triggers when an object is printed, and then takes the return value of the binding method (which must be a string type) as the result of this printing.
class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def __str__(self):
        return '' %(self.name,self.age)

obj1=People('egon',18)
obj2=People('lxx',38)

print(obj1) #print(obj1.__str__())
print(obj2) #print(obj2.__str__())

_ Del_: Automatically triggers before an object is deleted. Within this method, the recovery of system resources related to the object should be performed.
class Foo:
    def __init__(self,filename,encoding='utf-8'):
        self.f=open(filename,'r',encoding=encoding)

    def __del__(self):
        # print('run.....')
        self.f.close()

obj=Foo()
del obj #obj.__del__()

#obj.__del__()

6. Higher-order functions, iterators, generators

Definition 1 of higher-order function, parameter received by function is a function name 2, return value of function is a function name 3, satisfying any of the above conditions, can be called higher-order function.
import  time
def Foo():
    print('------')

def test(func):
    print(func)
    start_time=time.time()
    func()
    stop_time=time.time()
    print('func_runtime %s' %(stop_time-start_time))

Foo()
Test (Foo)  Modify the way function calls are made
def run():
    print('from_run')

run()

def test():
    Yield 1 # pause, entry
    print('from_run')
    yield 2
    print('from_run')

T = test () generates generator objects
# wake-up iterator
t.__next__()
next(t)  # yield10
t.send('123')
age=10
res=True if age>10 else False
# if form ternary expression
L=['a'for I in range (10)]# list parsing
G_l=('a'for I in range (10)# generator expression
print(l)
def test():
    for i in range(4):
        yield 1

t=test()

class Foo:
    def __init__(self,n):
        self.n=n
    def __iter__(self):
        return self
    def __next__(self):
        if self.n>=100:
            raise StopIteration
        self.n+=1
        return self.n
# l = list('hello')
# for i in l:
    # print(i)


f1 = Foo(10)
for i in f1: #f1.__iter__()----------->iter(f1)
    print(i)

View Code

Seven. Reflection

Reflection refers to the ability of a program to access, detect and modify its own state or behavior (introspection).

Isinstance (obj, cls) checks whether obj is an object like CLS

Issubclass (sub, super) checks whether the subclass is a derived class of the superclass

Reflection in Python object-oriented: Operating object-related properties in the form of strings. Everything in Python is an object (reflection can be used)

Four functions for introspection

hasattr(object,name)
Determine whether there is a method or attribute corresponding to a name string in an object

getattr(object,name,default=None)
Get named attributes from objects; getattr (x,'y') is equivalent to x.y.
When a default parameter is given, it is returned when the attribute is not given.
No, in this case an exception will be thrown.

setattr(x,y,v)
Sets the named property on a given object to the specified value.
Setattr (x,'y', v) is equal to'x.y = v

delattr(x,y)
Delete named attributes from a given object.
Delattr (x,'y') is equivalent to'del x.y'.

class Foo:
     pass

class Bar(Foo):
    pass

obj=Bar()

 print(isinstance(obj,Bar))
print(isinstance([],list))

print(issubclass(Bar,Foo))



# Reflection: Refers to manipulating attributes through strings
class Foo:
    def __init__(self,name):
        self.name=name


obj=Foo('eg')


# hasattr()
# print(hasattr(obj,'name')) #'name' in obj.__dict__

# getattr()
# print(getattr(obj,'name')) #obj.__dict__['name']
# print(getattr(obj,'age')) #obj.__dict__['age']
# print(getattr(obj,'age',None)) #obj.__dict__['age']

# setattr()
# setattr(obj,'age',18) #obj.age=18
# setattr(obj,'name','EG') #obj.name='EG'
# print(obj.__dict__)

# delattr()
# delattr(obj,'name')# del obj.name
# print(obj.__dict__)

code

Import other modules and use reflection to find out if there is a method for the module

Benefits of reflection

One advantage:

The implementation of pluggable mechanism can define interfaces in advance, and the interface will be executed only after being completed. This means plug and play, which is actually a kind of “late binding”. What does that mean? That is, you can write the main logic in advance (only define the interface), and then later implement the function of the interface.

Benefits two:

Dynamic Import Module (Based on Reflecting Current Module Members)

Module_a B c=_import_('dic.a.b.c')________________
# module_abc gets the top-level DIC module
module_abc.a.b.c

8. _setattr_, _delattr_, _getattr__

Demonstration of the usage of the three:

class Foo:
    x=1
    def __init__(self,y):
        self.y=y

    def __getattr__(self, item):
        Print ('--> from getattr: the attribute you are looking for does not exist')


    def __setattr__(self, key, value):
        print('----> from setattr')
        # Self. key = value  This is infinitely recursive. Think about it.
        # Self. Dict [key]= value should be used

    def __delattr__(self, item):
        print('----> from delattr')
        # del self. item  infinite recursion
        self.__dict__.pop(item)

#_ Setattr_ Adding/modifying attributes triggers its execution
f1=Foo(10)
Print (f1. _ Dict _) because you rewrite _ setattr, any assignment will trigger its operation, you did not write anything, is not assignment, unless you directly operate the attribute dictionary, otherwise you can never assign value.
f1.z=3
print(f1.__dict__)

#_ Delattr_ triggers when attributes are deleted
F1. _dict_ ['a']= 3 # We can modify the attribute dictionary directly to complete the operation of adding/modifying attributes.
del f1.a
print(f1.__dict__)

#_ getattr_ triggers only when the calling property is used and the property does not exist
f1.xxxxxx

To grant authorization

Authorization is a feature of packaging. Packaging a type is usually customized to existing types, which can create, modify or delete the functions of the original product. Others remain the same. The process of authorization is that all the updated functions are handled by some part of the new class, but the existing functions are authorized to the default attributes of the object.

The key to authorization is to override the _getattr_ method

The main way to authorize is to _getattr_ map undefined methods to real built-in function files
import time
class FileHandle:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        self.file=open(filename,mode,encoding=encoding)
        self.mode=mode
        self.encoding=encoding
    def write(self,line):
        print('---------',line)
        t=time.strftime('%Y-%m-%d %X')
        self.file.write('%s %s' %(t,line))

    def __getattr__(self, item):
        # print(item,type(item))
        return getattr(self.file,item)

    # def read(self):
    #     pass


f1=FileHandle('a.txt','r+')
print(f1.__dict__)
Print ('---->', f1. read) # triggers getattr
# print(f1.write)
f1.write('11111111211111\n')
# f1.seek(0)
# sys_f=open('b.txt','w+')
# The main way to authorize is to _getattr_ map undefined methods to real built-in function files
class List:
    def __init__(self,seq,permission=False):
        self.seq=seq
        self.permission=permission
    def clear(self):
        if not self.permission:
            raise PermissionError('not allow the operation')
        self.seq.clear()

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)
l=List([1,2,3])
# L. clear ()# At this time, no permission is granted and an exception is thrown.


l.permission=True
print(l)
l.clear()
print(l)

# access insert method based on authorization
l.insert(0,-123)
print(l)

9. _getattribute__

Review _getattr__

class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        Print ('I'm executing it')
        # return self.__dict__[item]

f1=Foo(10)
print(f1.x)
Attribute access that does not exist in f1.xxxxx triggers _getattr__
class Foo:
    def __init__(self,x):
        self.x=x

    def __getattribute__(self, item):
        Print ('I will execute it whether it exists or not')

f1=Foo(10)
f1.x
f1.xxxxxx

__getattribute__

 When _getattribute_ and _getattr_ coexist, only _getattrbute_ will be executed unless _getattribute_ throws an exception AttributeError during execution.

Both of them appear at the same time.

class Foo:
    def __init__(self,x):
        self.x=x

    def __getattr__(self, item):
        Print ('I'm executing it')
        # return self.__dict__[item]
    def __getattribute__(self, item):
        Print ('I will execute it whether it exists or not')
        Raise AttributeError ('Haha')

f1=Foo(10)
f1.x
f1.xxxxxx

Descriptors (_get_, _set_, _delete_)

1. What is the descriptor?

Descriptor is essentially a new class in which at least one of _get_(), _set_(), _delete_() is implemented, which is also called descriptor protocol.

_ get_(): Triggers when an attribute is called
_ set_(): Triggers when assigning an attribute
_ delete_(): Triggers when del deletes attributes

ClassFoo:  Foo in Python 3 is a new class that implements three methods, called a descriptor
    def __get__(self, instance, owner):
        pass
    def __set__(self, instance, value):
        pass
    def __delete__(self, instance):
        pass

The function of a descriptor is to proxy the attributes of another class (the descriptor must be defined as the class attributes of this class, not in the constructor).

class Foo:
    def __get__(self, instance, owner):
        Print ('trigger get')
    def __set__(self, instance, value):
        Print ('trigger set')
    def __delete__(self, instance):
        Print ('trigger delete')

# A new class containing these three methods is called a descriptor, and instances generated by this class call/assign/delete attributes without triggering the three methods.
f1=Foo()
f1.name='egon'
f1.name
del f1.name
# Question: When and where will trigger the execution of these three methods?
class Foo:
    def __get__(self, instance, owner):
        Print ('- - get method')

    def __set__(self, instance, value):
        Print ('- - set method')
        instance.__dict__['x']=value

    def __delete__(self, instance):
        Print ('- - delete method')

class Bar:
    X = Foo ()# Defines class attributes as another class
    def __init__(self,n):
        self.x=n

b1=Bar(10)
print(b1.__dict__)

A data descriptor: implements at least _get_() and _set_()

class Foo:
   def __set__(self, instance, value):
      print('set')
   def __get__(self, instance, owner):
      print('get')

Two non-data descriptors: no _set_()

 class Foo:
     def __get__(self, instance, owner):
         print('get')

Matters needing attention:
A descriptor itself should be defined as a new type class, and the proxy class should be a new type class.
Second, descriptors must be defined as class attributes of this class, not as constructors.
Thirdly, we should strictly follow the priority, which is from high to low.

1. categories of attributes
2. Data Descriptor
3. Instance attributes
4. Non-data descriptors
5. Unfound property trigger _getattr_()

# Descriptor Str
class Str:
    def __get__(self, instance, owner):
        Print ('Str call')
    def __set__(self, instance, value):
        Print ('Str Settings...')
    def __delete__(self, instance):
        Print ('Str deletes...')

class People:
    name=Str()
    Def init (self, name, age): name is proxied by Str class and age by Int class.
        self.name=name
        self.age=age


# Based on the above demonstration, we already know that defining a descriptor in a class is a class attribute that exists in the class attribute dictionary, not the instance attribute dictionary.

# Now that the descriptor is defined as a class attribute, it must be invoked directly by the class name, right?
People. name en, calling the class attribute name, is essentially calling the descriptor Str, triggering _get_()

People. name ='egon'. What about assignment? I went and did not trigger _set_()
Del People. name try del immediately. I went there and did not trigger _delete_()
Conclusion: descriptors have no effect on classes.

'''
Reason: Descriptors are defined as class attributes of another class when they are used, so class attributes have higher priority than class attributes disguised by secondary processed descriptors.
People. name en, call the class attribute name, can not find the class attribute name to go to the descriptor camouflage, triggered _get_()

People. name ='egon'# assignment, which directly assigns a class attribute, has a higher priority, equivalent to overwriting the descriptor, and certainly does not trigger the _set_() of the descriptor.
Del People.name Ibid.
'''

Class Attribute > Data Descriptor

View Code

# Descriptor Str
class Str:
    def __get__(self, instance, owner):
        Print ('Str call')
    def __set__(self, instance, value):
        Print ('Str Settings...')
    def __delete__(self, instance):
        Print ('Str deletes...')

class People:
    name=Str()
    Def init (self, name, age): name is proxied by Str class and age by Int class.
        self.name=name
        self.age=age


p1=People('egon',18)

# If the descriptor is a data descriptor (i.e. _get_ and _set_), then the invocation and assignment of p1.name are trigger descriptor operations, which are independent of P1 itself and are equivalent to covering the attributes of the instance.
p1.name='egonnnnnn'
p1.name
Print (p1. _ Dict _) instance has no name in the attribute dictionary, because name is a data descriptor with priority over instance attribute. View/assignment/deletion are all related to descriptors, not to instances.
del p1.name

Data Descriptor > Instance Properties

View Code

Descriptor application

Python is a weakly typed language, i.e. parameter assignment has no type restriction and can be implemented by descriptor mechanism.

class Type:
    def __init__(self,key,expected_type):
        self.key=key
        self.expected_type=expected_type

    def __get__(self, instance, owner):
        print('get_methods')
        # print ('getinstance parameter [% s]'% instance)
        # print ('owner parameter [% s]'% owner)
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        print('set_methods')
        # print ('setinstance parameter [% s]'% instance)
        # print ('value parameter [% s]'% value)
        if not isinstance(value,self.expected_type) :
            # print ('The type you pass in is not a string, error')
            # return
            Raise TypeError ('You're not passing in a string')
        instance.__dict__[self.key]=value

    def __delete__(self, instance):
        print('delete_methods')
        # print('instance_arg[%s]'%instance)
        instance.__dict__.pop(self.key)

class People:
    name=Type('name',str)
    age=Type(18,int)
    def __init__(self,name,age,salary):
        self.name=name
        self.age=age
        self.salary=salary

p1=People('egon',18,33.3)
p1.name='alex'
print(p1.__dict__)
p1.age

Conclusion:

Descriptors can implement the underlying functions of most Python class features, including @classmethod, @staticmethd, @property and even _slots_ attributes.

Describing the parent is one of the most important tools in many advanced libraries and frameworks, and descriptors are usually used as a component in a large framework of decorators or metaclasses.

class ClassMethod:
    def __init__(self,func):
        self.func=func

    Def get (self, instance, owner): class to call, instance to None, owner to class itself, instance to call, instance to instance, owner to class itself,
        def feedback():
            Print ('You can add functionality here...')
            return self.func(owner)
        return feedback

class People:
    name='linhaifeng'
    @ClassMethod # say_hi=ClassMethod(say_hi)
    def say_hi(cls):
        Print ('Hello, handsome man'% s'% cls. name)

People.say_hi()

p1=People()
p1.say_hi()
# Question, if there are parameters for class methods, let's say, let's say.

class ClassMethod:
    def __init__(self,func):
        self.func=func

    Def get (self, instance, owner): class to call, instance to None, owner to class itself, instance to call, instance to instance, owner to class itself,
        def feedback(*args,**kwargs):
            Print ('You can add functionality here...')
            return self.func(owner,*args,**kwargs)
        return feedback

class People:
    name='linhaifeng'
    @ClassMethod # say_hi=ClassMethod(say_hi)
    def say_hi(cls,msg):
        Print ('Hello, handsome man% s% s') (cls. name, msg))

People. say_hi

p1=People()
P1.say_hi('You're the thief of the heart')

Make your own @class method

Customize @ClassMethod

class StaticMethod:
    def __init__(self,func):
        self.func=func

    Def get (self, instance, owner): class to call, instance to None, owner to class itself, instance to call, instance to instance, owner to class itself,
        def feedback(*args,**kwargs):
            Print ('You can add functionality here...')
            return self.func(*args,**kwargs)
        return feedback

class People:
    @StaticMethod# say_hi=StaticMethod(say_hi)
    def say_hi(x,y,z):
        print('------>',x,y,z)

People.say_hi(1,2,3)

p1=People()
p1.say_hi(4,5,6)

Customize @StaticMethod

Item Series Methods

class Foo:
    def __getitem__(self, item):
        print('getitem')
        return self.__dict__[item]

    def __setitem__(self, key, value):
        print('setitem')
        self.__dict__[key]=value

    def __delitem__(self, key):
        print('delitem')
        self.__dict__.pop(key)

# Dictionary operation triggers item
# Triggering attr
f1= Foo()
print(f1.__dict__)
f1['name']='egon'
f1['22']='2222'

print(f1.__dict__)
class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        Print ('del obj [key], I execute')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        Print ('del obj. key, I execute')
        self.__dict__.pop(item)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alx'
print(f1.__dict__)

Property

A static propertypropertyThe essence is to implement get, set, delete three methods

# Implementing Type Detection Function

# First Pass:
class People:
    def __init__(self,name):
        self.name=name

    @property
    def name(self):
        return self.name

# P1 = People ('alex') # property automatically implements that set and get methods belong to data descriptors and have higher priority than instance attributes, so this writing triggers the built-in set of property and throws exceptions.


# Second Pass: Revised Edition

class People:
    def __init__(self,name):
        Self. name = name # instantiation triggers property

    @property
    def name(self):
        # return self. name # infinite recursion
        print('get------>')
        return self.DouNiWan

    @name.setter
    def name(self,value):
        print('set------>')
        self.DouNiWan=value

    @name.deleter
    def name(self):
        print('delete------>')
        del self.DouNiWan

P1 = People ('alex') # self. name is actually stored in self. DouNiWan
print(p1.name)
print(p1.name)
print(p1.name)
print(p1.__dict__)

p1.name='egon'
print(p1.__dict__)

del p1.name
print(p1.__dict__)


# Third Pass: Add Type Check
class People:
    def __init__(self,name):
        Self. name = name # instantiation triggers property

    @property
    def name(self):
        # return self. name # infinite recursion
        print('get------>')
        return self.DouNiWan

    @name.setter
    def name(self,value):
        print('set------>')
        if not isinstance(value,str):
            Raise TypeError ('must be a string type')
        self.DouNiWan=value

    @name.deleter
    def name(self):
        print('delete------>')
        del self.DouNiWan

P1 = People ('alex') # self. name is actually stored in self. DouNiWan
p1.name=1

XIII, _str_, _repr_, _format_, _slots__

Change the object string to display _str_, _repr__

Self-customized formatted string _format__

format_dict={
    'nat':'{obj.name} - {obj.addr} - {obj.type}', # school name - school address - school type
    'tna':'{obj.type}: {obj.name}: {obj.addr}, # school type: school name: school address
    'tan':'{obj.type}/{obj.addr}/{obj.name}', # school type/school address/school name
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

S1=School ('oldboy1',' er ',' private ')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

'''
STR function or print function - - > obj. _str_()
Repr or interactive interpreter - - > obj. _repr_()
If _str_ is not defined, then _repr_ is used instead of output.
Note: The return value of these two methods must be a string, or an exception will be thrown.
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))

What is 1.__slots__?

A class variable whose value can be a list, a meta-ancestor, or an iterative object, or a string (meaning that all instances have only one data attribute)
    Use points. To access attributes is essentially to access the _dict_ attribute dictionary of a class or object (the Dictionary of a class is shared, and each instance is independent)
2. Why use _slots_:
Dictionaries take up a lot of memory. If you have a class with few attributes, but there are many instances, in order to save memory, you can use _slots_ instead of _dicts of instances.__
    When you define _slots_, the _slots_ will use a more compact internal representation for the instance. Instances are built through a small fixed-size array rather than defining a dictionary for each instance, much like tuples or lists. The attribute names listed in _slots_ are internally mapped to the specified small label of the array. One bad thing about using _slots_ is that we can no longer add new attributes to instances, but use only those attribute names defined in _slots_.
3. Notes:
_ Many features of slots_ depend on ordinary dictionary-based implementations. In addition, classes defined after _slots_ no longer support some common class features, such as multi-inheritance. In most cases, you should only define _slots_ on classes that are often used as data structures, such as the millions of instance objects that need to be created for a class in a program.
A common misconception about _slots_ is that it can be used as an encapsulation tool to prevent users from adding new attributes to instances. Although using _slots_ can achieve this purpose, this is not its original intention. More is used as a memory optimization tool.
class Foo:
    __slots__='x'


f1=Foo()
f1.x=1
F1.y=2# Error Reporting
Print (F1.)__

class Bar:
    __slots__=['x','y']

n=Bar()
n.x,n.y=1,2
N.z=3# reported wrong
class Foo:
    __slots__=['name','age']

f1=Foo()
f1.name='alex'
f1.age=18
print(f1.__slots__)

f2=Foo()
f2.name='egon'
f2.age=19
print(f2.__slots__)

print(Foo.__dict__)
# Both F1 and F2 have no attribute dictionary _dict_, so they are unified into _slots_ tube to save memory.
Fourteenth, _next_, _iter_, _doc_ Fibonacci sequence 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

f1=Fib()

print(f1.__next__())
print(next(f1))
print(next(f1))

for i in f1:
    if i > 100:
        break
    print('%s ' %i,end='')

class Foo:
    'I'm descriptive information'.
    pass

class Bar(Foo):
    pass
Print (Bar. _doc_) This attribute cannot be inherited to subclasses

Fifteen, _module_, _class_, _del_______ module_ denotes the object of the current operation in that module _class__ denotes what class of the object of the current operation is from lib.aa import C.

obj = C()
Print obj. _module__________________
Print obj. _class___________ outputs lib.aa.C, i.e. output class

_ The del_ destructor automatically triggers execution when an object is released in memory. Note: if the object generated is just Python program level (user level), then there is no need to define __del__. If the object is generated, it will also initiate a system call to the operating system, that is, an object has two kinds of resources, such as user level and kernel level, such as opening a file and creating a database link. This used the typical application scenario of __del__: create database class, use this instance to generate database link object, the object itself is stored in the user space memory, and the link is managed by the operating system and stored in the kernel space memory. When the program is finished, python will only recycle its memory space, that is, user state memory, while the resources of the operating system are not. Being recycled, this requires us to customize __del__, launch a system call to close the database link to the operating system before the object is deleted, and recycle the resource f=open ('a.txt') to do two things. Get a f variable in user space and open a file in the kernel space of the operating system.
Del f only restores f in user space, and the file of the operating system is still in the open state.

# So we should ensure that F. close () is executed before del f. Even if there is no del, the program will automatically del clean up resources after execution, so the correct use of file operation should be
f=open('a.txt')
Read and write...
f.close()
In many cases, people tend to ignore f. close, which uses with context management 16, _enter_, _exit_, _call_ with open ('a.txt') as f:
   The'code block'is called the context management protocol, which is the with statement. In order to make an object compatible with the with statement, the _enter_ and _exit_ method context management protocols must be declared in the class of the object: class Open:
    def __init__(self,name):
        self.name=name

    def __enter__(self):
        Print ('With statement appears, object's _enter_ is triggered, and variable that has a return value is assigned to as declaration')
        # return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        Print ('with'executes me when the code block has finished executing)


with Open('a.txt') as f:
    Print ('=====> Execution Block')
    # print(f,f.name)

_ The three parameters in exit () represent the exception type, the exception value and the traceability information respectively. If the block of code in the with statement has an exception, the code after with cannot execute. If the return value of exit () is True, the exception will be emptied as if nothing had happened. The statement after with normally executes class Open:
    def __init__(self,filepath,mode='r',encoding='utf-8'):
        self.filepath=filepath
        self.mode=mode
        self.encoding=encoding

    def __enter__(self):
        # print('enter')
        self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        # print('exit')
        self.f.close()
        return True
    def __getattr__(self, item):
        return getattr(self.f,item)

with Open('a.txt','w') as f:
    print(f)
    F. write ('aaaaaa') # authorization
    F. wasdf throws exceptions and gives them to exit for processing purposes: 1. The purpose of using with statement is to put code blocks into with and execute them automatically after with, without manual intervention. 2. In programming environments where some resources need to be managed, such as files, network connections and locks, you can customize the mechanism of automatically releasing resources in exit and you don't have to deal with this anymore. Question, which will be of great use to trigger execution of _call_ note by bracketing after the object: the execution of the constructor is triggered by the creation object, that is, the object = class name (); and the execution of the _call_ method is triggered by bracketing after the object, that is, the object () or the class () Foo:

    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):

        print('__call__')


Obj = Foo () # Execution _init__
Obj () execution call 17, and metaclass Python are all objects. All objects are instantiated or called classes (the process of calling classes is called instantiation of classes). The process of generating classes is actually the process of calling class keywords of metaclasses. When we create classes, we call metaclass type (...), which is the key component of the incoming classes when we call type. A class has three major components: 1, class_name='xxxx'2, and base. Class_bases= (object,) 3, class_dic, class namespace, class namespace is to execute class body code and the call type will be passed in the above three parameters one class does not declare its own metaclass, default his metaclass is type, in addition to using built-in metaclass type, we can also define metaclass by inheriting type, and then use meta keyword parameters. Specify metaclasses for a class, and classes customized by class are all objects (including object class itself, which is an instance of metaclass type, which can be viewed by type (object)

Recommended Today

Detailed explanation of spring cloud ribbon load balancing Shenkeng that cannot be connected through the server name

First, the problem. Take the Eureka cluster and the client calls the service through the ribbon. The ribbon side reports the following exceptions java.net.UnknownHostException: SERVICE-HI java.lang.IllegalStateException: No instances available for SERVICE-HI java.lang.IllegalStateException: Request URI does not contain a valid hostname: http://SERVICE-HI com.netfix.discovery.shared.taransport.TransportException: Cannot execute request on any known server The spring cloud version is messy, […]