Class and object orientation
- Class: An abstract collection, considered a template, in which properties and methods are defined
- Object: Concrete instances based on classes
Class and class attributes
class Person:
"""
class doc
"""
classVar = 100
def showMe(self):
return __class__.__name__
print(Person)
print(type(Person))
print(Person.__name__)
print(Person.__doc__)
print(Person.showMe)
Copy the code
- Class is followed by an identifier to define the class
- Each class is actually an object, an object of class Type
- ClassVar is a class variable shared by all instances and classes
- The showMe method is essentially an object
instantiation
class Person:
"""
class doc
"""
classVar = 100
def showMe(self):
return __class__.__name__
p = Person()
print(p)
Copy the code
-
__main__ is the name of the file module, Person object represents the object of the Person class, and 0x to the end represents the object’s address in memory
-
Each instantiation generates a different object, even if the properties and methods in the instance are the same
-
The essence of instantiation is to call the class’s __init__ method, which cannot return a value
-
The Person class above does not define an __init__ method because it calls the __init__ method of the object class. Python3 does not define which class to inherit
-
Initializing an object can be seen as a two-step process. First, the __new__ method (inheriting object) is called to create operations such as storing the instance object in memory, and __init__ is used to fill the data of the instance. Only after the two steps are completed can the actual instantiation be considered
class Person:
def __init__(self,name,age):
self.name = name
self.age = age
Copy the code
- The first argument to the __init__ method, self, refers to the object created by the __new__ method in the first step, which may not be the self identifier. Self. name and self.age are instance attributes (instance variables) that take the name and age parameters, respectively
class Person:
age = 3
def __init__(self, name):
self.name = name
tom = Person('Tom')
jerry = Person('Jerry')
print(tom.name, tom.age)
print(jerry.name, tom.age)
print(Person.age)
Person.age = 30
print(Person.age, tom.age, jerry.age)
Copy the code
- Each instance variable value is unique to itself, and class variables are shared
Special attributes
Special attributes | meaning |
---|---|
_name_ | Name or module name |
_class_ | Instance Class information |
_dict_ | A dictionary of attributes for a class or instance |
_qualname_ | Simply put, the full path to the property |
class Person:
age = 3
def __init__(self, name):
self.name = name
self.inner = self.__class__.Inner()
class Inner:
var = 100
def test(self):
pass
tom = Person('Tom')
jerry = Person('Jerry')
print(tom.__dict__)
print(tom.__class__)
print(tom.__class__.__name__)
print(__name__)
print(Person.__dict__)
print(Person.Inner.test.__qualname__)
Copy the code
- Instance.__dict__ mainly outputs assignment statements defined under the __init__ method. Class.__dict__ outputs information about the class
- Only class.__name__ output the class name, and print(_ alonename_) outputs the module name, which is the filename defined if the file is imported by another file
- __class__ outputs the class information of the instance, and each class outputs the type class information
- __qualname__ is the full path of an object, such as person.inner. Test for the test method
Attribute access rules
class Person: age = 3 height = 170 def __init__(self, name, age=18): Self. name = name self.age = age Tom = Person("Tom") Person.age, tom.age, jerry. Age) print(2, person. height, tom.height, Jerry. Height = 175 print(3, person. height, Tom. Height, Height += 10 print(4, Person. Height, Tom. Height, Person. Height += 15 print(5, Person. Height, Tom. Height, Person.weight = 70 print(6, person. weight, tom.weight, jerry. Weight) Tom. __dict__ [' height ']) # please print (8, Tom. __dict__ [' weight ']) # pleaseCopy the code
- Person.age = 30 changes the value of the class variable. Tom uses the default 18 and Jerry passes in 20
- 170, 170, 170, 170, 170, 170
- Height =175 jerry.__dict__ add height=175 jerry
- Height +=10 and add it to Tom.__dict__
- 5 Output 185 180 175, for the class variable +=15, has no effect on the instance variable
- 6 Print 70, 70, 70, dynamically add the weight attribute to the Person class
- 7 Output 180, Tom._dict_[‘ height ‘] is equal to Tom. Height
- This is not an object oriented error, this is a dictionary error, you can’t find the key of weight, and Tom. weight is found inside Python to help you find the class variable, so Tom. _dict_[‘weight’] should never be used
Class methods and static methods
- Common methods
Class Person: def normal_function(): print(' normal ') def method(self): Normal_function () print(Person().normal_function) print(Person().normal_function()) print(Person().normal_function()) print(Person.__dict__)Copy the code
-
Person().normal_function() will return an error because normal_function() did not pass in an instance, and Person().normal_function can be treated as if the instance did not find the class attribute normal_function
-
Class method
class Person: @classmethod def class_method(cls): Print (' class methods) print (" {0. __name__} 's name = {0. __name__} ". The format (CLS)) CLS. HEIGHT = 170 # call Person. Class_method () Person().class_method() print(Person.__dict__) print(Person.HEIGHT) print(Person().HEIGHT)Copy the code
-
@classmethod means a classmethod, and both class and instance are accessible. CLS means a class, and CLS.HEIGHT = 170 creates a class variable
-
A static method
class Person: HEIGHT = 180 @staticmethod def static_method(): Person(). Static_method () print(person.__dict__)Copy the code
- @staticmethod means that it is a staticmethod, with fewer parameter passing steps than a class method, and is accessible to both classes and instances
Private variables
- Define private variables with “__”
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
p = Person("tom", 25)
print(p.__name)
print(p.__age)
Copy the code
-
Both p.__name and P. __age are reported above, essentially because Python changed __name instance variables to _Person__name and _Person__age. P.__dict__ can be seen
-
Protection members are defined by “_”
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
p = Person("tom", 25)
print(p._name)
print(p._age)
Copy the code
- It’s actually not protected, it’s still accessible, it’s just a convention
Attribute decorator
- Properties are set to private variables and methods are set to value and pass values,
class Person:
def __init__(self, name):
self._name = name
def name(self):
return self._name
def set_name(self, value):
self._name = value
Copy the code
- Python provides a property decorator to simplify calls
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def set_name(self, value):
self._name = value
Copy the code
- The property decorator must come first, followed by the setter and deleter decorators
- The property decorator is a simple way to turn an operation on a method into an access to a property, with some hidden effect
inheritance
- Inheritance: Inherits properties and methods from other classes, and can also have their own properties and methods, reducing code redundancy
class Animal:
def __init__(self, name):
self._name = name
def shout(self):
print(f"{self._name} shout")
@property
def name(self):
return self._name
@name.setter
def set_name(self, value):
self._name = value
a = Animal("tom")
a.shout()
class Cat(Animal):
pass
c = Cat("miao")
c.shout()
class Dog(Animal):
pass
d = Dog("wang")
d.shout()
Copy the code
-
Animal is the parent of Cat and Dog, which are subclasses of Animal
-
Special attributes
Special properties and methods | meaning |
---|---|
_bases_ | The parents of class |
_base_ | __bases__ The first metaancestor |
_mro_ | The order in which methods are found |
mro() | Same as above |
_subclasses_ () | A list of subclasses of class |
class A:
pass
print(A.__base__)
print(A.__bases__)
print(A.mro())
print(A.__mro__)
print(int.__subclasses__())
print(bool.mro())
Copy the code
- Access control in inheritance
class Animal:
__a = 10
_b = 20
c = 30
def __init__(self):
print("self init")
self.__d = 40
self._e = 50
self.f = 60
self.__a += 1
def showa(self):
print(self.__a)
print(self.__class__.__a)
def __showb(self):
print(self._b)
print(self.__a)
print(self.__class__.__a)
class Cat(Animal):
__a = 100
_b = 200
c = Cat()
c.showa()
c._Animal__showb()
print(c.c)
print(c._Animal__d)
print(c._e, c.f, c._Animal__a)
print(c.__dict__)
print(c.__class__.__dict__.keys())
Copy the code
-
C. showa():c calls the parent class showa. Cat is instantiated with Animal __init__. Self.__a +=1 is self._animal__a +=1. __a__ is found in Cat.__dict__, but not in Animal.__dict__. Method or instance invocation order: instance. dict_-> instance class. dict_-> parent class. dict_
-
With the search order, the output is easy. To sum up: instance.__dict__ can be understood as an assignment under the __init__ method. If a subclass does not override the __init__ method of its parent class, and the parent class has an assignment under its own __init__ method, the assignment on the instance is self._ parent name __a. Class.__dict__ can be understood as a collection of properties (not under __init__) and methods contained in a class.
-
Methods to rewrite
Shouts (self): print('Animal Shouts ') Class Cat(Animal): shouts (self): print('miao') def shout(self): print('miao2') a = Animal() a.shout() c = Cat() c.shout() print(Animal.__dict__) print(Cat.__dict__)Copy the code
-
The shout method of Cat overwrites the shout method of Animal, which is then overwritten by the shout method of its own class, essentially changing the method address pointed to by the shout variable in cat.__dict__
-
Enhancements to superclass methods
class Animal:
def shout(self):
print('Animal shouts')
class Cat(Animal):
def shout(self):
super(Cat, self).shout()
super().shout()
print('miao2')
a = Animal()
a.shout()
c = Cat()
c.shout()
print(Animal.__dict__)
print(Cat.__dict__)
Copy the code
- Scenario: Subclasses want to inherit attributes from their parent class, but also want to have their own attributes
class A:
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, b, c):
super(B, self).__init__(b + c)
self.b = b
self.c = c
b = B(2, 3)
print(b.a)
print(b.b)
print(b.c)
Copy the code
-
From the example above, the __init__ method of a subclass overrides the __init__ method of its parent class, so for a subclass to have the parent class’s A attribute, you need to call the __init__ method of the parent class
-
Multiple inheritance
zhuanlan.zhihu.com/p/268136917
- mixin
Class Doc: def __init__(self, content): self. Content = content # def print(self): raise NotImplementedError() class Printable: def printContent(self): print(self.content) class Pdf(Printable,Doc): pass p = Pdf("pdf content") print(Pdf.mro()) p.printContent()Copy the code
Magic methods
_new_: Instantiates an object by inheriting the __new__ method of the object class, which allocates memory to store the object. The __init__ method allocates attributes to the object. The general case does not use this magic method, but involves the design pattern point case, need to use. Reference: juejin. Cn/post / 684490…
class SingleObject:
def __new__(cls, *args, **kwargs):
if not hasattr(SingleObject, "_instance"):
SingleObject._instance = object.__new__(cls)
return SingleObject._instance
def __init__(self):
pass
print(SingleObject.__dict__.keys())
a = SingleObject()
print(SingleObject.__dict__.keys())
b = SingleObject()
print(id(a))
print(id(b))
Copy the code
- You can see that the class dictionary after a=SingleObject() has an additional _instance attribute
_str_: calls to the STR (), format(), and print() functions that return a string representation of an object. If not, the repr method is called to return a string representation; if not, the memory address of the object is returned
class Test: def __str__(self): # must return STR, __repr__ Return "STR method called" print(Test()) print("Test:{}". Format (Test())) print(STR (Test())) print([Test()])Copy the code
– When using instance objects in containers, the __repr__ magic method is looked for, and only the __repr__ magic method is overridden during development
_repr_: and __str__ magic method similar, return STR, development rewrite this magic method is good
class Test:
def __repr__(self):
return "repr method called"
print(Test())
print("Test:{}".format(Test()))
print(str(Test()))
print({Test()})
Copy the code
_bytes_: Returns a byte object
def __bytes__(self):
#return "{} is {}".format(self.name, self.age).encode()
import json
return json.dumps(self.__dict__).encode()
Copy the code
_BOOL_ : The built-in function bool(), or where the object is placed in a logical expression, returns a Boolean value when called. If you don’t define bool (), you look for len () to return length, if it’s not 0, it’s true. If len () is also undefined, all instances return true
class A:pass
print(bool(A()))
print(bool(A))
class B:
def __bool__(self):
return False
print(bool(B))
print(bool(B()))
class C:
def __len__(self):
return 0
print(bool(C()))
print(bool(C))
class D:
def __bool__(self):
return False
def __len__(self):
return 1
print(bool(D))
print(bool(D()))
Copy the code
Algorithm overload
class A:
def __add__(self, other):
return A(self.data + other.data)
def __init__(self, data):
self.data = data
def __lt__(self, other):
return self.data < other.data
def __ge__(self, other):
return self.data == other.data
def __gt__(self, other):
return self.data > other.data
def __iadd__(self, other):
return A(self.data + other.data)
def __repr__(self):
return f'A:[data={self.data}]'
a = A(2)
b = A(2)
print(id(a))
if a > b:
print("a>b")
elif a == b:
print("a==b")
else:
print("a<b")
print(a + b)
print(id(a))
print(a)
a += b
print(id(a))
print(a)
Copy the code
- Instances are unique by default, instance A is not equal to instance B, and the __eq__ method needs to be overridden
- __add__ returns the point value without modifying the calling object. __iadd__ modifies the original object, which means that a points to the point instance
Context management
- Enhancements to class instances when an object also implements _enterAnd _ _ ()exitThe _ () method, which is a context-managed object
class Point:
def __init__(self):
print("init")
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
with Point() as p:
print("with")
Copy the code
- You can see from the figure above that the __init__ method is executed when with Point()
- When executing the code in the with block, the __enter__ method is executed first
- The __exit__ method is executed after executing the code in the with block
- The __exit__ method is executed even if an exception is thrown in the with block. Premise is __exit__ method to return True, the use of context: www.cnblogs.com/wongbingmin…
- As p, like the operation file, is an alias. If the __enter__ method returns self, p is the alias of the Point() object. This means that the __enter__ method of the file object returns self.
class Point:
def __init__(self):
print("init")
def __enter__(self):
print("enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit")
with Point() as p:
print("with")
with p as f:
print(p)
print(f)
print(p == f)
print(p is f)
f = open("timeDemo.py", "r")
print(f.__enter__())
with f as f1:
print(f)
print(f1)
print(f == f1)
print(f is f1)
Copy the code
Generator function
- A function definition where a yield statement occurs is a generator function
def foo():
a = 0
while True:
print("yield before")
yield a
print("yield after")
a += 1
f = foo()
print(next(f))
print("~~~~~~")
print(next(f))
print("=====")
print(next(f))
Copy the code
- From the code execution above, a call to next() returns yield to value when the code executes to the yield line, and yield to code execution the next time
- Print the f object above and find that it is an iterator that returns the value every time next(). What is the use of the Python keyword yield? www.zhihu.com/question/34…
contextlib.contextmanager
- Contextlib contextmanager it is a decorator to realize context management, decorate a function, rather than as a class _enter_ and _exit_ method. The function must yield, that is, the function must return a generator and only yield.
import contextlib @contextlib.contextmanager def foo(): # print('enter') try: Finally: print('exit') except: print("error") finally: print("error") finally: print('exit') print("quit") with foo() as f: raise Exception("error") print(f)Copy the code
- The practical application
import contextlib
import datetime
import time
@contextlib.contextmanager
def timeit():
print('enter')
start = datetime.datetime.now()
try:
yield
finally:
print('exit')
delta = (datetime.datetime.now() - start).total_seconds()
print('delta = {}'.format(delta))
def add(x, y):
time.sleep(2)
return x + y
with timeit():
add(4, 5)
Copy the code