object-oriented programming
object: represents a specific thing in the problem space of the objective world, and also represents the basic element in the solution space of the software system
Object oriented programming (OP): it is not only a programming paradigm, but also a method of program development.
1. Class
Class (clas) is the construction of an object-oriented computer programming language. It is the blueprint for creating objects and describes the common properties and methods of the created objects
1. Understand the basic methods of creating classes
2. Preliminary understanding of object and object-oriented
class SuperMan: ''' A class of superman ''' def __init__(self,name): self.name = name self.gender = 1 self.single = False self.illness = False def nine_negative_kungfu(self): return "Ya!You have to die." guojing = SuperMan('guojing') print(guojing.name) print(guojing.gender) kongfu = guojing.nine_negative_kungfu() print(kongfu)
''' Write a program to judge whether students have finished their homework. If completed, teach Teachers will give praise, otherwise they will criticize. ''' class Student: def __init__(self, name, grade, subject): self.name = name self.grade = grade self.subject = subject def do_work(self, time): if self.grade > 3 and time > 2: return True elif self.grade < 3 and time > 0.5: return True else: return False class Teacher: def __init__(self, name, subject): self.name = name self.subject = subject def evaluate(self, result=True): if result: return "You are great." else: return "You should work hard" stu_zhang = Student('zhang', 5, 'math') tea_wang = Teacher('wang', 'math') teacher_said = tea_wang.evaluate(stu_zhang.do_work(1)) print("Teacher {0} said: {1}, {2}".format(tea_wang.name, stu_zhang.name, teacher_said)) stu_newton = Student('Newton', 6, 'physics') teacher_newton = tea_wang.evaluate(stu_newton.do_work(4)) print("Teacher {0} said: {1}, {2}".format(tea_wang.name, stu_newton.name, teacher_newton))
1.1. Properties
Attribute: describes what the object is
• class properties
Also known as static properties
It can only be modified through class
Instances also have class properties, but class properties cannot be modified
>>> class Foo: lang = 'python' >>> dir(Foo) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang'] >>> Foo.lang 'python' >>> f = Foo() >>> type(f) <class '__main__.Foo'> >>> dir(f) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang'] >>> f.lang 'python' >>> Foo.group = 'winner classroom' >>> dir(Foo) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang'] >>> dir(f) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang'] >>> f.name = 'winner' >>> dir(f) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang', 'name'] >>> dir(Foo) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'group', 'lang']
• instance properties
Instance properties, also known as dynamic properties
Create by instance
Different instances have different instance properties
Instance__ dict__ Displays all properties of the current instance
>>> class Bar: def __init__(self,name): self.name = name >>> b = Bar('winner') >>> c = Bar('xiaochun') >>> b.name 'winner' >>> c.name 'xiaochun'python >>> b.__dict__ {'name': 'winner'}
>>> class Foo: lang = 'python' def __init__(self,name): self.name = name >>> f = Foo('winner') >>> dir(f) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'lang', 'name'] >>> f.__dict__ {'name': 'winner'} >>> f.lang #lang is a class attribute, not an instance attribute, and cannot be__ dict__ But it can be accessed by instances 'python'
• the role of self
Unless otherwise specified, all methods in the class take self as the first parameter
self refers to the current instance
>>> class Bar: def __init__(self): print(self) >>> b = Bar() <__main__.Bar object at 0x00000181FD3E1580> >>> b <__main__.Bar object at 0x00000181FD3E1580> >>>
''' Create a class that can calculate the number of days and weeks between any two dates. ''' import datetime from dateutil import rrule class BetDate: def __init__(self, start_date, stop_date): self.start = datetime.datetime.strptime(start_date, "%Y, %m, %d") self.stop = datetime.datetime.strptime(stop_date, "%Y, %m, %d") def days(self): d = self.stop - self.start return d.days if d.days > 0 else False def weeks(self): weeks = rrule.rrule(rrule.WEEKLY, dtstart=self.start, until=self.stop) return weeks.count() fir_twe = BetDate("2019, 5, 1", "2019, 11, 25") d = fir_twe.days() w = fir_twe.weeks() print("Between 2019-5-1, 2019-11-25:") print("Days is:", d) print("Weeks is:", w)
1.2 method
Method: describe what the object can do
• comparison methods and functions
The naming of names and the writing of code blocks are the same
(instance) methods cannot be called alone, but only through instances / classes, while functions can be used alone
The first argument to the method must be self
>>> class Foo: def method(self,x): return x * 2 >>> f = Foo() >>> f.method(2) 4 >>> Foo.method(2) Traceback (most recent call last): File "<pyshell#320>", line 1, in <module> Foo.method(2) TypeError: method() missing 1 required positional argument: 'x' >>> Foo.method(f,2) 4 >>> f.method #Classes are objects and methods are objects <bound method Foo.method of <__main__.Foo object at 0x00000181FD3E1820>>
• class method
Use decorator: @ classmethod decorator
The first parameter of a class method: cls, which represents the class itself, has nothing to do with what is written. I'm used to using cls
>>> class Bar: @classmethod def method(cls,x): print(cls) >>> b = Bar() >>> b.method(2) <class '__main__.Bar'> >>> Bar <class '__main__.Bar'>
• static method
Use decorator: @ staticmethod decorator
Static methods are not bound to instances
>>> class Bar2: @staticmethod def add(): return 'add' >>> b2 = Bar2() >>> b2.add() 'add' >>> Bar2.add() 'add' >>> add() Traceback (most recent call last): File "<pyshell#343>", line 1, in <module> add() TypeError: add() missing 2 required positional arguments: 'x' and 'y'
practice
''' Create a class that can pass the "year"-month-Create an instance with the string "day", and verify whether the year, month and day are legal ''' class Date(object): def __init__(self,year=0,month=0,day=0): self.year = year self.month = month self.day = day @classmethod def from_string(cls,date_as_string): year,month,day = map(int,date_as_string.split('-')) datel = cls(year,month,day) return datel @staticmethod def is_date_valid(date_as_string): year, month, day = map(int, date_as_string.split('-')) return day <= 31 and month<=12 and year <= 2038 d = Date.from_string('2019-11-11') is_date = Date.is_date_valid('2019-11-11') print(is_date)
2. Inherit
Inheritance is one of the properties of an object
Inheritance is an important concept in object-oriented programming
• parent and child classes
Override of parent class method: if a method with the same name as the parent class is written in the child class, the method in the parent class will be overwritten
>>> class P: def __init__(self,name): self.name = name def eat(self): return "fish" >>> class C(P): pass >>> c = C() Traceback (most recent call last): File "<pyshell#356>", line 1, in <module> c = C() TypeError: __init__() missing 1 required positional argument: 'name' >>> c = C('google') >>> dir(c) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat', 'name'] >>> class D(P):pass >>> dir(D) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat'] >>> class E(P): def __init__(self,age): self.age = age >>> e = E('winner',18) Traceback (most recent call last): File "<pyshell#367>", line 1, in <module> e = E('winner',18) TypeError: __init__() takes 2 positional arguments but 3 were given >>> e = E('winner') >>> dir(e) ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat'] >>> e.age 'winner' >>> e.name Traceback (most recent call last): File "<pyshell#371>", line 1, in <module> e.name AttributeError: 'E' object has no attribute 'name'
In single inheritance, if a child class overrides the method of the same name in the parent class and wants to use the parent class method in the subclass, the method in the parent class is called in the subclass.
>>> class E(P): def __init__(self,name,age): self.age = age P.__init__(self,name) >>> e = E('winner',18) >>> e.age 18 >>> e.name 'winner' >>> class E(P): def __init__(self,name,age): self.age = age super().__init__(name) >>> e = E('winner',18) >>> e.age 18 >>> e.name 'winner'
• single inheritance
class Person: def __init__(self,name,age): self.name = name self.age = age def get_name(self): return self.name def get_age(self): return self.age class Student(Person): def __init__(self,school,name,age): self.school = school super().__init__(name,age) def grade(self,n): print("{0}'s grade is {1}".format(self.name,str(n))) stu1 = Student('Soochow','winner','18') stu1.grade(99) print(stu1.get_name()) print(stu1.get_age())
• multi inheritance
class K1: def foo(self): print("K1-foo") class K2: def foo(self): print("K2-foo") def bar(self): print("K2-bar") class J1(K1,K2): pass class J2(K1,K2): def bar(self): print("J2-bar") class C(J1,J2): pass print(C.__mro__) m = C() m.foo() m.bar() Operation results (<class '__main__.C'>, <class '__main__.J1'>, <class '__main__.J2'>, <class '__main__.K1'>, <class '__main__.K2'>, <class 'object'>) K1-foo J2-bar
''' Please write the class of "physicist" and regard it as "theoretical physicist" And "experimental physicist" ''' class Physicist: def __init__(self,name,iq=120,looks='handsom',subject='physics'): self.name = name self.iq = iq self.looks = looks self.subject = subject def research(self,field): print("{0} research {1}".format(self.name,field)) def speak(self): print("My name is",self.name) print("I am",self.looks) print("Intelligence is",self.iq) print("I like",self.subject) class ExperimentalPhysicist(Physicist): def __init__(self,main_study,name,iq=120,looks='handsom',subject='physics'): self.main_study = main_study super().__init__(name,iq,looks,subject) def experiment(self): print("{0} is in Physics Lab".format(self.name)) class TheoreticalPhysicist(Physicist): def __init__(self,theory,name,iq=120,looks='handsom',subject='physics'): self.theory = theory super().__init__(name,iq,looks,subject) def research(self,field,base): super().research(field) print("My theory is {0}, it is based on {1}".format(self.theory,base))
3. Polymorphism
-
Polymorphism is one of the characteristics of objects
-
Python language is naturally polymorphic
>>> def add(x,y): return x + y >>> add(3,4) 7 >>> add('winner','python') 'winnerpython'
4. Encapsulation
- Encapsulation is one of the characteristics of objects
- Python implements encapsulation through privatization, with two underscores in front of the object__
>>> class Foo: __name = 'winner' book = 'python' >>> Foo.book 'python' >>> Foo.__name Traceback (most recent call last): File "<pyshell#407>", line 1, in <module> Foo.__name AttributeError: type object 'Foo' has no attribute '__name' >>> Foo.name Traceback (most recent call last): File "<pyshell#408>", line 1, in <module> Foo.name AttributeError: type object 'Foo' has no attribute 'name' >>> f = Foo() >>> f.book 'python' >>> f.name Traceback (most recent call last): File "<pyshell#411>", line 1, in <module> f.name AttributeError: 'Foo' object has no attribute 'name' >>> f.__name Traceback (most recent call last): File "<pyshell#412>", line 1, in <module> f.__name AttributeError: 'Foo' object has no attribute '__name'
Encapsulated objects can only be called in this class
>>> class Foo: def __init__(self): self.name = 'winner' self.__group = 'winner classroom' def code(self): return self.__group def __author(self): return self.name >>> f = Foo() >>> f.code() 'winner classroom' >>> f.__group Traceback (most recent call last): File "<pyshell#426>", line 1, in <module> f.__group AttributeError: 'Foo' object has no attribute '__group' >>> f.__author() Traceback (most recent call last): File "<pyshell#427>", line 1, in <module> f.__author() AttributeError: 'Foo' object has no attribute '__author'
5. Custom class
- Understand classes and types
- Master the methods of customizing object types
class RoundFloat: def __init__(self, val): self.value = round(val, 2) def __str__(self): # str: user friendly; Repl: interpreter friendly return "{0:.2f}".format(self.value) __repr__ = __str__ r = RoundFloat(3.1415926) print(r) print(type(r))
>>> class Foo: def __repr__(self): return "I am in repr" def __str__(self): return "I am in str" >>> f = Foo() >>> s ['one', 'two', 'three', 'four'] >>> f I am in repr >>> print(f) I am in str >>>
class Fraction: def __init__(self, number, denom=1): self.number = number self.denom = denom def __str__(self): return str(self.number) + "/" + str(self.denom) __repr__ = __str__ f = Fraction(2, 3) print(f)
>>> from fractions import Fraction #fraction >>> m,n = Fraction(1,6),Fraction(3,6) >>> m Fraction(1, 6) >>> n Fraction(1, 2) >>> m+n Fraction(2, 3)
6. Control attribute access
-
Optimize memory: slots
>>> a = Foo() >>> a.__dict__ {} >>> a.age = 25 >>> a.__dict__ {'age': 25} >>> a.year = 28 >>> a.__dict__ {'age': 25, 'year': 28}
It controls the attributes of a class. It is not allowed to increase or decrease arbitrarily. Only the specified attributes are allowed, and modification is not allowed (read-only)
>>> class Bar: __slots__ = ('name','age') >>> Bar.name='winner' >>> Bar.age=28 >>> b=Bar() >>> b.name 'winner' >>> b.age 28 >>> b.city = "soochow" Traceback (most recent call last): File "<pyshell#476>", line 1, in <module> b.city = "soochow" AttributeError: 'Bar' object has no attribute 'city' >>> b.age = 38 Traceback (most recent call last): File "<pyshell#477>", line 1, in <module> b.age = 38 AttributeError: 'Bar' object attribute 'age' is read-only
-
Master special methods related to attributes
getattr
setattr
An error occurred while accessing a property that does not exist in the class
>>> class A: def __getattr__(self,name): print("you use getattr") def __setattr__(self,name,value): print("you use setattr") self.__dict__[name] = value >>> a = A() >>> a.x you use getattr >>> a.x = "haha" you use setattr >>> a.x 'haha'
7. Iterators and generators
Determines whether an object can be iterated
>>> hasattr(list,"__iter__") True
7.1 iterators
List is iteratable (non iterator object), but__ next__ Is unique to iterator objects
>>> hasattr(iter_lst,"__next__") True >>> hasattr(list,"__next__") False
Reads the elements in the iterator into memory
>>> lst = [1,2,3,4] >>> iter_lst = iter(lst) >>> iter_lst <list_iterator object at 0x00000181FD3F7790> >>> lst [1, 2, 3, 4] >>> hasattr(iter_list,"__iter__") Traceback (most recent call last): File "<pyshell#501>", line 1, in <module> hasattr(iter_list,"__iter__") NameError: name 'iter_list' is not defined >>> hasattr(iter_lst,"__iter__") True >>> hasattr(iter_lst,"__next__") True >>> iter_lst.__next__() 1 >>> iter_lst.__next__() 2 >>> iter_lst.__next__() 3 >>> iter_lst.__next__() 4 >>> iter_lst.__next__() Traceback (most recent call last): File "<pyshell#509>", line 1, in <module> iter_lst.__next__() StopIteration >>> for i in iter_lst: print(i) >>> iter_lst =iter(lst) >>> for i in iter_lst:print(i) 1 2 3 4
class MyRange: def __init__(self, n): self.i = 1 self.n = n def __iter__(self): return self def __next__(self): if self.i <= self.n: i = self.i self.i += 1 return i else: raise StopIteration() print("range(7):", list(range(7))) print("MyRange(7):", [i for i in MyRange(7)])
class Fibs: def __init__(self, max): self.max = max self.a = 0 self.b = 1 def __iter__(self): return self def __next__(self): fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b return fib fibs = Fibs(1000000) lst = [fibs.__next__() for i in range(10)] print(lst)
>>> import itertools >>> counter = itertools.count(start=7) >>> next(counter) 7 >>> next(counter) 8 >>> next(counter) 9
7.2 generator
>>> def g(): yield 0 yield 1 yield 2 >>> ge = g() >>> ge <generator object g at 0x00000181FD3EDCF0> >>> type(ge) <class 'generator'> >>> dir(ge) ['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] >>>
yield and return
When the execution reaches yield, the function is suspended and waits for the next execution
When return is executed, the function terminates
>>> def r_return(n): print("start") while n > 0: print("before return") return n n -= 1 print('after return') >>> rre = r_return(3) start before return >>> print(rre) 3 >>> def y_yield(n): print("start") while n > 0: print("before yield") yield n n -= 1 print('after yield') >>> yy = y_yield(3) >>> yy.__next__() start before yield 3 >>> yy.__next__() after yield before yield 2 >>> yy.__next__() after yield before yield 1 >>> yy.__next__() after yield Traceback (most recent call last): File "<pyshell#561>", line 1, in <module> yy.__next__() StopIteration
def fibs(): prev, curr = 0, 1 while True: yield prev prev, curr = curr, prev + curr import itertools print(list(itertools.islice(fibs(), 10)))
Generator resolution
>>> [x**2 for x in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> gt = (x**2 for x in range(10)) >>> gt <generator object <genexpr> at 0x00000181FD3EDE40> >>> gt.__next__() 0 >>> gt.__next__() 1 >>> gt.__next__() 4 >>> gt.__next__() 9