月度归档:2015年10月

python中类与类型的统一是指什么

世间具有共同特性的东西,我们可以将其归为一类,为它起个名字,叫吃的,喝的。。。但他们并不是具体的事物,而是抽象的名词。python中的类型(type)和对象(object)同样是抽象名词,type用来描述object具有哪些共同的属性,比如说苹果(object),香蕉(object),他们都能吃,可以把他们归为”吃的”类(type),能吃是它们的一个属性,当然他们还有其他属性,也可根据其他属性归类。

python中的每个object都具有一个class属性,他的值是一个type类型的实例,是一个实际对象,这个实力描述了这个类型的名称,属性和有哪些方法,比如说怎么吃,包皮吃还是直接吃。一只猪和一只狗是两个实际的object,它们是动物,那就让他们的class指向动物类型(type)的一个实例。每个type实例都有一个base属性,这是指继承于上一级的属性,比如动物和人,人是动物的一个子类,动物都有吃的属性,但人具有说话的属性。对于动物和人有两个类(type),animal和human,在ainimal中有吃的属性,在human中有说话的属性,当实例化一个human时,我们要调用吃的方法,会在human中定义查找这个方法,没有找到,那么就看看human.base中有哪些类,找到了动物,在animal的定义中找到了吃的属性,那么就调用这个属性。

值得我们记住的就是在python中所有的东西都是对象,他们都继承自object,既然都是对象,那么他们就都具有type属性(class)。object也不例外,它的class就是type。如果object是一头猪,那么class可能就是一个type的实例————动物。type也是一个对象,它的class就是type。

其实可以这样简单理解,我们所定义类型(class)或系统内建的类型(class)都是type的实例,我们用到的实例化后得到的东西是type的实例的实例,并且这些class都继承于class object。

这是我的个人理解,如有不对之处欢迎指出。

python中的类属性和实例属性

python中的实例属性指和每个实际实例相关的属性,当类A继承自B时,a = A()读取a.data,会首先在a.dict中查找data,也就是实例中查找data属性,dict其实就是存储实例属性的地方。当在a中查找到时(也就是在dict中),返回该指,如果data属性不在a中,那么会查找类及父类中的该属性。当对a.data赋值时,由于python动态绑定(或者其他原因),就直接在a的dict中赋值,比如append方法。

不管是类A,类B还是A的实例a或者B的实例b,在python眼中,它们都是实例,需要有位置存放与这些实例相关的数据,这正是dict的作用,此外除了dict外,在内部可能还会有个code属性,用来查找代码的位置等。另外,python看待类A和类B是完全一样的,它们都是同一个类型,继承关系只是规定了python在访问对象实例(python眼中的)的属性时,需要去哪里找而已。

以上是我个人观点,不代表正确,欢迎大家指正。

PHP通过魔术方法实现多继承与重载

 PHP所提供的”重载”(overloading)是指动态地”创建”类属性和方法。我们是通过魔术方法(magic methods)来实现的。当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。本节后面将使用”不可访问属性”和”不可访问方法”来称呼这些未定义或不可见的类属性或方法。所有的重载方法都必须被声明为 public。

<?php
class Parent1 {
    public function printFunction ($args) {
        echo 'parent1->printfunction ' . $args . '<br>';
    }

    public function printFunction1 ($args) {
        echo 'parent1->printfunction1 ' . $args . '<br>';
    }
}

class Parent2 {
    public function printFunction2 ($args) {
        echo 'parent2->printfunction2 ' . $args . '<br>';
    }
}

class Child {
    protected $_parents = null;

    public function __construct($parents) {
        $this->_parents = $parents;
    }

    public function __call($method, $args) {
        foreach ($this->_parents as $p) {
            if (is_callable(array($p, $method))) {
                return call_user_func_array(array($p, $method), $args);
            }
        }
    }

    public function printFunction ($args) {
        echo 'child->printfunction ' . $args . '<br>';
    }
}

class A {
    protected $_parents = null;

    public function __construct($parents) {
        $this->_parents = $parents;
    }

    public function __call($method, $args) {
        foreach ($this->_parents as $p) {
            if (is_callable(array($p, $method))) {
                return call_user_func_array(array($p, $method), $args);
            }
        }
    }   
}

class B extends Child{
    public function __construct($parent){
        parent::__construct($parent);
    }
}
$obj = new Child(array(new Parent1(), new Parent2()));
$a = new A(array(new Child(array(new Parent1(), new Parent2()))));
$b = new B(array(new Parent1(), new Parent2()));

$obj->printFunction(123); // child->printfunction 123
$obj->printFunction1(456); // parent1->printfunction1 456
$obj->printFunction2(789); // arent2->printfunction2 789

$a->printFunction(123); // child->printfunction 123
$a->printFunction1(456); // parent1->printfunction1 456
$a->printFunction2(789); // arent2->printfunction2 789

$b->printFunction(123); // child->printfunction 123
$b->printFunction1(456); // parent1->printfunction1 456
$b->printFunction2(789); // arent2->printfunction2 789

当执行$obj->printFunction(123)时,由于在Child类中定义了此方法,所以直接调用Child中的printFunction方法。而执行$obj->printFunction1(456)和$obj->printFunction2(789)时,由于Child类中未定义printFunction1和printFunction2方法,就会自动调用__call方法,该方法的第一个参数是调用的不存在的方法的名称,是字符串类型,第二个参数是要传递的参数,是数组类型。在__call方法中查找引用的类的实例中是否存在该方法。类A和类B分别为实现不同的“继承”方法,他们的结果是一样的。用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。

对于属性的重载也是同样的道理。

在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
当对不可访问属性调用 unset() 时,__unset() 会被调用。

还请读者参照PHP文档进行具体实现,若要了解详细使用,可参考yii中yii\base\Object的property和yii\base\Component的behavior的具体实现。