一、類的約束
二、類的定義
2.1、創建創建
2.1.1、類的導入
2.1.2、構造器
2.1.3、類屬性
三、類的繼承
3.1、單繼承
3.2、多繼承
3.3、調用父類方法
3.4、屬性擴展
3.4.1、完全擴展
3.4.2、單獨擴展
四、類的調用
五、抽象類
5.1、強制類型檢查
六、類的比較
一、類的約束# _開頭: 私有變量;# __開問: 私有變量,不能被繼承;# __xxx__: 能被訪問,不能被繼承;class A:def __init__(self):self._internal = 0 # 私有變量不能被訪問self.public = 1 # 可被訪問def public_method(self):passdef _private_method(self): # 私有方法不能被訪問passclass B:def __init__(self):self.__private = 0 # 這個屬性會在內存中被重新命名為_B__privatedef __private_method(self): # 不能被訪問,不能被繼承passdef __private_method__(self): # 能被訪問,不能被繼承pass
二、類的定義2.1、創建創建class Dog:a = "0"; #相當於public static變量,全局的"""__init__是一個默認的方法,且self為默認的,用self修飾的屬性為public類型的類變量"""def __init__(self, name, age):self.name = nameself.age = ageself.sex = "1";#設置屬性默認值def sit(self):print(self.name + "is now sitting" + "and sex is " + self.sex + Dog.a)@classmethoddef user_name(cls, name): #注意這種注解的用法return cls()dog = Dog("kk", 12);dog.sit()
2.1.1、類的導入在python中分為文件、模塊、類,其中文件和模塊可劃等價;所以導入有幾種方式,比如dog.py文件中定義了兩個Class,則在使用類中導入方法有以下幾種:
from car import Dog;#導入一個模塊中的特定類,使用時則直接Car();
import car;#導入一個模塊中的所有類,使用時則需要car.Car();
from car import *;#不推薦,容易引起命名沖突問題
from collections import OrderedDict; #使用標准類庫t = OrderedDict();
2.1.2、構造器class Date:# Primary constructordef __init__(self, year, month, day):self.year = yearself.month = monthself.day = day# Alternate [email protected] today(cls):t = time.localtime() #它接收一個class作為第一個參數,它被用來創建並返回最終的實例, 這個cls==__init__return cls(t.tm_year, t.tm_mon, t.tm_mday)a = Date(2020, 5, 10) # Primaryb = Date.today() # Alternate
減少構造函數的參數個數:
class Structure1:# Class variable that specifies expected fields_field_list = []def __init__(self, *args):if len(args) != len(self._field_list):raise TypeError(f'Expected {len(self._field_list)} arguments')# Set the argumentsfor name, value in zip(self._field_list, args):setattr(self, name, value)# Example class definitionsclass Course(Structure1):# 這行只是為了一個准許入判斷,沒有太多實際意思,或是一個聲明_field_list = ['course_name', 'total_class', 'score']c = Course('python', 30, 0.3);
關鍵字參數
class Structure2:_field_list = []def __init__(self, *args, **kwargs):if len(args) > len(self._field_list):raise TypeError(f'Expected {len(self._field_list)} arguments')# Set all of the positional argumentsfor name, value in zip(self._field_list, args):setattr(self, name, value)# Set the remaining keyword arguments#是通過pop這種方式來檢查的,在長度范圍內如果pop出錯則拋異常for name in self._field_list[len(args):]:setattr(self, name, kwargs.pop(name))# Check for any remaining unknown argumentsif kwargs:raise TypeError(f"Invalid argument(s): {','.join(kwargs)}")# Example useclass Course(Structure2):_field_list = ['course_name', 'total_class', 'score']course_1 = Course('python', 30, 0.3)course_2 = Course('python', 30, score=0.3)course_3 = Course('python', total_class=30, score=0.3)
擴展關鍵字參數:
class Structure3:# Class variable that specifies expected fields_field_list = []def __init__(self, *args, **kwargs):if len(args) != len(self._field_list):raise TypeError(f'Expected {len(self._field_list)} arguments')# Set the argumentsfor name, value in zip(self._field_list, args):setattr(self, name, value)# Set the additional arguments (if any)extra_args = kwargs.keys() - self._field_listfor name in extra_args:setattr(self, name, kwargs.pop(name))if kwargs:raise TypeError(f"Duplicate values for {','.join(kwargs)}")# Example useif __name__ == '__main__':class Course(Structure3):_field_list = ['course_name', 'total_class', 'score']course_1 = Course('python', 30, 0.3)course_2 = Course('python', 30, 0.3, date='8/5/2020')
2.1.3、類屬性要創建一個新的實例屬性,可以通過描述器的形式來定義它的功能,一個描述器就是一個實現了3個核心屬性訪問操作的類,分別對應get\set\delete這三個特殊的方法。
# Descriptor attribute for an integer type-checked attributeclass Integer:def __init__(self, name):self.name = name"""下面三個方法只是一個更嚴格的定義,可以不需要,要使用上面的描述器,需要把描述器放入到一個class中,這樣所有對描述器的訪問都會被get/set/delete所捕獲"""def __get__(self, instance, cls):if not instance:return selfelse:return instance.__dict__[self.name]def __set__(self, instance, value):if not isinstance(value, int):raise TypeError('Expected an int object')instance.__dict__[self.name] = valuedef __delete__(self, instance):del instance.__dict__[self.name]
示例1:
class Point:"""實例變量,和下面的x,y不是一回事"""x = Integer('x')y = Integer('y')def __init__(self, x, y):self.x = xself.y = yprint(Point.x.name) # xpoint = Point(3, 5)print(f'point x = {point.x}') #3print(f'point y = {point.y}') #5point.y = 6print(f'after change,point y = {point.y}') #6
三、類的繼承ptyhon在實現繼承時會用一個叫MRO列表的算法實現,它有三條規則:1、子類會先於父類;2、多個父類會根據它們在列表中的順序被檢查;3、如果對下一個類有兩個合法的選擇,則返回第一個合法的父類;
3.1、單繼承class A:def __init__(self):self.x = 0class B(A):def __init__(self):super().__init__() #這行需要注意,也可以不寫,但不寫時就不會調用父類的init方法self.y = 1
3.2、多繼承class Base:def __init__(self):print('call Base.__init__')class A(Base):def __init__(self):Base.__init__(self)print('call A.__init__')class B(Base):def __init__(self):Base.__init__(self)print('call B.__init__')"""多繼承的實現"""class C(A,B):def __init__(self):A.__init__(self)B.__init__(self)print('call C.__init__')c = C()# call Base.__init__# call A.__init__# call Base.__init__# call B.__init__# call C.__init__
3.3、調用父類方法class Proxy:def __init__(self, obj):self._obj = objdef __getattr__(self, name):return getattr(self._obj, name)def __setattr__(self, name, value):if name.startswith('_'):"""調用父類方法"""super().__setattr__(name, value)else:setattr(self._obj, name, value)proxy = Proxy({})proxy.__setattr__("_name", "hm")
3.4、屬性擴展3.4.1、完全擴展# 父類class Person:def __init__(self, name):self.name = name# defined Getter function, auto to call the sign name.setter when it be [email protected] name(self):return self._name# defined Setter [email protected] name(self, value):if not isinstance(value, str):raise TypeError('Expected a string')self._name = value# defined Deleter [email protected] name(self):raise AttributeError("Can't delete attribute")"""子類"""class SubPerson(Person):@propertydef name(self):print('Getting name')return super()[email protected] name(self, value):print(f'Setting name to {value}')super(SubPerson, SubPerson).name.__set__(self, value)@name.deleterdef name(self):print('Deleting name')super(SubPerson, SubPerson).name.__delete__(self)"""測試"""sub_person = SubPerson('Guido')print(f'name is: {sub_person.name}')
3.4.2、單獨擴展class SubPerson(Person):@Person.name.getterdef name(self):print('Getting name')return super().name # or super(SubPerson, SubPerson).name.__set__(self, value)sub_p = SubPerson('Bill')
#不能用property的原因是,property其實是get、set、del函數的集合,各有各的用處。下面才是正確的擴展方式,所以下面的代碼是不工作的class SubPerson(Person):@property # Doesn't workdef name(self):print('Getting name')return super().name#如果要用property屬性則要用下面的編碼實現class SubPerson(Person):@propertydef name(self):print('Getting name')return super()[email protected] name(self, value):print(f'Setting name to {value}')super(SubPerson, SubPerson).name.__set__(self, value)@name.deleterdef name(self):print('Deleting name')super(SubPerson, SubPerson).name.__delete__(self)
四、類的調用import timeclass Date:# Primary constructordef __init__(self, year, month, day):self.year = yearself.month = monthself.day = day# Alternate [email protected] today(cls):t = time.localtime() #它接收一個class作為第一個參數,它被用來創建並返回最終的實例, 這個cls==__init__return cls(t.tm_year, t.tm_mon, t.tm_mday)
"""普通調用"""c = Date(2010, 12, 12)"""類方法在繼承中使用"""class NewDate(Date):passc = Date.today() # Creates an instance of Date (cls=Date)d = NewDate.today() # Creates an instance of NewDate (cls=NewDate)
五、抽象類from abc import ABCMeta, abstractmethodclass IStream(metaclass=ABCMeta):@abstractmethoddef read(self, max_bytes=-1):[email protected] write(self, data):pass"""不能被實例化"""#a = IStream()class SocketStream(IStream):def read(self, max_bytes=-1):passdef write(self, data):pass"""檢查"""def serialize(obj, stream):if not isinstance(stream, IStream):raise TypeError('Expected an IStream')pass
5.1、強制類型檢查from abc import ABCMeta, abstractmethodclass IStream(metaclass=ABCMeta):@abstractmethoddef read(self, max_bytes=-1):[email protected] write(self, data):passimport io# Register the built-in I/O classes as supporting our interfaceIStream.register(io.IOBase)# Open a normal file and type checkf = None #open('test.txt')print(f'f object is IStream type: {isinstance(f, IStream)}')#f object is IStream type: False
六、類的比較from functools import total_orderingclass Room:def __init__(self, name, length, width):self.name = nameself.length = lengthself.width = widthself.square_feet = self.length * [email protected]_orderingclass House:def __init__(self, name, style):self.name = nameself.style = styleself.rooms = list()@propertydef living_space_footage(self):return sum(r.square_feet for r in self.rooms)def add_room(self, room):self.rooms.append(room)def __str__(self):return f'{self.name}: {self.living_space_footage} square foot {self.style}'def __eq__(self, other):return self.living_space_footage == other.living_space_footagedef __lt__(self, other):return self.living_space_footage < other.living_space_footage# Build a few houses, and add rooms to themh1 = House('h1', 'Cape')h1.add_room(Room('Master Bedroom', 14, 21))h1.add_room(Room('Living Room', 18, 20))h1.add_room(Room('Kitchen', 12, 16))h1.add_room(Room('Office', 12, 12))h2 = House('h2', 'Ranch')h2.add_room(Room('Master Bedroom', 14, 21))h2.add_room(Room('Living Room', 18, 20))h2.add_room(Room('Kitchen', 12, 16))h3 = House('h3', 'Split')h3.add_room(Room('Master Bedroom', 14, 21))h3.add_room(Room('Living Room', 18, 20))h3.add_room(Room('Office', 12, 16))h3.add_room(Room('Kitchen', 15, 17))houses = [h1, h2, h3]print(f'Is {h1} bigger than {h2}: {h1 > h2}')print(f'Is {h2} smaller than {h3}: {h2 < h3}')print(f'Is {h2} greater than or equal to {h1}: {h2 >= h1}')print(f'Which one is biggest in houses: {max(houses)}')print(f'Which is smallest in houses: {min(houses)}')""""""# Is h1: 990 square foot Cape bigger than h2: 846 square foot Ranch: True# Is h2: 846 square foot Ranch smaller than h3: 1101 square foot Split: True# Is h2: 846 square foot Ranch greater than or equal to h1: 990 square foot Cape: False# Which one is biggest in houses: h3: 1101 square foot Split# Which is smallest in houses: h2: 846 square foot Ranch# """"""class House:def __eq__(self, other):passdef __lt__(self, other):pass# Methods created by @total_ordering__le__ = lambda self, other: self < other or self == other__gt__ = lambda self, other: not (self < other or self == other)__ge__ = lambda self, other: not (self < other)__ne__ = lambda self, other: not self == other
到此這篇關於Python類的定義繼承調用比較方法技巧的文章就介紹到這了,更多相關Python類的定義內容請搜索軟件開發網以前的文章或繼續浏覽下面的相關文章希望大家以後多多支持軟件開發網!