GMOEA代码运行1--python之面向对象编程

引言

最近在学习GMOEA这篇论文,我虽然找到了论文和代码,但是代码都是以类给出的,真正要运行起来还需要自己编写脚本。但是对于python本身的面向对象编程不太熟。不知道全局参数的设置,以及测试问题对象之间参数传递以及方法调用等等。先复习一下python的面向对象编程。

学习资料转载自知乎:

史上最全 Python 面向对象编程

类中共有的概念

和Java C++ C#等面向对象的编程语言类似。python也支持面向对象编程。其中有一些共有的概念。

1.类(Class): 用来描述具有相同属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。其中的对象被称作类的实例。
2.实例:也称对象。通过类定义的初始化方法,赋予具体的值,成为一个”有血有肉的实体”。
3.实例化:创建类的实例的过程或操作。
4.实例变量:定义在实例中的变量,只作用于当前实例。
5.类变量:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外。
6.数据成员:类变量、实例变量、方法、类方法、静态方法和属性等的统称。
7.方法:类中定义的函数。
8.静态方法:不需要实例化就可以由类执行的方法
9.类方法:类方法是将类本身作为对象进行操作的方法。
10.方法重写:如果从父类继承的方法不能满足子类的需求,可以对父类的方法进行改写,这个过程也称override。
11.封装:将内部实现包裹起来,对外透明,提供api接口进行调用的机制
12.继承:即一个派生类(derived class)继承父类(base class)的变量和方法。
13.多态:根据对象类型的不同以不同的方式进行处理。

类的定义和实例化

import sys
import time
reload(sys)
sys.setdefaultencoding('utf-8')

class studetn:
    # 定义一个类名为studetn
    def __init__(self,idx):
    # 定义初始化构造,这里使用init,还有别的属性比如reversed,iter之类的
        self.idx=idx
        # 初始化变量,方便继承
    def runx(self):
    # 定义运行函数,从上面继承变量
        print self.idx
        # 打印出idx的值,或者做一些别的处理
        time.sleep(1)
a=studetn('a')
a.runx()
# 这是类的调用,一定要记得类的使用方法,首先传入参数,类赋值给一个变量a
# 然后调用这个类下面定义的函数

类方法的调用

实例化方法调用

import sys
import time
import requests
reload(sys)
sys.setdefaultencoding('utf-8')

class dd:
    def __init__(self,url):
        self.url=url
    def runx(self):
        print requests.get(self.url).status_code

a = dd('http://www.langzi.fun')
a.runx()
这种调用方法就是实例方法

静态方法调用

静态方法直接通过类名调用,相当于所有对象全局共享。静态方法由类调用,无默认参数。将实例方法参数中的self去掉,然后在方法定义上方加上@staticmethod的注解,就成为静态方法。它属于类,和实例无关。建议只使用类名.静态方法的调用方式。(虽然也可以使用实例名.静态方法的方式调用)

import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class ff:
    @staticmethod
    def runx():
        print requests.get('http://www.langzi.fun').status_code
ff.runx()
这里就直接调用了类的变量,只在类中运行而不在实例中运行的方法

类方法

类方法由类调用,采用@classmethod注解,至少传入一个cls(代指类本身,类似self)参数。执行类方法时,自动将调用该方法的类赋值给cls。

import sys
import requests
reload(sys)
sys.setdefaultencoding('utf-8')
class ff:
    @classmethod
    def runx(cls):
        print requests.get('http://www.langzi.fun').status_code
ff.runx()

类的特性

封装

封装是指将数据与具体操作的实现代码放在某个对象内部,外部无法访问。必须要先调用类的方法才能启动。在外部看来只看得到一个对象。看不到里面的私有数据和方法。只对外提供接口。

class cc:
    ccc = 'ccc'
    # cc就是类名 如果想要继承别的类 就class cc(threading) 意思就是从threading继承
    def __init__(self,a,b,c):
        self.a=a
        self.b=b
        self.c=c
print e.ccc
#类变量,在类里面找到定义的变量。
print ccc
# 这里会报错,这就是封装。类中的函数同理。

继承

当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
比如,我们已经编写了一个名为Animal的class,有一个run()方法可以直接打印:

class Animal(object):
    def run(self):
        print 'Animal is running...'

当我们需要编写Dog和Cat类时,就可以直接从Animal类继承:继承方式是将父类写到类的括号里面。

class Dog(Animal):
    pass #表示什么内容也没有
class Cat(Animal):
    pass
dog = Dog()
dog.run()
cat = Cat()
cat.run()

继承可以获得父类的全部功能,然后可以重写父类的方法然后可以实现多态。

多态

多态同一个函数接收不同的对象表现出不同的作用,本质上是向下兼容,一般是用父类的对象作为接收的参数,然后输入子类对象为参数时,可以调用子类的同名函数。

在父类中定义一个函数,以父类对象作为输入

def run_twice(animal):
    animal.run()
    animal.run()

当我们传入父类对象Animal的实例时,run_twice()就打印出:

run_twice(Animal())
运行结果:
Animal is running...
Animal is running..

当传入子类对象时

run_twice(Dog())
运行结果:
Dog is running...
Dog is running...

这就表现出了多态性。

魔法方法

个人感觉就是默认方法,就是你不写编译器自己也会给你补上的函数。

__init__ :      构造函数,在生成对象时调用
__del__ :       析构函数,释放对象时使用
__repr__ :      打印,转换
__setitem__ :   按照索引赋值
__getitem__:    按照索引获取值
__len__:        获得长度
__cmp__:        比较运算
__call__:       调用
__add__:        加运算
__sub__:        减运算
__mul__:        乘运算
__div__:        除运算
__mod__:        求余运算
__pow__:

具体使用

构造函数 init() 在创建类时自动触发。

class Foo:
    def __init__(self, name):
        self.name = name
        self.age = 18
obj = Foo(jack') # 自动执行类中的 __init__ 方法

析构函数del()对象内存被释放时自动触发此方法

class Foo:
    def __del__(self):
        print("我被回收了!")

obj = Foo()
del obj

输出对象 str() 需要用户自己定义

class Foo:
    pass
obj = Foo()
print(obj)
定义了__str__()方法后,打印结果是:'jack'class Foo:
    def __str__(self):
        return 'jack'
obj = Foo()
print(obj)

取值、赋值、删除这“三剑客”的套路,在Python中getitem__()、setitem()、__delitem()分别表示取值赋值和删除。Python中,标识符后面加圆括号,通常代表执行或调用方法的意思。而在标识符后面加中括号[],通常代表取值的意思

a = 标识符[] :   执行__getitem__方法
标识符[] = a  :   执行__setitem__方法
del 标识符[] :   执行__delitem__方法

class Foo:
    def __getitem__(self, key):
        print('__getitem__',key)
    def __setitem__(self, key, value):
        print('__setitem__',key,value)
    def __delitem__(self, key):
        print('__delitem__',key)
obj = Foo()
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'jack'      # 自动触发执行 __setitem__
del obj['k1']             # 自动触发执行 __delitem__

如果需要用for遍历对象数组,则需要定义迭代器方法iter()

class Foo:
    def __init__(self, sq):
        self.sq = sq
    def __iter__(self):
        return iter(self.sq)
obj = Foo([11,22,33,44])
for i in obj:
    print(i)

如果要获取对象长度需要重写len()

len('ABC')
3
'ABC'.__len__()
3

add__: 加运算 sub: 减运算 mul: 乘运算 div: 除运算 mod: 求余运算 __pow: 幂运算

这些都是算术运算方法,需要你自己为类设计具体运算代码。有些Python内置数据类型,比如int就带有这些方法。Python支持运算符的重载,也就是重写。

class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

Python作为一种动态语言,可以在类定义完成和实例化后,给类或者对象继续添加随意个数或者任意类型的变量或方法,这是动态语言的特性。例如:

def print_doc(self):
    print("haha")

class Foo:
    pass

obj1 = Foo()
obj2 = Foo()
# 动态添加实例变量
obj1.name = "jack"
obj2.age = 18
# 动态的给类添加实例方法
Foo.show = print_doc
obj1.show()
obj2.show()

如果想限制实例可以添加的变量咋办?可以使slots限制实例的变量,比如,只允许Foo的实例添加name和age属性。

def print_doc(self):
    print("haha")
class Foo:
    __slots__ = ("name", "age")
    pass
obj1 = Foo()
obj2 = Foo()
# 动态添加实例变量
obj1.name = "jack"
obj2.age = 18
obj1.sex = "male"       # 这一句会弹出错误
# 但是无法限制给类添加方法
Foo.show = print_doc
obj1.show()
obj2.show()
由于'sex'不在__slots__的列表中,所以不能绑定sex属性,试图绑定sex将得到AttributeError的错误。
Traceback (most recent call last):
  File "F:/Python/pycharm/201705/1.py", line 14, in <module>
    obj1.sex = "male"
AttributeError: 'Foo' object has no attribute 'sex'

成员保护与访问控制

私有成员

加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问

class obj:
    def __init__(self,name):
        self.name=name
    def pri(self):
        print self.name
    __age = 18
    # 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
a = obj('zhao')
a.pri()

如果要在类中调用这个私有成员,可以这么用

class obj:
    def __init__(self,name):
        self.name=name
    def prin(self):
        print self.name
    __age = 18
    # 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
    @classmethod
    # 如果要在类中调用,首先调用类方法
    def pri(cls):
        print cls.__age
        # 然后在使用
a = obj('zhao')
a.prin()
obj.pri()
# 通过这样直接调用类中的私有变量

使用get-set-del方法操作私有成员

class obj:
    def __init__(self,name):
        self.name=name
    def prin(self):
        print self.name
    __age = 18
    # 加上双下划线的就是私有变量,只能在类的内部访问,外部无法访问
    @classmethod
    # 如果要在类中调用,首先调用类方法
    def pri(cls):
        print cls.__age
        # 然后在使用
    @classmethod
    def set_age(cls,value):
        cls.__age = value
        return cls.__age
        # 这个用法就是改变__age的值
    @classmethod
    def get_age(cls):
        return cls.__age
        # 这个用法就是直接返回__age的值
    @classmethod
    def del_age(cls):
        del cls.__age
        # 这个用法就是直接删除__age的值

print obj.get_age()
# 这里是直接调用出__age的值  返回值18
print obj.set_age(20)
# 这里是直接改变__age的值  返回值20
obj.del_age()
# 这里是直接删除__age的值

猜你喜欢

转载自blog.csdn.net/qq_36820823/article/details/123727010