python—类

python——类

定义

  • Python使用class关键字来定义类,class关键字之后是一个空格,然后是类的名字,再然后是一个冒号,最后换行并定义类的内部实现。
  • 类名的首字母一般要大写,当然也可以按照自己的习惯定义类名,但一般推荐参考惯例来命名,并在整个系统的设计和实现中保持风格一致,这一点对于团队合作尤其重要。

语法格式:

class ClassName:
        #属性
        [属性定义体]
        #方法
         [方法定义体]
#属性就是变量,静态的特征,方法就是一个个的函数,通过这些函数来描述动作行为。

使用

类对象实例化

对象名 = 类名()
>>> car = Car()
注意,类名后面要添加一个括号“()”。

调用对象的属性和方法

对象名.属性名
对象名.方法名
>>> car.infor()

在Python中,可以使用内置方法isinstance()来测试一个对象是否为某个类的实例。

>>> isinstance(car, Car)
True
>>> isinstance(car, str)
False

构造类

__ init __(self)

只要实例化一个对象的时候,这个方法就会在对象被创建的时候自动调用。实例化对象的时候是可以传入参数的,这些参数会自动传入__ init __(self,param1,param2,…)方法中,我们可以通过重写这个方法来自定义对象的初始化操作。

举例

>>> class Bear:
	        def __init__(self,name):
		  self.name = name
	        def kill(self):
                 print("%s,是保护动物,不能杀..."% self.name)
>>> a = Bear('狗熊')
>>> a.kill()
狗熊,是保护动物,不能杀...

另外,我们还可以把传入的参数设置为默认参数,我们在实例化的时候不传入参数系统也不会报错。

>>> class Bear:
	   def __init__(self,name = "默认的熊"):
	        self.name = name
	   def kill(self):
            print("%s,是保护动物,不能杀..."% self.name)

self参数
  • 类的所有实例方法都必须至少有一个名为self的参数,并且必须是方法的第一个形参(如果有多个形参的话),self参数代表将来要创建的对象本身。
  • 在类的实例方法中访问实例属性时需要以self为前缀。
  • 在外部通过对象调用对象方法时并不需要传递self参数,如果在外部通过类调用对象方法则需要显式为self参数传值。
  • 在Python中,在类中定义实例方法时将第一个参数定义为“self”只是一个习惯,而实际上不必须使用“self”这个名字,尽管如此,建议编写代码时仍以self作为方法的第一个参数名字。
类属性和实例属性
  • 在Python中比较特殊的是,可以动态地为自定义类和对象增加或删除属性,这一点是和很多面向对象程序设计语言不同的,也是Python动态类型特点的一种重要体现。
  • 实例属性:一般是指在构造函数__ init __()中定义的,定义在方法中的变量,属于某个具体的对象,定义和使用时必须以self作为前缀;
  • 类属性是在类中所有方法之外定义的,在整个实例化的对象中是公用的。
  • 在主程序中(或类的外部),实例属性属于实例(对象),只能通过对象名访问;而类属性属于类,可以通过类名或对象名都可以访问。
class Car:
    price = 100000                     #定义类属性
    def __init__(self, c):
        self.color = c                 #定义实例属性

__ dict __属性

每个类和对象都有一个叫作__ dict __字典属性,用来记录该类或对象所拥有的属性。用类名调用输出该由类中所有类属性组成的字典;而使用类的实例对象输出由类中所有实例属性组成的字典。Python内置类型不支持属性的增加,用户自定义类及其对象一般支持属性和方法的增加与删除

class Car: #通过类调用类属性
    price = 100000                     #定义类属性
    def __init__(self, c):
        self.color = c                 #定义实例属性
>>>car1 = Car("Red")  
>>> print(car1.__dict__)
{'color': 'Red'}
实例属性的增删改查
>>> car1 = Car("Red")         #实例化对象
>>> car2 = Car("Blue")
>>> print(car1.color)       #查看实例属性的值
Red
>>> car1.color = "Yellow"   #修改实例属性
>>> print(car2.color)       #
Blue
>>> print(car1.color) 
Yellow
>>> car1.age=1     #增加实例属性
>>> print(car1.age) #查看实例属性的值
1 
>>> del Car.name  '#删除类属性
>>> Car.name
Traceback (most recent call last)
私有属性和公有属性

Python并没有对私有属性提供严格的访问保护机制。

  • 私有属性:在定义类的属性时,如果属性名以两个下划线“__”或更多下划线开头而不以两个或更多下划线结束则表示是私有属性。
  • 私有属性在类的外部不能直接访问,需要通过调用对象的方法来访问,也可以通过Python支持的特殊方式来访问。
  • _ xxx:私有属性,只有类对象自己能访问,但在对象外部可以通过“对象名.类名__xxx”这样的特殊方式来访问。
class A:
	def __init__(self, value1 = 0, value2 = 0):
		self.value1 = value1
		self.__value2 = value2
	def setValue(self, value1, value2):
		self.value1 = value1
		self.__value2 = value2
	def show(self):
		print(self.value1)
		print(self.__value2)
	def printt(self):
		print(self.__value2)
a=A()
a.printt()#内部访问
print(a._A__value2)#外部访问,不能直接访问私有属性

在Python中,以下划线开头的变量名和方法名有特殊的含义,尤其是在类的定义中。

  • _xxx:受保护属性,不能用’from module import *'导入;
  • __ xxx __:系统定义的特殊属性;
  • __ xxx:私有属性,只有类对象自己能访问,子类对象不能直接访问到这个属性,但在对象外部可以通过“对象名.类名__ xxx”这样的特殊方式来访问。
class Root:
    __total = 0
    def __init__(self, v):    #构造方法
        self.__value = v
        Root.__total += 1

    def show(self):           #普通实例方法
        print('self.__value:', self.__value)
        print('Root.__total:', Root.__total)
    def __private(self):           #私有方法
        print(‘This is a private function.’)
>>> r._Root__private()
This is a private function.

如果通过类名来调用属于对象的公有方法,需要显式为该方法的self参数传递一个对象名,用来明确指定访问哪个对象的数据属性。

class Root:
    __total = 0
    def __init__(self, v):    #构造方法
        self.__value = v
        Root.__total += 1

    def show(self):           #普通实例方法
        print('self.__value:', self.__value)
        print('Root.__total:', Root.__total)
r = Root(3)
rr = Root(5)
#试图通过类名直接调用实例方法,失败
>>> Root.show()
TypeError: unbound method show() must be called with Root instance as first argument (got nothing instead)
#但是可以通过这种方法来调用方法并访问实例属性
>>> Root.show(r) 
self.__value: 3
Root.__total: 2
#通过类名调用实例方法时为self参数显式传递对象名
>>> Root.show(rr) 
self.__value: 5
Root.__total: 2
类方法和静态方法
  • 类方法:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法), 并且在调用类方法时不需要为该参数传递值。
  • 静态方法:使用装饰器@staticmethod。可以没有参数,没有“self”和“cls”参数。实例对象和类对象都可以调用。
class Root:
    __total = 0
    def __init__(self, v):    #构造方法
        self.__value = v
        Root.__total += 1

    def show(self):           #普通实例方法
        print('self.__value:', self.__value)
        print('Root.__total:', Root.__total)

    @classmethod        #修饰器,声明类方法
    def classShowTotal(cls):  #类方法
        print(cls.__total)

    @staticmethod    #修饰器,声明静态方法
    def staticShowTotal():    #静态方法
        print(Root.__total)
        
        
>>> r = Root(3)
>>> r.classShowTotal()   #对象来调用类方法
1
>>> r.staticShowTotal()  #对象来调用静态方法
1
>>> r.show()
self.__value: 3
Root.__total: 1
>>> rr = Root(5)
>>> Root.classShowTotal()  #类名调用类方法
2
>>> Root.staticShowTotal()  #类名调用静态方法
2

例题

自定义栈,实现基本的入栈、出栈,判栈空,栈满操作。

class Stack:
    def __init__(self, size = 10):
        '''创建栈对象并进行初始化,默认栈大小为10'''
        # 使用列表存放栈的元素
        self._content = []    # 初始栈大小
        self._size = size  # 栈中元素个数初始化为0
        self._current = 0
        
    def empty(self):
        '''清空栈'''
        self._content = []
        self._current = 0

    def isFull(self):
        '''测试栈是否已满'''
        return self._current == self._size
    def push(self, v):
        '''将新元素入栈'''
        # 模拟入栈,需要先测试栈是否已满
        if self._current < self._size:
            self._content.append(v)
            # 栈中元素个数加1
            self._current = self._current+1
        else:
            print('Stack Full!')
     def pop(self):
        '''将栈顶元素出栈'''
        # 模拟出栈,需要先测试栈是否为空
        if self._content:
            # 栈中元素个数减1
            self._current = self._current-1
            return self._content.pop()  
        else:
            print('Stack is empty!')

构造函数和析构函数
  • Python中类的构造函数是__ init __(),一般用来为数据属性设置初值或进行其他必要的初始化工作,在创建对象时被自动调用和执行。如果用户没有设计构造函数,Python将提供一个默认的构造函数用来进行必要的初始化工作。
  • Python中类的析构函数是__ del __(),一般用来释放对象占用的资源,在Python删除对象和收回对象空间时被自动调用和执行。如果用户没有编写析构函数,Python将提供一个默认的析构函数进行必要的清理工作
class Person(object):
    def run(self):
        print("run")
    def eat(self, food):
        print("eat" + food)
    def __init__(self,name,age,height,weight):
        self.name=name
        self.age=age
        self.height=height
        self.weight=weight
    def __del__(self):#当程序结束时运行
        print("析构函数")
        #在函数里定义的对象,会在函数结束时自动释放,这样可以减少内存空间的浪费

>>>per1=Person("lili",20,175,50)
>>>del per1  #手动释放对象
析构函数
>>>print(per1.name)#释放对象后程序不运行
继承机制
  • 继承是用来实现代码复用和设计复用的机制,是面向对象程序设计的重要特性之一。设计一个新类时,如果可以继承一个已有的设计良好的类然后进行二次开发,无疑会大幅度减少开发工作量。
  • 在继承关系中,已有的、设计好的类称为父类或基类,新设计的类称为子类或派生类。
  • Python支持多继承,如果父类中有相同的方法名,而在子类中使用时没有指定父类名,则Python解释器将从左向右按顺序进行搜索。

继承是子类自动共享父类的数据和方法的机制。

语法格式如下:
Class ClassName(BaseClassName):
             ……
ClassName:是子类的名称,第一个字母必须大写。
BaseClassName:是父类的名称。

派生类可以继承父类的公有属性,但是不能继承其私有属性。如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过“基类名.方法名()”的方式来实现这一目的。

class A:
    #构造方法可能会被派生类继承
	    def __init__(self):
		self.__private()
		self.public()
   #私有方法在派生类中不能直接访问
	    def __private(self):
		print('__private() method in A')	
	#公开方法在派生类中可以直接访问,及被覆盖
	    def public(self):
		print('public() method in A')
class B(A): 
#类B没有构造方法,会继承基类的构造方法
	    def __private(self): #不会覆盖基类的私有方法
		print('__private() method in B')
	    #覆盖了继承自A类的公开方法public
	    def public(self):
		print('public() method in B')
>>> b = B()             #自动调用基类构造方法
__private() method in A
public() method in B

>>> dir(b) #基类和派生类的私有方法访问方式不一样
['_A__private', '_B__private',...]
>>> b._A__private()
__private() method in A


#dir( ):不仅仅输出本类中新添加的属性名和方法,还会输出从父类继承得到的属性名和方法名。
>>> class C(A):
	    def __init__(self):     #显式定义构造函数
		self.__private()     #这里调用的是类C的私有方法
		self.public()

	    def __private(self):
		print('__private() method in C')

    def public(self):
		print('public() method in C')	

>>> c = C()                 #调用类C的构造方法
__private() method in C
public() method in C

>>> dir(c)
['_A__private', '_C__private', '__class__', ...]

多态
  • •所谓多态(polymorphism),是指基类的同一个方法在不同派生类对象中具有不同的表现和行为。派生类继承了基类行为和属性之后,还会增加某些特定的行为和属性,同时还可能会对继承来的某些行为进行一定的改变,这都是多态的表现形式。
  • Python大多数运算符可以作用于多种不同类型的操作数,并且对于不同类型的操作数往往有不同的表现,这本身就是多态,是通过特殊方法与运算符重载实现的。
>>> class Animal(object):      #定义基类
    def show(self):
        print('I am an animal.')
>>> class Cat(Animal):         #派生类,覆盖了基类的show()方法
    def show(self):
        print('I am a cat.')
>>> class Dog(Animal):         #派生类
    def show(self):
        print('I am a dog.')
>>> class Tiger(Animal):       #派生类
    def show(self):
        print('I am a tiger.')
>>> class Test(Animal):        #派生类,没有覆盖基类的show()方法
    pass
>>> x = [item() for item in (Animal, Cat, Dog, Tiger, Test)]
>>> for item in x:        #遍历基类和派生类对象并调用show()方法
    item.show()

I am an animal.
I am a cat.
I am a dog.
I am a tiger.
I am an animal.

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C中调用Python类的方法有多种方式。一种常见的方法是使用pybind11库。pybind11是一个C++库,可以在C++和Python之间进行无缝转换。它提供了一种简单的方式来将C++类绑定到Python,并且可以在C++中调用Python类的方法。通过使用pybind11,您可以在C++中创建一个Python模块,将C++类导出为Python类,并在C++中调用Python类的方法。 另一种方法是使用Python的C API。您可以使用Python的C API在C中调用Python类的方法。首先,您需要使用PyImport_ImportModule函数导入Python模块,然后使用PyObject_GetAttrString函数获取Python类的引用。接下来,您可以使用PyObject_CallMethod函数调用Python类的方法。 这是一个使用Python的C API在C中调用Python类的示例代码: ```c++ #include <Python.h> int main() { // 初始化Python接口 Py_Initialize(); // 导入Python模块 PyObject* pModule = PyImport_ImportModule("module_name"); if (pModule == NULL) { // 模块导入失败 return 1; } // 获取Python类的引用 PyObject* pClass = PyObject_GetAttrString(pModule, "class_name"); if (pClass == NULL || !PyCallable_Check(pClass)) { // 类引用获取失败或者不可调用 return 1; } // 创建类的实例 PyObject* pInstance = PyObject_CallObject(pClass, NULL); if (pInstance == NULL) { // 类实例创建失败 return 1; } // 调用类的方法 PyObject_CallMethod(pInstance, "method_name", NULL); // 释放资源 Py_DECREF(pInstance); Py_DECREF(pClass); Py_DECREF(pModule); // 结束Python接口初始化 Py_Finalize(); return 0; } ``` 请注意,上述代码中的"module_name"是要导入的Python模块的名称,"class_name"是要调用的Python类的名称,"method_name"是要调用的Python类的方法的名称。您需要根据实际情况进行相应的更改。 总结起来,您可以使用pybind11库或Python的C API在C中调用Python类的方法。这些方法可以让您在C和Python之间进行无缝的交互,并实现代码的扩展和功能的增强。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值